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
f32 case, 1.0 - 0.5ULP = 0.9999999701976776, and atanh(0.9999999701976776) = 9.010913339622269966955482563389. As a result, for all f32 x > 9.010913, 1.0 - 0.5ULP < tanh(x) < 1.0. In the same way, for all f32 x < -9.010913, -1.0 < tanh(x) < -1.0 + 0.5ULP.
- In
f16 case, 1.0 - 0.5ULP = 0.999755859375, and atanh(0.999755859375) = 4.505395634757801020091217354083. As a result, for all f16 x > 4.504, 1.0 - 0.5ULP < tanh(x) < 1.0. In the same way, for all f16 x < -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.
Currently the accuracy requirement of built-in
tanhis defined asInherited from sinh(x) / cosh(x), while bothsinh(x)andcosh(x)inherited fromexp(x)andexp(-x).exp(x)is very easy to get overflow with rather small inputx(about88.72forf32and11.09forf16). Under current inherited definition of accuracy requirement,tanh(x)can result in indeterminate result whenabs(x) > 88.72forf32orabs(x) > 11.09forf16. However,tanh(x)is mathematically well-defined on the whole real number set(-inf, inf)and its value converges to1whenxis large enough and-1when small enough.To take numerical consideration,
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.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:tanh(x)sinh(x) / cosh(x)If
x < -9.010913the result is precisely-1.0.If
x > 9.010913the result is precisely1.0.sinh(x) / cosh(x)If
x < -4.504the result is precisely-1.0.If
x > 4.504the result is precisely1.0.This proposed accuracy is stricter than current inherited requirement when
xis smaller/larger than the condition but not makingsinhorcoshoverflow.Note that in the current HLSL native implementation,
tanhbuilt-in will result in NaN for large input like1000. Similar polypills has been implemented in Angle, taking condition onabs(x) > 15.0.