@@ -24,41 +24,59 @@ LLVM_LIBC_FUNCTION(float, expm1f, (float x)) {
24
24
using FPBits = typename fputil::FPBits<float >;
25
25
FPBits xbits (x);
26
26
27
- // When x < log(2^-25) or nan
28
- if (unlikely (xbits.uintval () >= 0xc18a'a123U )) {
29
- // exp(-Inf) = 0
30
- if (xbits.is_inf ())
31
- return -1 .0f ;
32
- // exp(nan) = nan
33
- if (xbits.is_nan ())
34
- return x;
27
+ uint32_t x_u = xbits.uintval ();
28
+ uint32_t x_abs = x_u & 0x7fff'ffffU ;
29
+
30
+ // Exceptional value
31
+ if (unlikely (x_u == 0x3e35'bec5U )) { // x = 0x1.6b7d8ap-3f
35
32
int round_mode = fputil::get_round ();
36
- if (round_mode == FE_UPWARD || round_mode == FE_TOWARDZERO )
37
- return - 0x1 .ffff ' fep-1f; // -1.0f + 0x1.0p-24f
38
- return -1.0f ;
33
+ if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD )
34
+ return 0x1 .8dbe64p- 3f ;
35
+ return 0x1 .8dbe62p- 3f ;
39
36
}
40
- // x >= 89 or nan
41
- if (unlikely(!xbits.get_sign() && (xbits.uintval() >= 0x42b2' 0000 ))) {
42
- if (xbits.uintval () < 0x7f80'0000U ) {
43
- int rounding = fputil::get_round ();
44
- if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
45
- return static_cast <float >(FPBits (FPBits::MAX_NORMAL));
46
37
47
- errno = ERANGE;
38
+ // When |x| > 25*log(2), or nan
39
+ if (unlikely (x_abs >= 0x418a'a123U )) {
40
+ // x < log(2^-25)
41
+ if (xbits.get_sign ()) {
42
+ // exp(-Inf) = 0
43
+ if (xbits.is_inf ())
44
+ return -1 .0f ;
45
+ // exp(nan) = nan
46
+ if (xbits.is_nan ())
47
+ return x;
48
+ int round_mode = fputil::get_round ();
49
+ if (round_mode == FE_UPWARD || round_mode == FE_TOWARDZERO)
50
+ return -0x1 .ffff ' fep-1f; // -1.0f + 0x1.0p-24f
51
+ return -1.0f;
52
+ } else {
53
+ // x >= 89 or nan
54
+ if (xbits.uintval() >= 0x42b2' 0000 ) {
55
+ if (xbits.uintval () < 0x7f80'0000U ) {
56
+ int rounding = fputil::get_round ();
57
+ if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
58
+ return static_cast <float >(FPBits (FPBits::MAX_NORMAL));
59
+
60
+ errno = ERANGE;
61
+ }
62
+ return x + static_cast <float >(FPBits::inf ());
63
+ }
48
64
}
49
- return x + static_cast <float >(FPBits::inf ());
50
65
}
51
66
52
- int unbiased_exponent = static_cast <int >(xbits.get_unbiased_exponent ());
53
67
// |x| < 2^-4
54
- if (unbiased_exponent < 123 ) {
68
+ if (x_abs < 0x3d80'0000U ) {
55
69
// |x| < 2^-25
56
- if (unbiased_exponent < 102 ) {
70
+ if (x_abs < 0x3300'0000U ) {
57
71
// x = -0.0f
58
72
if (unlikely (xbits.uintval () == 0x8000'0000U ))
59
73
return x;
60
- // When |x| < 2^-25, the relative error:
61
- // |(e^x - 1) - x| / |x| < |x^2| / |x| = |x| < 2^-25 < epsilon(1)/2.
74
+ // When |x| < 2^-25, the relative error of the approximation e^x - 1 ~ x
75
+ // is:
76
+ // |(e^x - 1) - x| / |e^x - 1| < |x^2| / |x|
77
+ // = |x|
78
+ // < 2^-25
79
+ // < epsilon(1)/2.
62
80
// So the correctly rounded values of expm1(x) are:
63
81
// = x + eps(x) if rounding mode = FE_UPWARD,
64
82
// or (rounding mode = FE_TOWARDZERO and x is negative),
@@ -67,20 +85,21 @@ LLVM_LIBC_FUNCTION(float, expm1f, (float x)) {
67
85
// fma(x, x, x) ~ x + x^2 instead.
68
86
return fputil::fma (x, x, x);
69
87
}
88
+
70
89
// 2^-25 <= |x| < 2^-4
71
90
double xd = static_cast <double >(x);
72
91
double xsq = xd * xd;
73
92
// Degree-8 minimax polynomial generated by Sollya with:
74
93
// > display = hexadecimal;
75
- // > P = fpminimax(expm1(x)/x, 7 , [|D...|], [-2^-4, 2^-4]);
94
+ // > P = fpminimax(( expm1(x) - x)/x^2, 6 , [|D...|], [-2^-4, 2^-4]);
76
95
double r =
77
- fputil::polyeval (xd, 0x1p-1 , 0x1 .55555555559abp -3 , 0x1 .55555555551a7p -5 ,
78
- 0x1 .111110f70f2a4p -7 , 0x1 .6c16c17639e82p -10 ,
79
- 0x1 .a02526febbea6p -13 , 0x1 .a01dc40888fcdp -16 );
96
+ fputil::polyeval (xd, 0x1p-1 , 0x1 .55555555557ddp -3 , 0x1 .55555555552fap -5 ,
97
+ 0x1 .111110fcd58b7p -7 , 0x1 .6c16c1717660bp -10 ,
98
+ 0x1 .a0241f0006d62p -13 , 0x1 .a01e3f8d3c06p -16 );
80
99
return static_cast <float >(fputil::fma (r, xsq, xd));
81
100
}
82
101
83
- // For -18 < x < 89, to compute exp (x), we perform the following range
102
+ // For -18 < x < 89, to compute expm1 (x), we perform the following range
84
103
// reduction: find hi, mid, lo such that:
85
104
// x = hi + mid + lo, in which
86
105
// hi is an integer,
@@ -89,48 +108,30 @@ LLVM_LIBC_FUNCTION(float, expm1f, (float x)) {
89
108
// In particular,
90
109
// hi + mid = round(x * 2^7) * 2^(-7).
91
110
// Then,
92
- // exp (x) = exp(hi + mid + lo) = exp(hi) * exp(mid) * exp(lo).
111
+ // expm1 (x) = exp(hi + mid + lo) - 1 = exp(hi) * exp(mid) * exp(lo) - 1 .
93
112
// We store exp(hi) and exp(mid) in the lookup tables EXP_M1 and EXP_M2
94
- // respectively. exp(lo) is computed using a degree-7 minimax polynomial
113
+ // respectively. exp(lo) is computed using a degree-4 minimax polynomial
95
114
// generated by Sollya.
96
115
97
- // Exceptional value
98
- if (xbits.uintval () == 0xbdc1'c6cbU ) {
99
- // x = -0x1.838d96p-4f
100
- int round_mode = fputil::get_round ();
101
- if (round_mode == FE_TONEAREST || round_mode == FE_DOWNWARD)
102
- return -0x1 .71c884p-4f ;
103
- return -0x1 .71c882p-4f ;
104
- }
105
-
106
116
// x_hi = hi + mid.
107
- int x_hi = static_cast <int >(x * 0x1 .0p7f);
117
+ int x_hi = static_cast <int >(x * 0x1 .0p7f + (xbits. get_sign () ? - 0 . 5f : 0 . 5f ) );
108
118
// Subtract (hi + mid) from x to get lo.
109
119
x -= static_cast <float >(x_hi) * 0x1 .0p-7f ;
110
120
double xd = static_cast <double >(x);
111
- // Make sure that -2^(-8) <= lo < 2^-8.
112
- if (x >= 0x1 .0p-8f ) {
113
- ++x_hi;
114
- xd -= 0x1 .0p-7 ;
115
- }
116
- if (x < -0x1 .0p-8f ) {
117
- --x_hi;
118
- xd += 0x1 .0p-7 ;
119
- }
120
121
x_hi += 104 << 7 ;
121
122
// hi = x_hi >> 7
122
123
double exp_hi = EXP_M1[x_hi >> 7 ];
123
124
// lo = x_hi & 0x0000'007fU;
124
125
double exp_mid = EXP_M2[x_hi & 0x7f ];
125
126
double exp_hi_mid = exp_hi * exp_mid;
126
- // Degree-7 minimax polynomial generated by Sollya with the following
127
+ // Degree-4 minimax polynomial generated by Sollya with the following
127
128
// commands:
128
129
// > display = hexadecimal;
129
- // > Q = fpminimax(expm1(x)/x, 6 , [|D...|], [-2^-8, 2^-8]);
130
+ // > Q = fpminimax(expm1(x)/x, 3 , [|D...|], [-2^-8, 2^-8]);
130
131
// > Q;
131
- double exp_lo = fputil::polyeval (
132
- xd, 0x1p0, 0x1p0, 0x1p- 1 , 0x1 .5555555555555p- 3 , 0x1 .55555555553ap- 5 ,
133
- 0x1 .1111111204dfcp- 7 , 0x1 .6c16cb2da593ap- 10 , 0x1 .9ff1648996d2ep- 13 );
132
+ double exp_lo =
133
+ fputil::polyeval ( xd, 0x1 .0p0, 0x1 .ffffffffff777p - 1 , 0x1 .000000000071cp- 1 ,
134
+ 0x1 .555566668e5e7p- 3 , 0x1 .55555555ef243p- 5 );
134
135
return static_cast <float >(fputil::fma (exp_hi_mid, exp_lo, -1.0 ));
135
136
}
136
137
0 commit comments