JDK-8285384 : Math.exp(1.0) has different result on aarch64 vs x86
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 17
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • Submitted: 2022-04-21
  • Updated: 2022-04-22
  • Resolved: 2022-04-21
Related Reports
Relates :  
Description
On aarch64, `Math.exp(1.0)` returns a value that has an extra decimal place compared with the result on x86:

#### `linux-aarch64`
```
$ jshell
|  Welcome to JShell -- Version 17.0.3
|  For an introduction type: /help intro

jshell> Math.exp(1.0)
$1 ==> 2.7182818284590455
jshell> Math.exp(1.0) == 2.718281828459045D
$2 ==> false
```

#### `linux-x64`
```
$ jshell 
|  Welcome to JShell -- Version 17.0.3
|  For an introduction type: /help intro

jshell> Math.exp(1.0)
$1 ==> 2.718281828459045
jshell> Math.exp(1.0) == 2.718281828459045D
$2 ==> true
```

Filed on behalf of [~fniephaus].
Comments
While it would be preferable for exp(1.0) to equal Math.E, the current Math.exp spec does not require this so assertions that this should hold are not justified.
22-04-2022

Thanks, Raffaello. That's all good! Just wanted to make sure that this is ok as I didn't mention Math.E in my initial bug report.
22-04-2022

Hi Fabio, I know this is annoying, but apart from re-specifying the behavior of methods in j.l.Math, which would take a long time to formulate and implement, there seems to be no short term solution. Since j.l.Math::exp is an intrinsic, I guess it is implemented either on silicon or in some ARM provided library. Or it fails over to StrictMath::exp, which doesn't produce E either. But I didn't investigate further. (Note that the semantics of StrictMath::exp are that of fdlibm version 5.3.) Numeric tests that expect Math.exp(1.0) == Math.E are ill advised. They should use more tolerant assertions when dealing with transcendental functions. This is the only short term solution that comes to my mind. It would be nice if all transcendental functions were correctly rounded, always producing the floating-point value closest to the actual real value. There are free implementations around, but they usually perform worse.
22-04-2022

Thanks for the comments! Although the result of Math.exp(1.0) is within the accuracy requirements of j.l.Math, I'd like to note that it does not match Math.E, which I still find problematic. Numeric tests that somehow assert Math.exp(1.0) == Math.E currently fail on aarch64.
22-04-2022

Thanks for the analysis everyone - I was not aware of (or had forgotten) the subtleties of the spec for this method.
21-04-2022

[~dnsimon] Intel's implementation of Math.exp(1.0) is correctly rounded; ARM's is not, although still within the accuracy requirements of j.l.Math.
21-04-2022

Specifically, for Math.exp the quality of implementation requirements are: "The computed result must be within 1 ulp of the exact result. Results must be semi-monotonic." The 1 ulp accuracy means either of the two floating point numbers bracketing the true result may be returned (assuming the true result is not representable as a floating-point number itself). Mathematically, exp(1.0) is equal to e and as a transcendental number, e is not representable. In decimal the value of e is 2.7182818284590452353602874713526624977572470936999… and in binary 10.101101111110000101010001011000101000101011101101001 010100110101010111111011100010101100010000000100111001111010011110011110001... So the two returned values do look to both be acceptable in terms of bracketing the true value of e. Closing as not a bug.
21-04-2022

On macOS Catalina 2.6 GHz 6-Core Intel Core i7: jshell> Math.exp(1.0) == 2.718281828459045D $1 ==> true jshell> StrictMath.exp(1.0) == 2.718281828459045D $2 ==> false jshell> StrictMath.exp(1.0) $3 ==> 2.7182818284590455
21-04-2022

As long as the implementation returns results within the accuracy and semi-monotonicity properties mandated by j.l.Math, it is "correct".
21-04-2022

I'm seeing something similar on x86: $ jshell | Welcome to JShell -- Version 11.0.14 | For an introduction type: /help intro jshell> StrictMath.exp(1.0) ; $1 ==> 2.7182818284590455 jshell> Math.exp(1.0) ; $2 ==> 2.718281828459045 Not a bug, I think, as long as the results are monotonic. e = 2.71828182845904523536...
21-04-2022

The outcome of Intel is exactly Math.E.
21-04-2022

Intel's implementation seems more accurate. But keep in mind that j.l.Math is allowed to have some latitude in the accuracy.
21-04-2022

How interesting! I'm investigating.
21-04-2022