Commit Graph

348 Commits

Author SHA1 Message Date
Bruce Evans
0bea84b2d4 Exploit skew-symmetry to avoid an operation: -sin(x-A) = sin(A-x). This
gives a tiny but hopefully always free optimization in the 2 quadrants
to which it applies.  On Athlons, it reduces maximum latency by 4 cycles
in these quadrants but has usually has a smaller effect on total time
(typically ~2 cycles (~5%), but sometimes 8 cycles when the compiler
generates poor code).
2005-11-28 06:15:10 +00:00
Bruce Evans
35ae347641 Try to use the "proximity" (~) operator consistently in comments
(x ~<= a, not x <= ~a).  This got messed up in some places when the
comments were moved from e_rem_pio2f.c.

Added my (non-)copyright.
2005-11-28 05:46:13 +00:00
Bruce Evans
960d3da0f0 Changed spelling of the request-to-inline macro name to match the change
of the function name.

Added my (non-)copyright.

In k_tanf.c, added the first set of redundant parentheses to control
grouping which was claimed to be added in the previous commit.
2005-11-28 05:35:32 +00:00
Bruce Evans
59aad933ab Use only double precision for "kernel" cosf and sinf (except for
returning float).  The functions are renamed from __kernel_{cos,sin}f()
to __kernel_{cos,sin}df() so that misuses of them will cause link errors
and not crashes.

