Issue 3171 - % not implemented correctly for floats
Summary: % not implemented correctly for floats
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other Linux
: P2 normal
Assignee: No Owner
URL:
Keywords: spec
Depends on:
Blocks:
 
Reported: 2009-07-13 12:01 UTC by Andrei Alexandrescu
Modified: 2015-06-09 05:15 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Comment 1 Walter Bright 2009-07-13 13:08:41 UTC
As to why the code generator doesn't use FPREM1 instead of FPREM, there's the following comment: "We don't use fprem1 because for some inexplicable
reason we get -5 when we do _modulo(15, 10)"

This could be a bug in older CPUs.
Comment 2 Don 2009-07-14 01:49:30 UTC
(In reply to comment #1)
> As to why the code generator doesn't use FPREM1 instead of FPREM, there's the
> following comment: "We don't use fprem1 because for some inexplicable
> reason we get -5 when we do _modulo(15, 10)"
> 
> This could be a bug in older CPUs.

It isn't a bug. That's what the IEEE remainder specifies.
Note that C's fmod is NOT the same as IEEE remainder.

15/10 = 1.5, so there's a choice of n == 1 or n==2. The standard specifies even n in such cases, so r == a - b*n == 15 - 2*10 == -5.

That's kind of... weird, highly non-intuitive, and not terribly useful. I'm pretty sure that that behaviour would be unpopular.
Comment 3 Walter Bright 2009-07-14 02:27:46 UTC
Thanks for the explanation. At least I know why that happens, now. What do you suggest, then? Staying with FPREM or going with FPREM1 ?
Comment 4 Don 2009-07-14 04:03:19 UTC
(In reply to comment #3)
> Thanks for the explanation. At least I know why that happens, now. What do you
> suggest, then? Staying with FPREM or going with FPREM1 ?

It's hard to justify including a primitive built-in operator that differs from IEEE. But it may be justifiable when it's the only way to avoid a major break from C and intuition.

  int x = 15 % 10;
  int y = cast(int)((cast(float)15) % 10);

// Are we really comfortable with these being completely different?

You know, all this time I was thinking that the behaviour of % for negative integers was because it needed to be consistent with floating-point modulus...
Now it just seems to be wrong.


But I think I have the answer. In IEEE, the preferred conversion from float to int uses round-to-nearest. IEEE remainder makes sense in that context. Since in cast(int), D has inherited 'chop' rounding from C, D needs to also inherit C's fmod behaviour.

So D should stay with FPREM. But we need to document it properly.
Comment 5 Walter Bright 2009-07-14 15:15:10 UTC
We're not breaking with C because C has no % operator for floats. But I agree we should match C99's fmod behavior, which is its current behavior.
Comment 6 Walter Bright 2009-12-06 00:46:11 UTC
Fixed dmd 1.053 and 2.037