Skip to content

Commit

Permalink
Fix issue 17562 - tan returning -nan for inputs where abs(x) >= 2^63
Browse files Browse the repository at this point in the history
The fptan instruction pushes a 1.0 onto the FPU register stack after a
successful operation, but when abs(input) >= 2^63 the C2 flag is set to
indicate that the input was out of bounds, and it doesn't push the 1.0.

Prior to this PR, the top value of the FPU stack was popped irrespective
of whether C2 was set, which in the case of an out-of-bounds input
caused the input to be removed from the stack and ultimately resulted in
an incorrect return value of -nan. This PR changes this behavior, only
popping after fptan when C2 was not set.

See: http://x86.renejeschke.de/html/file_module_x86_id_109.html

* Added unit tests for handling out-of-range inputs of fptan
  • Loading branch information
pineapplemachine authored and PetarKirov committed Jun 27, 2017
1 parent b5d6ac1 commit 0fb66f0
Showing 1 changed file with 16 additions and 4 deletions.
20 changes: 16 additions & 4 deletions std/math.d
Expand Up @@ -768,10 +768,9 @@ real tan(real x) @trusted pure nothrow @nogc
jc trigerr ; // x is NAN, infinity, or empty
// 387's can handle subnormals
SC18: fptan ;
fstp ST(0) ; // dump X, which is always 1
fstsw AX ;
sahf ;
jnp Lret ; // C2 = 1 (x is out of range)
jnp Clear1 ; // C2 = 1 (x is out of range)

// Do argument reduction to bring x into range
fldpi ;
Expand All @@ -789,6 +788,10 @@ trigerr:
}
return real.nan;

Clear1: asm pure nothrow @nogc{
fstp ST(0) ; // dump X, which is always 1
}

Lret: {}
}
else version(D_InlineAsm_X86_64)
Expand All @@ -815,10 +818,9 @@ Lret: {}
jnz trigerr ; // x is NAN, infinity, or empty
// 387's can handle subnormals
SC18: fptan ;
fstp ST(0) ; // dump X, which is always 1
fstsw AX ;
test AH,4 ;
jz Lret ; // C2 = 1 (x is out of range)
jz Clear1 ; // C2 = 1 (x is out of range)

// Do argument reduction to bring x into range
fldpi ;
Expand All @@ -837,6 +839,10 @@ trigerr:
}
return real.nan;

Clear1: asm pure nothrow @nogc{
fstp ST(0) ; // dump X, which is always 1
}

Lret: {}
}
else
Expand Down Expand Up @@ -7174,6 +7180,12 @@ deprecated("Phobos1 math functions are deprecated, use isInfinity ") alias isinf

real r = tan(-2.0L);
assert(fabs(r - 2.18504f) < .00001);

// Verify correct behavior for large inputs
assert(!isNaN(tan(0x1p63)));
assert(!isNaN(tan(0x1p300L)));
assert(!isNaN(tan(-0x1p63)));
assert(!isNaN(tan(-0x1p300L)));
}

@safe pure nothrow unittest
Expand Down

0 comments on commit 0fb66f0

Please sign in to comment.