https://issues.dlang.org/show_bug.cgi?id=20451
--- Comment #4 from jacob <[email protected]> --- (In reply to berni44 from comment #3) > (In reply to jacob from comment #1) > > Comparing floating point numbers with "==" is in itself an error. > > I know. But the "==" was there first. I tried to fix the issue and when I > found out, that the results where indeed the correct results and the > (original) problem was because double was compared with real and real > produces just better results, I added the cast. This worked for most > machines... > > > You shouldn't be comparing approximation of numbers to see if they are > > exactly > > the same. > > I agree, but it's not an approximation in this case. (Although I meanwhile > solved the original stuff by using approxEqual with a large constant, so > actually it's comparing for identity.) It is an approximation. You are computing something using two different methods. The result at runtime is also dependent on hardware. You change settings in SSE and the FPU so that the same two inputs give different results. It's all an approximation if you are using floating point numbers. Even if math says others, it's different when you have to do computations in the real world and can't use fractions to retain infinite precision. > > // can't just cast(double) here cause pow() returns value on the FPU > > // so the conversion never happens otherwise > > double a = pow(xd, neg2); > > assert(a == cast(double) (1 / (x * x))); > > I don't understand that. xd is of type F=double and the result of pow() is > "Unqual!F" which is also double. FPU or not, the result should behave like a > double. When casting another value to double and the results have equal bit > patterns, they should be compareable with ==. Non-working: CALL __D3std4math__T3powTydTysZQlFNaNbNiNeydysZd FLD qword ptr [DAT_004d2f88] FUCOMPP Working (cast(double)): CALL __D3std4math__T3powTydTysZQlFNaNbNiNeydysZd FSTP qword ptr [ESP + 0x8] FLD qword ptr [ESP + 0x8] FLD qword ptr [DAT_004d2f88] FUCOMPP Do you see the difference? It's a hardware problem, and it's the reason why the FPU isn't used anymore. The D and C/C++ convention is to return floating point numbers on the FPU. This means the number stays as it's 80-bit representation in the FPU. All the calculations were probably done in the FPU as well. The reason the code works that I posted, was because we explicitly told it to store the value before comparing it. As you can see, it "FSTP" (stores) the value in a qword (64-bits) before loading it and doing the comparison. > > You are comparing different types, pow() returns real > > If it does, this is the bug. It's not really a bug. It's how the FPU operatores, all values on the FPU are stored as 80-bit fp. You get situations like these cause of the difference in precision. The SSE doesn't support 80-bit floats, and operations are done in the same precision they are given in. If you do 32-bit floating point operations, they stay in 32-bit (if that's how it was programmed). With the FPU everything gets "upgraded" to 80-bits. You can't really avoid it unless you don't use it, but I imagine Windows/FreeBSD 32-bit ABI probably requires it. Though I guess it could be changed for D's ABI. --
