[
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)