-
Notifications
You must be signed in to change notification settings - Fork 368
Description
Currently the accuracy requirement of built-in tanh is defined as Inherited from sinh(x) / cosh(x), while both sinh(x) and cosh(x) inherited from exp(x) and exp(-x).
exp(x) is very easy to get overflow with rather small input x (about 88.72 for f32 and 11.09 for f16). Under current inherited definition of accuracy requirement, tanh(x) can result in indeterminate result when abs(x) > 88.72 for f32 or abs(x) > 11.09 for f16. However, tanh(x) is mathematically well-defined on the whole real number set (-inf, inf) and its value converges to 1 when x is large enough and -1 when small enough.
To take numerical consideration,
- In
f32case,1.0 - 0.5ULP = 0.9999999701976776, andatanh(0.9999999701976776) = 9.010913339622269966955482563389. As a result, for all f32x > 9.010913,1.0 - 0.5ULP < tanh(x) < 1.0. In the same way, for all f32x < -9.010913,-1.0 < tanh(x) < -1.0 + 0.5ULP. - In
f16case,1.0 - 0.5ULP = 0.999755859375, andatanh(0.999755859375) = 4.505395634757801020091217354083. As a result, for all f16x > 4.504,1.0 - 0.5ULP < tanh(x) < 1.0. In the same way, for all f16x < -4.504,-1.0 < tanh(x) < -1.0 + 0.5ULP.
So, to avoid indeterminate result for tanh, a possible accuracy requirement could be proposed as:
| Built-in Function | Accuracy for f32 | Accuracy for f16 |
|---|---|---|
tanh(x) |
Inherited from sinh(x) / cosh(x)If x < -9.010913 the result is precisely -1.0.If x > 9.010913 the result is precisely 1.0. |
Inherited from sinh(x) / cosh(x)If x < -4.504 the result is precisely -1.0.If x > 4.504 the result is precisely 1.0. |
This proposed accuracy is stricter than current inherited requirement when x is smaller/larger than the condition but not making sinh or cosh overflow.
Note that in the current HLSL native implementation, tanh built-in will result in NaN for large input like 1000. Similar polypills has been implemented in Angle, taking condition on abs(x) > 15.0.