The latest round of fixes on Complex have made it fully C99 compliant
for a range of -5 to +5 in the real and imaginary components. I have yet
to finish the testing of overflow/underflow conditions. Here I report on
the standard range data.
I have updated the test of Complex to load test data from file
resources. These files have been produced using GNU gcc. But the data
can be swapped for another reference source.
Currently the test is using very high tolerances specified in units of
least precision (ULPs). Dropping in another file using low precision
data (not the full 17 fractional digits of a double) would break the
test. So this may have to be revised in the future if other references
are to be used.
Measuring the difference between Complex and the reference data with the
units of least precision (ULP) delta between them shows:
function mean +/- sd (n=count) [min, max] Median=x
acos 3.94 +/- 5.03 (n=484) [ 0, 36] Median= 2
acosh 3.94 +/- 5.03 (n=484) [ 0, 36] Median= 2
asinh 0.05 +/- 0.23 (n=242) [ 0, 1] Median= 0
atanh 0.84 +/- 2.14 (n=242) [ 0, 17] Median= 0
cosh 0.09 +/- 0.31 (n=242) [ 0, 2] Median= 0
sinh 0.08 +/- 0.30 (n=242) [ 0, 2] Median= 0
tanh 0.82 +/- 2.30 (n=242) [ 0, 34] Median= 0
exp 0.06 +/- 0.31 (n=484) [ 0, 2] Median= 0
log 0.10 +/- 0.37 (n=484) [ 0, 3] Median= 0
sqrt 0.02 +/- 0.16 (n=484) [ 0, 1] Median= 0
multiply 0.00 +/- 0.00 (n= 32) [ 0, 0] Median= 0
divide 1.03 +/- 1.75 (n= 32) [ 0, 7] Median= 1
pow 1.12 +/- 2.61 (n= 32) [ 0, 9] Median= 0
If we only include those with a delta above 1 ULP (i.e. so that there is
at least one number between the two):
acos 6.54 +/- 5.38 (n=274) [ 2, 36] Median= 5
acosh 6.54 +/- 5.38 (n=274) [ 2, 36] Median= 5
asinh NaN +/- NaN (n= 0) [NaN, NaN] Median=NaN
atanh 4.56 +/- 3.96 (n= 34) [ 2, 17] Median= 3
cosh 2.00 +/- 0.00 (n= 2) [ 2, 2] Median= 2
sinh 2.00 +/- 0.00 (n= 2) [ 2, 2] Median= 2
tanh 3.22 +/- 5.30 (n= 36) [ 2, 34] Median= 2
exp 2.00 +/- 0.00 (n= 9) [ 2, 2] Median= 2
log 3.00 +/- 0.00 (n= 4) [ 3, 3] Median= 3
sqrt NaN +/- NaN (n= 0) [NaN, NaN] Median=NaN
multiply NaN +/- NaN (n= 0) [NaN, NaN] Median=NaN
divide 5.00 +/- 2.31 (n= 4) [ 3, 7] Median= 5
pow 5.83 +/- 3.06 (n= 6) [ 2, 9] Median= 7
This mainly shows a count of real differences ignoring floating-point
round-off.
These show that Complex is doing quite well for all but:
acos
acosh
atanh
tanh
acosh is implemented using a trigonomic identity with acos and the two
are equally bad. Fixing acos would fix this too.
I am not sure what can be done for tanh. This uses the formula:
tan(a + b i) = sinh(2a)/(cosh(2a)+cos(2b)) + i [sin(2b)/(cosh(2a)+cos(2b))]
It is implemented entirely using the Math library. A histogram of the
failures show that there is mainly one anomaly with a ULP delta of 34:
tanh 2 23
tanh 3 12
tanh 34 1
For now this can be left for further investigation. More data may show
that this error is an outlier.
The data is: (0.0,1.5).tanh(). Perhaps there is a trigonomic identity to
use when the real (or imaginary) component is zero.
So how to fix acos and atanh?
atanh uses divide and log on a Complex.
acos uses multiply, sqrt and log on a Complex.
Thus the differences between Complex and the standard are in those
methods that are using the Complex object to perform part of the
computation.
I note that asin uses asinh which uses multiply, sqrt and log on a
Complex and this does not perform badly. The method is very similar to
acos. This may be due to the range of the test data or the
implementation using only positive component parts to preserve the
conjugate and odd function equalities.
The C++ boost library has implementations for asin, acos and atanh.
These have overflow and underflow protection and an efficient
computation in a 'normal' value range. I will investigate using those
methods to see if they make a difference to the error.
I would like to get this error down to under 1 ULP on average with a
lower maximum.
Then I will look at the boundary cases for finite numbers which have
overflow or underflow during parts of the computation. I am sure that
the functions using Math.sinh and Math.cosh which asymptote to infinity
require some overflow protection. These are:
cosh
sinh
tanh
Alex