[ 
https://issues.apache.org/jira/browse/MATH-1692?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18124869#comment-18124869
 ] 

Alex Herbert commented on MATH-1692:
------------------------------------

You can see why this fails as it implements the canonical formula:
{noformat}
asinh(a) = log(a + sqrt(a * a + 1))
acosh(a) = log(a + sqrt(a * a - 1))
{noformat}
This is an issue when a is large as squaring it overflows. Simple fix is to 
know we cannot +/- 1 to 2^54.
{code:java}
if (Math.abs(a) > 0x1p27) {
    // asinh = acosh
    AccurateMath.log(Math.abs(a) + a)
}
{code}
h2. Implementation change

Since hypot is overflow safe asinh can also be fixed using that:
{code:java}
// asinh
AccurateMath.log(a + AccurateMath.hypot(a, 1));
{code}
The same does not apply for acosh and the hypot method would have to be adapted 
to compute a signed square of the second argument to add -1 to a*a.

Looking inside hypot it first compares the exponents of the two arguments. If 
above 27 then it returns the absolute value of the larger magnitude. If not 
then it returns sqrt(x*x + y*y). This does not use extended precision. So here 
AccurateMath hypot would compute the same result.

Note that the hypot method can use extended precision. The square of the larger 
magnitude can be computed exactly to double-double precision. The square of the 
smaller magnitude can be added in single precision or also as a double-double. 
The method used in o.a.c.Numbers.Complex uses the extended precision square of 
both arguments. When I developed that it was more accurate than Math.hypot in 
JDK 8 and insensitive to magnitude changes in the low 21 bits of the 53-bit 
mantissa when the upper 32-bits are equal. The JDK 8 implementation was flawed 
since on certain input hypot(a, b) != hypot(b, a) which breaks the documented 
contract for the method. Newer JDKs should have improved on this though. Modern 
JDKs will likely implement hypot with extended precision using 
fused-multiply-add, or delegate to a native method which uses extended 
precision in the FPU.

In short, if we update AccurateMath hypot to use extended precision on sqrt(a*a 
+/- 1) it may compute a 1 ULP difference when a ~ 2^27 and improve the 
asinh/acosh accuracy.

The asinh/acosh methods were added in JDK 27. The documentation states that the 
expected ULP is 2.5. See ([Math asinh (Javadoc JDK 
27)|https://docs.oracle.com/en/java/javase/27/docs/api/java.base/java/lang/Math.html#asinh(double)]).

> Test failures in Java 27
> ------------------------
>
>                 Key: MATH-1692
>                 URL: https://issues.apache.org/jira/browse/MATH-1692
>             Project: Commons Math
>          Issue Type: Test
>          Components: legacy-core
>    Affects Versions: 4.0-beta1
>            Reporter: Gilles Sadowski
>            Priority: Minor
>              Labels: comparison, jdk27, unit-test
>
> Current code builds fine with JDK 11, 17 and 21, but with JDK 27, the 
> following failures occur:
> {noformat}
> [INFO] Running 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest
> [ERROR] Tests run: 72, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 
> 0.075 s <<< FAILURE! -- in 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictCompar
> isonTest
> [ERROR] 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.test1[55]
>  -- Time elapsed: 0.004 s <<< FAILURE!
> java.lang.AssertionError: double asinh(-1.7976931348623157E308) expected 
> -710.4758600739439 actual -Infinity entries [6]
>         at org.junit.Assert.fail(Assert.java:89)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.reportFailedResults(AccurateMathStrictComparisonTest.java:161)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.callMethods(AccurateMathStrictComparisonTest.java:187)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.setupMethodCall(AccurateMathStrictComparisonTest.java:212)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.test1(AccurateMathStrictComparisonTest.java:94)
>         at java.base/java.lang.reflect.Method.invoke(Method.java:583)
> [ERROR] 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.test1[56]
>  -- Time elapsed: 0.001 s <<< FAILURE!
> java.lang.AssertionError: double acosh(-1.7976931348623157E308) expected NaN 
> actual Infinity entries [6]
>         at org.junit.Assert.fail(Assert.java:89)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.reportFailedResults(AccurateMathStrictComparisonTest.java:161)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.callMethods(AccurateMathStrictComparisonTest.java:187)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.setupMethodCall(AccurateMathStrictComparisonTest.java:212)
>         at 
> org.apache.commons.math4.legacy.core.jdkmath.AccurateMathStrictComparisonTest.test1(AccurateMathStrictComparisonTest.java:94)
>         at java.base/java.lang.reflect.Method.invoke(Method.java:583)
> {noformat}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to