This version is an almost-routine translation with no special optimizations
for accuracy or efficiency.  The not-quite-routine part is that in
__kernel_cosf(), regenerating the minimax polynomial with double
precision coefficients gives a coefficient for the x**2 term that is
not quite -0.5, so the literal 0.5 in the code and the related `hz'
variable need to be modified; also, the special code for reducing the
error in 1.0-x**2*0.5 is no longer needed, so it is convenient to
adjust all the logic for the x**2 term a little.  Note that without
extra precision, it would be very bad to use a coefficient of other
than -0.5 for the x**2 term -- the old version depends on multiplication
by -0.5 being infinitely precise so as not to need even more special
code for reducing the error in 1-x**2*0.5.

This gives an unimportant increase in accuracy, from ~0.8 to ~0.501
ulps.  Almost all of the error is from the final rounding step, since
the choice of the minimax polynomials so that their contribution to the
error is a bit less than 0.5 ulps just happens to give contributions that
are significantly less (~.001 ulps).

An Athlons, for uniformly distributed args in [-2pi, 2pi], this gives
overall speed increases in the 10-20% range, despite giving a speed
decrease of typically 19% (from 31 cycles up to 37) for sinf() on args
in [-pi/4, pi/4].
2005-11-28 04:58:57 +00:00
Bruce Evans
833f0e1a4a Minor cleanups and optimizations:
- Remove dead code that I forgot to remove in the previous commit.

- Calculate the sum of the lower terms of the polynomial (divided by
  x**5) in a single expression (sum of odd terms) + (sum of even terms)
  with parentheses to control grouping.  This is clearer and happens to
  give better instruction scheduling for a tiny optimization (an
  average of about ~0.5 cycles/call on Athlons).

- Calculate the final sum in a single expression with parentheses to
  control grouping too.  Change the grouping from
  first_term + (second_term + sum_of_lower_terms) to
  (first_term + second_term) + sum_of_lower_terms.  Normally the first
  grouping must be used for accuracy, but extra precision makes any
  grouping give a correct result so we can group for efficiency.  This
  is a larger optimization (average 3-4 cycles/call or 5%).

- Use parentheses to indicate that the C order of left to right evaluation
  is what is wanted (for efficiency) in a multiplication too.

The old fdlibm code has several optimizations related to these.  2
involve doing an extra operation that can be done almost in parallel
on some superscalar machines but are pessimizations on sequential
machines.  Others involve statement ordering or expression grouping.
All of these except the ordering for the combining the sums of the odd
and even terms seem to be ideal for Athlons, but parallelism is still
limited so all of these optimizations combined together with the ones
in this commit save only ~6-8 cycles (~10%).

On an AXP, tanf() on uniformly distributed args in [-2pi, 2pi] now
takes 39-59 cycles.  I don't know of any more optimizations for tanf()
short of writing it all in asm with very MD instruction scheduling.
Hardware fsin takes 122-138 cycles.  Most of the optimizations for
tanf() don't work very well for tan[l]().  fdlibm tan() now takes
145-365 cycles.
2005-11-24 13:48:40 +00:00
Joel Dahl
19797b2256 s/5.5/6.0/ in HISTORY section.
Discussed with:	ru
2005-11-24 09:25:10 +00:00
Bruce Evans
16638b5585 Optimized by eliminating the special case for 0.67434 <= |x| < pi/4.
A single polynomial approximation for tan(x) works in infinite precision
up to |x| < pi/2, but in finite precision, to restrict the accumulated
roundoff error to < 1 ulp, |x| must be restricted to less than about
sqrt(0.5/((1.5+1.5)/3)) ~= 0.707.  We restricted it a bit more to
give a safety margin including some slop for optimizations.  Now that
we use double precision for the calculations, the accumulated roundoff
error is in double-precision ulps so it can easily be made almost 2**29
times smaller than a single-precision ulp.  Near x = pi/4 its maximum
is about 0.5+(1.5+1.5)*x**2/3 ~= 1.117 double-precision ulps.

The minimax polynomial needs to be different to work for the larger
interval.  I didn't increase its degree the old degree is just large
enough to keep the final error less than 1 ulp and increasing the
degree would be a pessimization.  The maximum error is now ~0.80
ulps instead of ~0.53 ulps.

The speedup from this optimization for uniformly distributed args in
[-2pi, 2pi] is 28-43% on athlons, depending on how badly gcc selected
and scheduled the instructions in the old version.  The old version
has some int-to-float conversions that are apparently difficult to schedule
well, but gcc-3.3 somehow did everything ~10 cycles or ~10% faster than
gcc-3.4, with the difference especially large on AXPs.  On A64s, the
problem seems to be related to documented penalties for moving single
precision data to undead xmm registers.  With this version, the speed
is cycles is almost independent of the athlon and gcc version despite
the large differences in instruction selection to use the FPU on AXPs
and SSE on A64s.
2005-11-24 02:04:26 +00:00
Bruce Evans
94a5f9be99 Use only double precision for "kernel" tanf (except for returning float).
This is a minor interface change.  The function is renamed from
__kernel_tanf() to __kernel_tandf() so that misues of it will cause
link errors and not crashes.

This version is a routine translation with no special optimizations
for accuracy or efficiency.  It gives an unimportant increase in
accuracy, from ~0.9 ulps to 0.5285 ulps.  Almost all of the error is
from the minimax polynomial (~0.03 ulps and the final rounding step
(< 0.5 ulps).  It gives strange differences in efficiency in the -5
to +10% range, with -O1 fairly consistently becoming faster and -O2
slower on AXP and A64 with gcc-3.3 and gcc-3.4.
2005-11-23 14:27:56 +00:00
Bruce Evans
01231dd04c Simplified setiing up args for __kernel_rem_pio2(). We already have x
with a 24-bit fraction, so we don't need a loop to split it into up to
3 terms with 24-bit fractions.
2005-11-23 03:03:09 +00:00
Bruce Evans
33f8f56e09 Quick fix for stack buffer overrun in rev.1.13. Oops. The prec == 1
arg to __kernel_rem_pio2() gives 53-bit (double) precision, not single
precision and/or the array dimension like I thought.  prec == 2 is
used in e_rem_pio2.c for double precision although it is documented
to be for 64-bit (extended) precision, and I just reduced it by 1
thinking that this would give the value suitable for 24-bit (float)
precision.  Reducing it 1 more to the documented value for float
precision doesn't actually work (it gives errors of ~0.75 ulps in the
reduced arg, but errors of much less than 0.5 ulps are needed; the bug
seems to be in kernel_rem_pio2.c).  Keep using a value 1 larger than
the documented value but supply an array large enough hold the extra
unused result from this.

The bug can also be fixed quickly by increasing init_jk[0] in
k_rem_pio2.c from 2 to 3.  This gives behaviour identical to using
prec == 1 except it doesn't create the extra result.  It isn't clear
how the precision bug affects higher precisions.  113-bit (quad) is
the largest precision, so there is no way to use a large precision
to fix it.
2005-11-23 02:06:06 +00:00
Bruce Evans
4ce5120952 Mess up the "kernel" float trig function .c files with ifdefs so that
they can be #included in other .c files to give inline functions, and
use them to inline the functions in most callers (not in e_lgammaf_r.c).
__kernel_tanf() is too large and complicated for gcc to inline very well.

An athlons, this gives a speed increase under favourable pipeline
conditions of about 10% overall (larger for AXP, smaller for A64).
E.g., on AXP, sinf() on uniformly distributed args in [-2Pi, 2Pi]
now takes 30-56 cycles; it used to take 45-61 cycles; hardware fsin
takes 65-129.
2005-11-21 04:57:12 +00:00
Bruce Evans
58652034e8 Use double precision to simplify and optimize a long division.
On athlons, this gives a speedup of 10-20% for tanf() on uniformly
distributed args in [-2Pi, 2Pi].  (It only directly applies for 43%
of the args and gives a 16-20% speedup for these (more for AXP than
A64) and this gives an overall speedup of 10-12% which is all that it
should; however, it gives an overall speedup of 17-20% with gcc-3.3
on AXP-A64 by mysteriously effected cases where it isn't executed.)

I originally intended to use double precision for all internals of
float trig functions and will probably still do this, but benchmarking
showed that converting to double precision and back is a pessimization
in cases where a simple float precision calculation works, so it may
be optimal to switch precisions only when using extra precision is
much simpler.
2005-11-21 00:38:21 +00:00
Bruce Evans
23f6483e0a Restored a cleanup in rev.1.9 tthat was lost in rev.1.10. 2005-11-20 20:17:04 +00:00
Bruce Evans
8299eb7e3e Moved all the optimizations for |x| <= 9pi/2 from
__ieee754_rem_pio2f() to its 3 callers and manually inline them.

On Athlons, with favourable compiler flags and optimizations and
favourable pipeline conditions, this gives a speedup of 30-40 cycles
for cosf(), sinf() and tanf() on the range pi/4 < |x| <= 9pi/4, so
thes functions are now signifcantly faster than the hardware trig
functions in many cases.  E.g., in a benchmark with uniformly distributed
x in [-2pi, 2pi], A64 hardware fcos took 72-129 cycles and cosf() took
37-55 cycles.  Out-of-order execution is needed to get both of these
times.  The optimizations in this commit apparently work more by
removing 1 serialization point than by reducing latency.
2005-11-19 02:38:27 +00:00
Bruce Evans
3f1a8f462c Removed an unused declaration which was so old that it wasn't a prototype
and thus just broke building at any nonzero WARNS level.

Fixed nearby style bugs.
2005-11-18 05:03:12 +00:00
Ruslan Ermilov
110e1704d3 -mdoc sweep. 2005-11-17 13:00:00 +00:00
Bruce Evans
75ff209cbb Minor cleanups:
s_cosf.c and s_sinf.c:
Use a non-bogus magic constant for the threshold of pi/4.  It was 2 ulps
smaller than pi/4 rounded down, but its value is not critical so it should
be the result of natural rounding.

s_cosf.c and s_tanf.c:
Use a literal 0.0 instead of an unnecessary variable initialized to
[(float)]0.0.  Let the function prototype convert to 0.0F.

Improved wording in some comments.

Attempted to improve indentation of comments.
2005-11-17 03:53:22 +00:00
Bruce Evans
123e5d3dae Rearranged the the optimizations for special cases to reduce the average
number of branches.

Use a non-bogus magic constant for the threshold of pi/4.  It was 2 ulps
smaller than pi/4 rounded down, but its value is not critical so it should
be the result of natural rounding.  Use "<=" comparisons with rounded-
down thresholds for all small multiples of pi/4.

Cleaned up previous commit:
- use static const variables instead of expressions for multiples of pi/2
  to ensure that they are evaluated at compile time.  gcc currently
  evaluates them at compile time but C99 compilers are not required
  to do so.  We want compile time evaluation for optimization and don't
  care about side effects.
- use M_PI_2 instead of a magic constant for pi/2.  We need magic constants
  related to pi/2 elsewhere but not here since we just want pi/2 rounded
  to double and even prefer it to be rounded in the default rounding mode.
  We can depend on the cmpiler being C99ish enough to round M_PI_2 correctly
  just as much as we depended on it handling hex constants correctly.  This
  also fixes a harmless rounding error in the hex constant.
- keep using expressions n*<value for pi/2> in the initializers for the
  static const variables.  2*M_PI_2 and 4*M_PI_2 are obviously rounded in
  the same way as the corresponding infinite precision expressions for
  multiples of pi/2, and 3*M_PI_2 happens to be rounded like this, so we
  don't need magic constants for the multiples.
- fixed and/or updated some comments.
2005-11-17 02:20:04 +00:00
Bruce Evans
25efbfb212 Fixed some magic numbers.
The threshold for not being tiny was too small.  Use the usual 2**-12
threshold.  This change is not just an optimization, since the general
code that we fell into has accuracy problems even for tiny x.  Avoiding
it fixes 2*1366 args with errors of more than 1 ulp, with a maximum
error of 1.167 ulps.

The magic number 22 is log(DBL_EPSILON)/2 plus slop.  This is bogus
for float precision.  Use 9 (~log(FLT_EPSILON)/2 plus less slop than
for double precision).  The code for handling the interval
[2**-28, 9_was_22] has accuracy problems even for [9, 22], so this
change happens to fix errors of more than 1 ulp in about 2*17000
cases.  It leaves such errors in about 2*1074000 cases, with a max
error of 1.242 ulps.

The threshold for switching from returning exp(x)/2 to returning
exp(x/2)^2/2 was a little smaller than necessary.  As for coshf(),
This was not quite harmless since the exp(x/2)^2/2 case is inaccurate,
and fixing it avoids accuracy problems in 2*6 cases, leaving problems
in 2*19997 cases.

Fixed naming errors in pseudo-code in comments.
2005-11-13 00:41:46 +00:00
Bruce Evans
c24b7984fc Fixed some magic numbers.
The threshold for not being tiny was confusing and too small.  Use the
usual 2**-12 threshold and simplify the algorithm slightly so that
this threshold works (now use the threshold for sinhf() instead of one
for 1+expm1()).  This is just a small optimization.

The magic number 22 is log(DBL_EPSILON)/2 plus slop.  This is bogus
for float precision.  Use 9 (~log(FLT_EPSILON)/2 plus less slop than
for double precision).

The threshold for switching from returning exp(x)/2 to returning
exp(x/2)^2/2 was a little smaller than necessary.  This was not quite
harmless since the exp(x/2)^2/2 case is inaccurate.  Fixing it happens
to avoid accuracy problems for 2*6 of the 2*151 args that were handled
by the exp(x)/2 case.  This leaves accuracy problems for about 2*19997
args near the overflow threshold (~89); the maximum error there is
2.5029 ulps.

There are also accuracy probles for args in +-[0.5*ln2, 9] -- 2*188885
args with errors of more than 1 ulp, with a maximum error of 1.384 ulps.

Fixed a syntax error and naming errors in pseudo-code in comments.
2005-11-13 00:08:23 +00:00
Bruce Evans
e96c4fd9f7 Imoproved comments for the minimax polynomial.
Removed an unused variable.

Fixed some wrong comments and some nearby misformatting.
2005-11-12 20:06:04 +00:00
Bruce Evans
6e10a447f8 Tweaked the minimax polynomial and improved its comments. 2005-11-12 19:56:35 +00:00
Bruce Evans
787d6d77d5 Improved comments for the minimax polynomial. 2005-11-12 19:54:45 +00:00
Bruce Evans
d4a74de9fc As for the float trig functions, use a minimax polynomial that is
specialized for float precision.  The new polynomial has degree 8
instead of 14, and a maximum error of 2**-34.34 (absolute) instead of
2**-30.66.  This doesn't affect the final error significantly; the
maximum error was and is about 0.8879 ulps on amd64 -01.

The fdlibm expf() is not used on i386's (the "optimized" asm version
is used), but probably should be since it was already significantly
faster than the asm version on athlons.  The asm version has the
advantage of being more accurate, so keep using it for now.
2005-11-12 18:20:09 +00:00
Bruce Evans
c01611e437 As for __kernel_cosf() and __kernel_sinf(), use a fairly optimal minimax
polynomial for __kernel_tanf().  The old one was the double-precision
polynomial with coefficients truncated to float.  Truncation is not
a good way to convert minimax polynomials to lower precision.  Optimize
for efficiency and use the lowest-degree polynomial that gives a
relative error of less than 1 ulp.  It has degree 13 instead of 27,
and happens to be 2.5 times more accurate (in infinite precision) than
the old polynomial (the maximum error is 0.017 ulps instead of 0.041
ulps).

Unlike for cosf and sinf, the old accuracy was close to being inadequate
-- the polynomial for double precision has a max error of 0.014 ulps
and nearly this small an error is needed.  The new accuracy is also a
bit small, but exhaustive checking shows that even the old accuracy
was enough.  The increased accuracy reduces the maximum relative error
in the final result on amd64 -O1 from 0.9588 ulps to 0.9044 ulps.
2005-11-10 17:43:49 +00:00
Bruce Evans
2b6ca0f6a5 Detach k_rem_pio2f.c from the build since it is now unused. It is a libm
internal so this shouldn't cause version problems.
2005-11-06 17:59:40 +00:00
Bruce Evans
efff995f3b Use a 53-bit approximation to pi/2 instead of a 33+53 bit one for the
special case pi/4 <= |x| < 3*pi/4.  This gives a tiny optimization (it
saves 2 subtractions, which are scheduled well so they take a whole 1
cycle extra on an AthlonXP), and simplifies the code so that the
following optimization is not so ugly.

Optimize for the range 3*pi/4 < |x| < 9*Pi/2 in the same way.  On
Athlon{XP,64} systems, this gives a 25-40% optimization (depending a
lot on CFLAGS) for the cosf() and sinf() consumers on this range.
Relative to i387 hardware fcos and fsin, it makes the software versions
faster in most cases instead of slower in most cases.  The relative
optimization is smaller for tanf() the inefficient part is elsewhere.

The 53-bit approximation to pi/2 is good enough for pi/4 <= |x| <
3*pi/4 because after losing up to 24 bits to subtraction, we still
have 29 bits of precision and only need 25 bits.  Even with only 5
extra bits, it is possible to get perfectly rounded results starting
with the reduced x, since if x is nearly a multiple of pi/2 then x is
not near a half-way case and if x is not nearly a multiple of pi/2
then we don't lose many bits.  With our intentionally imperfect rounding
we get the same results for cosf(), sinf() and tanf() as without this
optimization.
2005-11-06 17:48:02 +00:00
Bruce Evans
32948b81c4 The logb() functions are not just ieee754 "test" functions, but are
standard in C99 and POSIX.1-2001+.  They are also not deprecated, since
apart from being standard they can handle special args slightly better
than the ilogb() functions.

Move their documentation to ilogb.3.  Try to use consistent and improved
wording for both sets of functions.  All of ieee854, C99 and POSIX
have better wording and more details for special args.

Add history for the logb() functions and ilogbl().  Fix history for
ilogb().
2005-11-06 12:18:27 +00:00
Bruce Evans
cb92d4d58f Moved the optimization for tiny x from __kernel_tan[f](x) to tan[f](x)
so that it can be faster for tiny x and avoided for reduced x.

This improves things a little differently than for cosine and sine.
We still need to reclassify x in the "kernel" functions, but we get
an extra optimization for tiny x, and an overall optimization since
tiny reduced x rarely happens.  We also get optimizations for space
and style.  A large block of poorly duplicated code to fix a special
case is no longer needed.  This supersedes the fixes in k_sin.c revs
1.9 and 1.11 and k_sinf.c 1.8 and 1.10.

Fixed wrong constant for the cutoff for "tiny" in tanf().  It was
2**-28, but should be almost the same as the cutoff in sinf() (2**-12).
The incorrect cutoff protected us from the bugs fixed in k_sinf.c 1.8
and 1.10, except 4 cases of reduced args passed the cutoff and needed
special handling in theory although not in practice.  Now we essentially
use a cutoff of 0 for the case of reduced args, so we now have 0 special
args instead of 4.

This change makes no difference to the results for sinf() (since it
only changes the algorithm for the 4 special args and the results for
those happen not to change), but it changes lots of results for sin().
Exhaustive testing is impossible for sin(), but exhaustive testing
for sinf() (relative to a version with the old algorithm and a fixed
cutoff) shows that the changes in the error are either reductions or
from 0.5-epsilon ulps to 0.5+epsilon ulps.  The new method just uses
some extra terms in approximations so it tends to give more accurate
results, and there are apparently no problems from having extra
accuracy.  On amd64 with -O1, on all float args the error range in ulps
is reduced from (0.500, 0.665] to [0.335, 0.500) in 24168 cases and
increased from 0.500-epsilon to 0.500+epsilon in 24 cases.  Non-
exhaustive testing by ucbtest shows no differences.
2005-11-02 14:01:45 +00:00
Bruce Evans
4f8d68d6ca Updated the comment about the optimization for tiny x (the previous
commit moved it).  This includes a comment that the "kernel" sine no
longer works on arg -0, so callers must now handle this case.  The kernel
sine still works on all other tiny args; without the optimization it is
just a little slower on these args.  I intended it to keep working on
all tiny args, but that seems to be impossible without losing efficiency
or accuracy.  (sin(x) ~ x * (1 + S1*x**2 + ...) would preserve -0, but
the approximation must be written as x + S1*x**3 + ... for accuracy.)
2005-11-02 13:06:49 +00:00
Bruce Evans
639a1e1106 Removed dead code for handling tan[f]() on odd multiples of pi/2. This
case never occurs since pi/2 is irrational so no multiple of it can
be represented as a float and we have precise arg reduction so we never
end up with a remainder of 0 in the "kernel" function unless the
original arg is 0.

If this case occurs, then we would now fall through to general code
that returns +-Inf (depending on the sign of the reduced arg) instead
of forcing +Inf.  The correct handling would be to return NaN since
we would have lost so much precision that the correct result can be
anything _except_ +-Inf.

Don't reindent the else clause left over from this, although it was already
bogusly indented ("if (foo) return; else ..." just marches the indentation
to the right), since it will be removed too.

Index: k_tan.c
===================================================================
RCS file: /home/ncvs/src/lib/msun/src/k_tan.c,v
retrieving revision 1.10
diff -r1.10 k_tan.c
88,90c88
< 			if (((ix | low) | (iy + 1)) == 0)
< 				return one / fabs(x);
< 			else {
---
> 			{
2005-11-02 06:45:21 +00:00
Bruce Evans
16622bffd4 Fixed some of the silliness related to rev.1.8. In 1.8, "double" in
a declaration was not translated to "float" although bit fiddling on
double variables was translated.  This resulted in garbage being put
into the low word of one of the doubles instead of non-garbage being
put into the only word of the intended float.  This had no effect on
any result because:
- with doubles, the algorithm for calculating -1/(x+y) is unnecessarily
  complicated.  Just returning -1/((double)x+y) would work, and the
  misdeclaration gave something like that except for messing up some
  low bits with the bit fiddling.
- doubles have plenty of bits to spare so messing up some of the low
  bits is unlikely to matter.
- due to other bugs, the buggy code is reached for a whole 4 args out
  of all 2**32 float args.  The bug fixed by 1.8 only affects a small
  percentage of cases and a small percentage of 4 is 0.  The 4 args
  happen to cause no problems without 1.8, so they are even less likely
  to be affected by the bug in 1.8 than average args; in fact, neither
  1.8 nor this commit makes any difference to the result for these 4
  args (and thus for all args).

Corrections to the log message in 1.8: the bug only applies to tan()
and not tanf(), not because the float type can't represent numbers
large enough to trigger the problem (e.g., the example in the fdlibm-5.3
readme which is > 1.0e269), but because:
- the float type can't represent small enough numbers.  For there to be
  a possible problem, the original arg for tanf() must lie very near an
  odd multiple of pi/2.  Doubles can get nearer in absolute units.  In
  ulps there should be little difference, but ...
- ... the cutoff for "small" numbers is bogus in k_tanf.c.  It is still
  the double value (2**-28).  Since this is 32 times smaller than
  FLT_EPSILON and large float values are not very uniformly distributed,
  only 6 args other than ones that are initially below the cutoff give
  a reduced arg that passes the cutoff (the 4 problem cases mentioned
  above and 2 non-problem cases).

Fixing the cutoff makes the bug affect tanf() and much easier to detect
than for tan().  With a cutoff of 2**-12 on amd64 with -O1, 670102
args pass the cutoff; of these, there are 337604 cases where there
might be an error of >= 1 ulp and 5826 cases where there is such an
error; the maximum error is 1.5382 ulps.

The fix in 1.8 works with the reduced cutoff in all cases despite the
bug in it.  It changes the result in 84492 cases altogether to fix the
5826 broken cases.  Fixing the fix by translating "double" to "float"
changes the result in 42 cases relative to 1.8.  In 24 cases the
(absolute) error is increased and in 18 cases it is reduced, but it
remains less than 1 ulp in all cases.
2005-11-02 05:37:31 +00:00
Bruce Evans
053d1689b1 Fixed spelling of remquof() in its prototype. 2005-10-30 12:34:58 +00:00
Bruce Evans
f964c6ecfb Fixed some comments added in rev.1.5.
The log message for 1.5 said that some small (one or two ulp) inaccuracies
were fixed, and a comment implied that the critical change is to switch
the rounding mode to to-nearest, with a switch of the precision to
extended at no extra cost.  Actually, the errors are very large (ucbtest
finds ones of several hundred ulps), and it is the switch of the
precision that is critical.

Another comment was wrong about NaNs being handled sloppily.
2005-10-30 12:21:02 +00:00
Bruce Evans
19b114da0e Implement inline functions to give the complex result x+I*y from float
or double args x and y.  x+I*y cannot be used directly yet due to compiler
bugs.

Submitted by:	Steve Kargl <sgk@troutmask.apl.washington.edu>
2005-10-29 17:14:11 +00:00
Bruce Evans
8b438ea8dd Use double precision to simplify and optimize arg reduction for small
and medium size args too: instead of conditionally subtracting a float
17+24, 17+17+24 or 17+17+17+24 bit approximation to pi/2, always
subtract a double 33+53 bit one.  The float version is now closer to
the double version than to old versions of itself -- it uses the same
33+53 bit approximation as the simplest cases in the double version,
and where the float version had to switch to the slow general case at
|x| == 2^7*pi/2, it now switches at |x| == 2^19*pi/2 the same as the
double version.

This speeds up arg reduction by a factor of 2 for |x| between 3*pi/4 and
2^7*pi/4, and by a factor of 7 for |x| between 2^7*pi/4 and 2^19*pi/4.
2005-10-29 16:34:50 +00:00
Bruce Evans
21b0341c80 Start trying to make the float precision trig functions actually worth
using under FreeBSD.  Before this commit, all float precision functions
except exp2f() were implemented using only float precision, apparently
because Cygnus needed this in 1993 for embedded systems with slow or
inefficient double precision.  For FreeBSD, except possibly on systems
that do floating point entirely in software (very old i386 and now
arm), this just gives a more complicated implementation, many bugs,
and usually worse performance for float precision than for double
precision.  The bugs and worse performance were particulary large in
arg reduction for trig functions.  We want to divide by an approximation
to pi/2 which has as many as 1584 bits, so we should use the widest
type that is efficient and/or easy to use, i.e., double.  Use fdlibm's
__kernel_rem_pio2() to do this as Sun apparently intended.  Cygnus's
k_rem_pio2f.c is now unused.  e_rem_pio2f.c still needs to be separate
from e_rem_pio2.c so that it can be optimized for float args.  Similarly
for long double precision.

This speeds up cosf(x) on large args by a factor of about 2.  Correct
arg reduction on large args is still inherently very slow, so hopefully
these args rarely occur in practice.  There is much more efficiency
to be gained by using double precision to speed up arg reduction on
medium and small float args.
2005-10-29 08:15:29 +00:00
Bruce Evans
11dc241777 Use fairly optimal minimax polynomials for __kernel_cosf() and
__kernel_sinf().  The old ones were the double-precision polynomials
with coefficients truncated to float.  Truncation is not a good way
to convert minimax polynomials to lower precision.  Optimize for
efficiency and use the lowest-degree polynomials that give a relative
error of less than 1 ulp -- degree 8 instead of 14 for cosf and degree
9 instead of 13 for sinf.  For sinf, the degree 8 polynomial happens
to be 6 times more accurate than the old degree 14 one, but this only
gives a tiny amount of extra accuracy in results -- we just need to
use a a degree high enough to give a polynomial whose relative accuracy
in infinite precision (but with float coefficients) is a small fraction
of a float ulp (fdlibm generally uses 1/32 for the small fraction, and
the fraction for our degree 8 polynomial is about 1/600).

The maximum relative errors for cosf() and sinf() are now 0.7719 ulps
and 0.7969 ulps, respectively.
2005-10-28 13:36:58 +00:00
Bruce Evans
3b46e988e7 Use a better algorithm for reducing the error in __kernel_cos[f]().
This supersedes the fix for the old algorithm in rev.1.8 of k_cosf.c.

I want this change mainly because it is an optimization.  It helps
make software cos[f](x) and sin[f](x) faster than the i387 hardware
versions for small x.  It is also a simplification, and reduces the
maximum relative error for cosf() and sinf() on machines like amd64
from about 0.87 ulps to about 0.80 ulps.  It was validated for cosf()
and sinf() by exhaustive testing.  Exhaustive testing is not possible
for cos() and sin(), but ucbtest reports a similar reduction for the
worst case found by non-exhaustive testing.  ucbtest's non-exhaustive
testing seems to be good enough to find problems in algorithms but not
maximum relative errors when there are spikes.  E.g., short runs of
it find only 3 ulp error where the i387 hardware cos() has an error
of about 2**40 ulps near pi/2.
2005-10-26 12:36:18 +00:00
Bruce Evans
a92cb60b4e More fixes for arg reduction near pi/2 on systems with broken assignment
to floats (mainly i386's).  All errors of more than 1 ulp for float
precision trig functions were supposed to have been fixed; however,
compiling with gcc -O2 uncovered 18250 more such errors for cosf(),
with a maximum error of 1.409 ulps.

Use essentially the same fix as in rev.1.8 of k_rem_pio2f.c (access a
non-volatile variable as a volatile).  Here the -O1 case apparently
worked because the variable is in a 2-element array and it takes -O2
to mess up such a variable by putting it in a register.

The maximum error for cosf() on i386 with gcc -O2 is now 0.5467 (it
is still 0.5650 with gcc -O1).  This shows that -O2 still causes some
extra precision, but the extra precision is now good.

Extra precision is harmful mainly for implementing extra precision in
software.  We want to represent x+y as w+r where both "+" operations
are in infinite precision and r is tiny compared with w.  There is a
standard algorithm for this (Knuth (1981) 4.2.2 Theorem C), and fdlibm
uses this routinely, but the algorithm requires w and r to have the
same precision as x and y.  w is just x+y (calculated in the same
finite precision as x and y), and r is a tiny correction term.  The
i386 gcc bugs tend to give extra precision in w, and then using this
extra precision in the calculation of r results in the correction
mostly staying in w and being missing from r.  There still tends to
be no problem if the result is a simple expression involving w and r
-- modulo spills, w keeps its extra precision and r remains the right
correction for this wrong w.  However, here we want to pass w and r
to extern functions.  Extra precision is not retained in function args,
so w gets fixed up, but the change to the tiny r is tinier, so r almost
remains as a wrong correction for the right w.
2005-10-25 12:13:37 +00:00
Bruce Evans
4339c67c48 Moved the optimization for tiny x from __kernel_{cos,sin}[f](x) to
{cos_sin}[f](x) so that x doesn't need to be reclassified in the
"kernel" functions to determine if it is tiny (it still needs to be
reclassified in the cosine case for other reasons that will go away).

This optimization is quite large for exponentially distributed x, since
x is tiny for almost half of the domain, but it is a pessimization for
uniformally distributed x since it takes a little time for all cases
but rarely applies.  Arg reduction on exponentially distributed x
rarely gives a tiny x unless the reduction is null, so it is best to
only do the optimization if the initial x is tiny, which is what this
commit arranges.  The imediate result is an average optimization of
1.4% relative to the previous version in a case that doesn't favour
the optimization (double cos(x) on all float x) and a large
pessimization for the relatively unimportant cases of lgamma[f][_r](x)
on tiny, negative, exponentially distributed x.  The optimization should
be recovered for lgamma*() as part of fixing lgamma*()'s low-quality
arg reduction.

Fixed various wrong constants for the cutoff for "tiny".  For cosine,
the cutoff is when x**2/2! == {FLT or DBL}_EPSILON/2.  We round down
to an integral power of 2 (and for cos() reduce the power by another
1) because the exact cutoff doesn't matter and would take more work
to determine.  For sine, the exact cutoff is larger due to the ration
of terms being x**2/3! instead of x**2/2!, but we use the same cutoff
as for cosine.  We now use a cutoff of 2**-27 for double precision and
2**-12 for single precision.  2**-27 was used in all cases but was
misspelled 2**27 in comments.  Wrong and sloppy cutoffs just cause
missed optimizations (provided the rounding mode is to nearest --
other modes just aren't supported).
2005-10-24 14:08:36 +00:00
Bruce Evans
74bbe8ed42 Fixed range reduction for large multiples of pi/2 on systems with
broken assignment to floats (e.g., i386 with gcc -O, but not amd64 or
ia64; i386 with gcc -O0 worked accidentally).

Use an unnamed volatile temporary variable to trick gcc -O into clipping
extra precision on assignment.  It's surprising that only 1 place needed
to be changed.

For tanf() on i386 with gcc -O, the bug caused errors > 1 ulp with a
density of 2.3% for args larger in magnitude than 128*pi/2, with a
maximum error of 1.624 ulps.

After this fix, exhaustive testing shows that range reduction for
floats works as intended assuming that it is in within a factor of
about 2^16 of working as intended for doubles.  It provides >= 8
extra bits of precision for all ranges.  On i386:

range                       max error in double/single ulps    extra precision
-----                       -------------------------------    ---------------
0 to 3*pi/4                 0x000d3132  /  0.0016              9+ bits
3*pi/4 to 128*pi/2          0x00160445  /  0.0027              8+
128*pi/2 to +Inf            0x00000030  /  0.00000009          23+
128*pi/2 up, -O0 before fix 0x00000030  /  0.00000009          23+
128*pi/2 up, -O1 before fix 0x10000000  /  0.5                 1

The 23+ bits of extra precision for large multiples corresponds to almost
perfect reduction to a pair of floats (24 extra would be perfect).

After this fix, the maximum relative error (relative to the corresponding
fdlibm double precision function) is < 1 ulp for all basic trig functions
on all 2^32 float args on all machines tested:

          amd64     ia64      i386-O0   i386-O1
	  ------    ------    ------    ------
cosf:     0.8681    0.8681    0.7927    0.5650
sinf:     0.8733    0.8610    0.7849    0.5651
tanf:     0.9708    0.9329    0.9329    0.7035
2005-10-11 07:56:05 +00:00
Bruce Evans
59b8fc1535 Fixed range reduction near (but not very near) medium-sized multiples
of pi/2 (1 line) and expand a comment about related magic (many lines).

The bug was essentially the same as for the +-pi/2 case (a mistranslated
mask), but was smaller so it only significantly affected multiples
starting near +-13*pi/2.  At least on amd64, for cosf() on all 2^32
float args, the bug caused 128 errors of >= 1 ulp, with a maximum error
of 1.2393 ulps.
2005-10-10 20:02:02 +00:00
Bruce Evans
11cba99f67 Fix numerous errors of >= 1 ulp for cosf(x) and sinf(x) (1 line)
and add a comment about related magic (many lines)).

__kernel_cos[f]() needs a trick to reduce the error to below 1 ulp
when |x| >= 0.3 for the range-reduced x.  Modulo other bugs, naive
code that doesn't use the trick would have an error of >= 1 ulp
in about 0.00006% of cases when |x| >= 0.3 for the unreduced x,
with a maximum relative error of about 1.03 ulps.  Mistransation
of the trick from the double precision case resulted in errors in
about 0.2% of cases, with a maximum relative error of about 1.3 ulps.

The mistranslation involved not doing implicit masking of the 32-bit
float word corresponding to to implicit masking of the lower 32-bit
double word by clearing it.

sinf() uses __kernel_cosf() for half of all cases so its errors from
this bug are similar.  tanf() is not affected.

The error bounds in the above and in my other recent commit messages
are for amd64.  Extra precision for floats on i386's accidentally masks
this bug, but only if k_cosf.c is compiled with -O.  Although the extra
precision helps here, this is accidental and depends on longstanding
gcc precision bugs (not clipping extra precision on assignment...),
and the gcc bugs are mostly avoided by compiling without -O.  I now
develop libm mainly on amd64 systems to simplify error detection and
debugging.
2005-10-09 21:07:23 +00:00
Bruce Evans
a0e34da09f Oops, the last-minute optimization in rev.1.8 wasn't a good idea. The
17+17+24 bit pi/2 must only be used when subtraction of the first 2
terms in it from the arg is exact.  This happens iff the the arg in
bits is one of the 2**17[-1] values on each side of (float)(pi/2).

Revert to the algorithm in rev.1.7 and only fix its threshold for using
the 3-term pi/2.  Use the threshold that maximizes the number of values
for which the 3-term pi/2 is used, subject to not changing the algorithm
for comparing with the threshold.  The 3-term pi/2 ends up being used
for about half of its usable range (about 64K values on each side).
2005-10-09 04:29:08 +00:00
Bruce Evans
cd604283af Fixed syntax error (a missing brace) in previous commit. 2005-10-08 22:55:36 +00:00
Bruce Evans
a7b8acac04 Fixed range reduction near (but not very near) +-pi/2. A bug caused
a maximum error of 2.905 ulps for cosf(), but the algorithm for cosf()
is good for < 1 ulps and happens to give perfect rounding (< 0.5 ulps)
near +-pi/2 except for the bug.  The extra relative errors for tanf()
were similar (slightly larger).  The bug didn't affect sinf() since
sinf'(+-pi/2) is 0.

For range reduction in ~[-3pi/4, -pi/4] and ~[pi/4, 3pi/4] we must
subtract +-pi/2 and the only complication is that this must be done
in extra precision.  We have handy 17+24-bit and 17+17+24-bit
approximations to pi/2.  If we always used the former then we would
lose up to 24 bits of accuracy due to cancelation of leading bits, but
we need to keep at least 24 bits plus a guard digit or 2, and should
keep as many guard bits as efficiency permits.  So we used the
less-precise pi/2 not very near +-pi/2 and switched to using the
more-precise pi/2 very near +-pi/2.  However, we got the threshold for
the switch wrong by allowing 19 bits to cancel, so we ended up with
only 21 or 22 bits of accuracy in some cases, which is even worse than
naively subtracting pi/2 would have done.

Exhaustive checking shows that allowing only 17 bits to cancel (min.
accuracy ~24 bits) is sufficient to reduce the maximum error for cosf()
near +-pi/2 to 0.726 ulps, but allowing only 6 bits to cancel (min.
accuracy ~35-bits) happens to give perfect rounding for cosf() at
little extra cost so we prefer that.

We actually (in effect) allow 0 bits to cancel and always use the
17+17+24-bit pi/2 (min. accuracy ~41 bits).  This is simpler and
probably always more efficient too.  Classifying args to avoid using
this pi/2 when it is not needed takes several extra integer operations
and a branch, but just using it takes only 1 FP operation.

The patch also fixes misspelling of 17 as 24 in many comments.

For the double-precision version, the magic numbers include 33+53 bits
for the less-precise pi/2 and (53-32-1 = 20) bits being allowed to
cancel, so there are ~33-20 = 13 guard bits.  This is sufficient except
probably for perfect rounding.  The more-precise pi/2 has 33+33+53
bits and we still waste time classifying args to avoid using it.

The bug is apparently from mistranslation of the magic 32 in 53-32-1.
The number of bits allowed to cancel is not critical and we use 32 for
double precision because it allows efficient classification using a
32-bit comparison.  For float precision, we must use an explicit mask,
and there are fewer bits so there is less margin for error in their
allocation.  The 32 got reduced to 4 but should have been reduced
almost in proportion to the reduction of mantissa bits.
2005-10-08 22:43:55 +00:00
Bruce Evans
0b42281ee9 Fixed aliasing bugs in TRUNC() by using the fdlibm macros for access
to doubles as bits.  fdlibm-1.1 had similar aliasing bugs, but these
were fixed by NetBSD or Cygnus before a modified version of fdlibm was
imported in 1994.  TRUNC() is only used by tgamma() and some
implementation-detail functions.  The aliasing bugs were detected by
compiling with gcc -O2 but don't seem to have broken tgamma() on i386's
or amd64's.  They broke my modified version of tgamma().

Moved the definition of TRUNC() to mathimpl.h so that it can be fixed
in one place, although the general version is even slower than necessary
because it has to operate on pointers to volatiles to handle its arg
sometimes being volatile.  Inefficiency of the fdlibm macros slows
down libm generally, and tgamma() is a relatively unimportant part of
libm.  The macros act as if on 32-bit words in memory, so they are
hard to optimize to direct actions on 64-bit double registers for
(non-i386) machines where this is possible.  The optimization is too
hard for gcc on amd64's, and declaring variables as volatile makes it
impossible.
2005-09-19 11:28:19 +00:00
David Schultz
26bd283f2a Add a missing ldexpf() alias for amd64.
Noticed by:	bz@, tjr@
2005-09-12 20:54:00 +00:00
Ken Smith
a84020c2b9 Bump the shared library version number of all libraries that have not
been bumped since RELENG_5.

Reviewed by:	ru
Approved by:	re (not needed for commit check but in principle...)
2005-07-22 17:19:05 +00:00