You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Alex Herbert (Jira)" <ji...@apache.org> on 2026/10/08 07:19:00 UTC
[jira] [Commented] (MATH-1692) Test failures in Java 27
[ 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)