Bug 16341 – 32-bit floating-point issue

Status
RESOLVED
Resolution
INVALID
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Linux
Creation time
2016-07-31T09:18:00Z
Last change time
2016-07-31T10:57:03Z
Assigned to
nobody
Creator
greensunny12

Comments

Comment #0 by greensunny12 — 2016-07-31T09:18:18Z
While the difference is usually not noticeable, it's there and once used with pow and exp, it can yield to totally different results (that's how I discovered it). import std.stdio; alias S = float; float shL = 0x1.1b95eep-4; // -0.069235 float shR = 0x1.9c7cfep-7; // -0.012588 F fun(F)(F x) { return 1.0 + x * 2; } S working() { S r = fun(shR); S l = fun(shL); return (r - l); } S failing() { return (fun(shR) - fun(shL)); } unittest { writefln("work: %a", working); writefln("fail: %a", failing); assert(working == failing); } assembler: .text._D3foo7workingFZf segment assume CS:.text._D3foo7workingFZf _D3foo7workingFZf: push EBP mov EBP,ESP sub ESP,0Ch mov -0Ch[EBP],EBX mov EAX,GS:[00h] mov ECX,_D3foo3shRf@TLS_IE push [ECX][EAX] call _D3foo10__T3funTfZ3funFNaNbNiNffZf@PC32 fstp float ptr -8[EBP] mov EDX,GS:[00h] mov EBX,_D3foo3shLf@TLS_IE push [EBX][EDX] call _D3foo10__T3funTfZ3funFNaNbNiNffZf@PC32 fstp float ptr -4[EBP] fld float ptr -8[EBP] fsub float ptr -4[EBP] mov EBX,-0Ch[EBP] leave ret nop nop nop nop nop .text._D3foo7workingFZf ends .text._D3foo7failingFZf segment assume CS:.text._D3foo7failingFZf _D3foo7failingFZf: push EBP mov EBP,ESP sub ESP,010h mov -010h[EBP],EBX mov EAX,GS:[00h] mov ECX,_D3foo3shRf@TLS_IE push [ECX][EAX] call _D3foo10__T3funTfZ3funFNaNbNiNffZf@PC32 mov EDX,GS:[00h] mov EBX,_D3foo3shLf@TLS_IE push [EBX][EDX] fstp float ptr -0Ch[EBP] call _D3foo10__T3funTfZ3funFNaNbNiNffZf@PC32 fld float ptr -0Ch[EBP] fsubrp ST(1),ST mov EBX,-010h[EBP] leave ret nop .text._D3foo7failingFZf ends .text._D3foo10__T3funTfZ3funFNaNbNiNffZf segment assume CS:.text._D3foo10__T3funTfZ3funFNaNbNiNffZf _D3foo10__T3funTfZ3funFNaNbNiNffZf: fld float ptr 4[ESP] fadd ST(0),ST fld1 faddp ST(1),ST ret 4 nop nop nop .text._D3foo10__T3funTfZ3funFNaNbNiNffZf ends
Comment #1 by ag0aep6g — 2016-07-31T10:57:03Z
I think this is due to D allowing floating points operations to be done at a higher precision than is stated in the source. That is, `fun` may do its calculations with doubles or reals, and it may return a double or real in a register. The same applies to `working` and `failing`, but `working` puts the results from `fun` on the stack first, forcing a conversion to float, while `failing` returns directly, so the operands are not converted to float. Note that the assert passes when you compile with -O, because then `working` is optimized to behave like `failing`. Closing as INVALID. Feel free to reopen if you disagree.