Bug 13548 – wrong sqrt

Status
RESOLVED
Resolution
FIXED
Severity
blocker
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-09-27T23:17:22Z
Last change time
2022-03-25T10:14:36Z
Keywords
backend, wrong-code
Assigned to
No Owner
Creator
Илья Ярошенко

Comments

Comment #0 by ilyayaroshenko — 2014-09-27T23:17:22Z
Win64 & FreeBSD32 are affected. Tester: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=3&pullid=2548 PR: https://github.com/D-Programming-Language/phobos/pull/2548#issuecomment-57064711 ---------------- unittest { import std.stdio; import std.string; assert(isIdentical(abs(-0.0L), 0.0L)); assert(isNaN(abs(real.nan))); assert(abs(-real.infinity) == real.infinity); assert(abs(-3.2Li) == 3.2L); assert(abs(71.6Li) == 71.6L); assert(abs(-56) == 56); assert(abs(2321312L) == 2321312L); assert(abs(creal (-1+1i)) == sqrt(2.0L)); cdouble c = -1+1i; assert(sqrt(c.re*c.re+c.im*c.im) == sqrt(2.0)); double ad, bd, cd; ad = sqrt(2.0); bd = hypot(c.re, c.im); cd = sqrt(2.0); assert(ad == cd, "FP fail"); //<-----------------------FAILS SQRT(2) != SQRT(2) assert(ad == bd, format("sqrt(2.0) = %.*a, hypot(c.re, c.im) = %.*a", 25, ad, 25, bd)); assert(hypot(c.re, c.im) == sqrt(2.0), format("sqrt(2.0) = %.*a, hypot(c.re, c.im) = %.*a", 20, sqrt(2.0), 20, hypot(c.re, c.im))); assert(abs(c) == sqrt(2.0)); assert(abs(cdouble(-1+1i)) == sqrt(2.0 )); assert(abs(cfloat (-1+1i)) == sqrt(2.0f)); } ----------------
Comment #1 by yebblies — 2015-02-08T11:41:46Z
My guess is that this is a similar bug to issue 13474, where ad is truncated by saving it to the stack then reloading it, while cd is kept in a register after being returned with >double precision.
Comment #2 by ilyayaroshenko — 2015-02-14T13:18:44Z
Probably this is reduced example for FreeBSD_32 and Win32: ---- double two = 2.0; assert(sqrt(two) == sort(2.0)); ----
Comment #3 by bugzilla — 2020-08-31T09:16:49Z
Code: import core.stdc.math; void main() { double two = 2.0; assert(sqrt(two) == sqrt(2.0)); } Generates for main(): enter 014h,0 fld qword ptr FLAT:CONST[00h] fstp qword ptr -8[EBP] push dword ptr -4[EBP] push dword ptr -8[EBP] call near ptr _sqrt add ESP,8 push dword ptr FLAT:CONST[04h] push dword ptr FLAT:CONST[00h] fstp qword ptr -014h[EBP] call near ptr _sqrt add ESP,8 fld qword ptr -014h[EBP] fxch ST(1) fucompp ST(1),ST fstsw AX sahf jp L40 je L4D L40: push 6 mov EAX,offset FLAT:___a7_74657374322e64 push EAX call near ptr __d_assertp L4D: xor EAX,EAX leave ret Both calls to sqrt() produce the same result in ST0. But the first one stores and reloads it as a double, thus causing a round-to-double operation. The second does not, so they compare unequal. yebblies is right. I'm not sure what the right fix would be. I could change sqrt() in DMC's runtime library to store/load the value it returns, but that wouldn't fix things for FreeBSD32. On Win64 there isn't a problem because the sqrt() result is returned in XMM0 rather than ST0.
Comment #4 by bugzilla — 2020-09-01T10:13:45Z
I fixed DMC's sqrt to round to double. https://github.com/DigitalMars/dmc/commit/29d49d5527fcb3e92f0b6f8620eb1bd9e0de1a14 Not much I can do about FreeBSD32.