1

I'm a bit confused with modulo in c. Trying the following examples:

double d = 4912;
int a;
a = (int) d%100;
printf ("%d \n", a);

Answer is 12. Fine, that's what I'm expecting. Now I try this:

double d = 49.12;
d = d*100;
int a;
a = (int) d%100;
printf ("%d \n", a);

Answer: 12. Again what I'm expecting. But now:

double d = 49.12;
int a;
a = (int)(d*100)%100;
printf ("%d \n", a);

Answer: 11! That's definitly not what I expected. But I have no idea why. oO

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
XSized
  • 13
  • 2
  • 2
    Rounding errors probably. Is d*100 4912.00000000000001 or 4911.999999999999999?. It's not the modulo either, it's the (int) – user253751 Feb 14 '18 at 22:23
  • Try `printf("%.20g\n", 49.12);`. What is your result? IS it "49.119999999999997442"? – chux - Reinstate Monica Feb 14 '18 at 22:24
  • Tried, that's 49.119999999999997 – XSized Feb 14 '18 at 22:26
  • Isn't it answering your question? – Eugene Sh. Feb 14 '18 at 22:29
  • I think so, but I don't understand, why I see this rounding error in only one case. :/ – XSized Feb 14 '18 at 22:32
  • @XSized For `double` of the form `xx.yy`, about half of them will encode a `double` a bit above the mathematical `xx.yy` and about half below. The `(int)` in `(int)(d*100)%100` call will split those groups to `yy` and `yy-1` camps. – chux - Reinstate Monica Feb 14 '18 at 22:36
  • Is there a reason not to close this as a duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken)? – Jonathan Leffler Feb 14 '18 at 22:56
  • @XSized: The C standard allows a C implementation to use extended precision in intermediate calculations. So `(int) d*100` may apply `int` to a value that is very very near, but less than, 4912. When a value is assigned to an object, the rules require it be converted to the target precision. So `d = d * 100;` would round that value to the nearest `double`, which is apparently 4912. – Eric Postpischil Feb 14 '18 at 22:59
  • 1
    @JonathanLeffler: Yes. The answers in that question explain little and do not well address specific issues that people ask about. Promiscuously closing questions as duplicates of that one deters people from learning about floating point and precludes building up a repository of matched floating-point questions and answers. It is like answering every C question where somebody is tripped up by sequence points, integer promotion, *etc.* as a duplicate of “Is C broken?” – Eric Postpischil Feb 14 '18 at 23:03

1 Answers1

4

double as a 64-bit floating point number cannot represent every number coded as text. In can encode exactly about 264 different numbers. 49.12 is not one of them.

Given the binary nature of most double, the closest double d value is about 49.119999999999997.

The result of (int)(d*100)%100 is then simply 11.


On another platform,the result may have been 12.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Perfect! Thanks, now I understand the problem! – XSized Feb 14 '18 at 22:36
  • There is more going in here. This answer only gives a possible reason `(int) (d*100) % 100` evaluates to 11. It does not explain why, after `d = d*100;`, `(int) d % 100` evaluates to 12. OP may be using an implementation that uses extended precision in intermediate calculations. – Eric Postpischil Feb 14 '18 at 22:43
  • 1
    @XSized Note that your `printf("%.20g\n", 49.12);` reported 49.119999999999997 and mine reported 49.119999999999997442. That is certainly due to the quality of the `printf()` function and not due to a difference of the `double` value code is using. Some `printf()` better handle the lower digits better than others. – chux - Reinstate Monica Feb 14 '18 at 22:44
  • @EricPostpischil Yes, certainly far more going on. Your suggestion about intermediate results may occur at higher precision is good - as usual. Still focusing on OP's likely initial understanding needs before rambling about in the details about precision `FLT_EVAL_METHOD` and the rest. – chux - Reinstate Monica Feb 14 '18 at 22:50