i386/67469: src/lib/msun/i387/s_tan.S gives incorrect results
for large inputs
David Schultz
das at FreeBSD.ORG
Sat Feb 5 16:09:27 PST 2005
On Sat, Feb 05, 2005, Bruce Evans wrote:
> Better call the MI tan() to do all this. It won't take significantly
> longer, and shouldn't be reached in most cases anyway.
Yeah, but s_tan.S overrides s_tan.c, so that would require extra
machinery. Also, if fptan had worked as advertised and correctly
identified the cases where range reduction was necessary, calling
rem_pio2() directly would have avoided superfluous range checking.
> I think it is because fptan is inherently inaccurate. [...]
As you mention, it gets the wrong answer for M_PI. In general, it
seems to do pretty badly on numbers close to multiples of pi.
Granted, one could argue that the answer returned is going to be
even *further* from the answer the programmer expected (namely, 0),
so it won't make much difference. ;-)
BTW, Kahan has a program for producing large floating-point
numbers close to multiples of pi/2:
http://www.cs.berkeley.edu/~wkahan/testpi/
In investigating this, I discovered several interesting things:
- The Intel software developer's guide says that fptan has an error
of at most 1 ulp, but as we've seen, they're lying.
- Maple 9.5 on sparc64 with Digits:=5000 corroborates fdlibm's answer
to tan(M_PI).
- fdlibm's tan() does not seem to be much slower than fptan
on the range (-M_PI,M_PI), which is what people are most
likely to care about. The MD version is faster for some
inputs where the small angle approximation applies
(|x| < 2^-28 implies x == tan(x)). fdlibm special cases
this, too, but the special case isn't early enough, and the
bugfix in fdlibm 5.3 slows things down. Throwing that
special case out of the average, fdlibm seems to be faster!
(NB: I benchmarked this very sloppily on ref4. Perhaps
you could confirm the results...)
Your suggestion of effectively special-casing large inputs and
inputs close to multiples of pi is probably the right way to fix
the inaccuracy. However, I'm worried that it would wipe away
any performance benefit of using fptan, if there is a benefit
at all. How about punting and removing s_tan.S instead?
Other unanswered questions (ENOTIME right now):
- What about sin() and cos()?
- What about the float versions of these?
More information about the freebsd-i386
mailing list