On Monday, 24 August 2015 at 17:26:12 UTC, Steven Schveighoffer
wrote:
On 8/24/15 12:52 PM, "=?UTF-8?B?Ik3DoXJjaW8=?= Martins\"
<[email protected]>\"" wrote:
I'm posting this here for visibility. This was silently
corrupting our
data, and might be doing the same for others as well.
import std.stdio;
void main() {
double x = 1.2;
writeln(cast(ulong)(x * 10.0));
double y = 1.2 * 10.0;
writeln(cast(ulong)y);
}
Output:
11
12
Yes. This is part of the issue of floating point. 1.2 cannot be
represented accurately.
The second case is done via real, not double, and at compile
time (i.e. constant folding). There may be other reasons why
this works.
You are better off adding a small epsilon:
writeln(cast(ulong)(x * 10.0 + 0.1));
to!ulong instead of the cast does the right thing, and is a
viable
work-around.
to!ulong likely adds the epsilon, but you'd have to look to be
sure.
Note, this is NOT a D problem, this is a problem with floating
point. And by problem, I mean feature-that-you-should-avoid :)
-Steve
I am familiar with floating-point representations and their
pitfalls, and I think that is not the issue here.
The issue I am trying to illustrate is the fact that the same
exact operation returns different results.
Both operations are x * 10.0, except one of them passes through
the stack before the cast.
I would expect this to be consistent, as I believe is the case in
C/C++.