@@ -133,6 +133,29 @@ struct exp_b_reduc_t {
133133 double lo;
134134};
135135
136+ // Coefficients for double (6th-degree minimax polynomial on [0, 2^-7]).
137+ // Minimax polynomial of log(1 + dx) generated by Sollya with:
138+ // > P = fpminimax(log(1 + x)/x, 6, [|D...|], [0, 2^-7]);
139+ static constexpr double LOG_COEFFS_DOUBLE[6 ] = {
140+ -0x1 .ffffffffffffcp -2 , 0x1 .5555555552ddep-2 , -0x1 .ffffffefe562dp -3 ,
141+ 0x1 .9999817d3a50fp-3 , -0x1 .554317b3f67a5p-3 , 0x1 .1dc5c45e09c18p-3 };
142+
143+ // Coefficients for float (6th-degree minimax polynomial on [0, 2^-7]).
144+ // Minimax polynomial of log(1 + dx) generated by Sollya with:
145+ // > P = fpminimax(log(1 + x)/x, 6, [|D...|], [0, 2^-7]);
146+ static constexpr float LOG_COEFFS_FLOAT[6 ] = {-0x1 .fffffep -2f , 0x1 .555556p-2f ,
147+ -0x1 .fffefep -3f , 0x1 .99999ap-3f ,
148+ -0x1 .554318p-3f , 0x1 .1dc5c4p-3f };
149+
150+ // log(2) in double precision.
151+ static constexpr double LOG2_DOUBLE = 0x1 .62e42fefa39efp-1 ;
152+
153+ // log(2) in float precision.
154+ // Generated by Sollya with the following commands:
155+ // > display = hexadecimal;
156+ // > round(log(2), SG, RN);
157+ static constexpr float LOG2_FLOAT = 0x1 .62e43p-1f ;
158+
136159// The function correctly calculates b^x value with at least float precision
137160// in a limited range.
138161// Range reduction:
@@ -297,73 +320,46 @@ LIBC_INLINE static double log2_eval(double x) {
297320 return result;
298321}
299322
300- // x should be positive, normal finite value
301- LIBC_INLINE static float log_eval_f (float x) {
323+ template <typename T> LIBC_INLINE static T log_eval (T x) {
302324 // For x = 2^ex * (1 + mx), logf(x) = ex * logf(2) + logf(1 + mx).
303- using FPB = fputil::FPBits<float >;
304- FPB bs (x);
325+ using FPBits = fputil::FPBits<T >;
326+ FPBits xbits (x);
305327
306- float ex = static_cast <float >(bs .get_exponent ());
328+ T ex = static_cast <T>(xbits .get_exponent ());
307329 // p1 is the leading 7 bits of mx, i.e.
308330 // p1 * 2^(-7) <= m_x < (p1 + 1) * 2^(-7).
309- int p1 = static_cast <int >(bs .get_mantissa () >> (FPB ::FRACTION_LEN - 7 ));
331+ int p1 = static_cast <int >(xbits .get_mantissa () >> (FPBits ::FRACTION_LEN - 7 ));
310332
311333 // Set bs to (1 + (mx - p1*2^(-7))
312- bs .set_uintval (bs .uintval () & (FPB ::FRACTION_MASK >> 7 ));
313- bs .set_biased_exponent (FPB ::EXP_BIAS);
334+ xbits .set_uintval (xbits .uintval () & (FPBits ::FRACTION_MASK >> 7 ));
335+ xbits .set_biased_exponent (FPBits ::EXP_BIAS);
314336 // dx = (mx - p1*2^(-7)) / (1 + p1*2^(-7)).
315- float dx = (bs.get_val () - 1 .0f ) * ONE_OVER_F_FLOAT[p1];
316-
317- // Minimax polynomial of log(1 + dx) generated by Sollya with:
318- // > P = fpminimax(log(1 + x)/x, 6, [|D...|], [0, 2^-7]);
319- const float COEFFS[6 ] = {-0x1 .fffffep -2f , 0x1 .555556p-2f , -0x1 .fffefep -3f ,
320- 0x1 .99999ap-3f , -0x1 .554318p-3f , 0x1 .1dc5c4p-3f };
321-
322- float dx2 = dx * dx;
323-
324- float c1 = fputil::multiply_add (dx, COEFFS[1 ], COEFFS[0 ]);
325- float c2 = fputil::multiply_add (dx, COEFFS[3 ], COEFFS[2 ]);
326- float c3 = fputil::multiply_add (dx, COEFFS[5 ], COEFFS[4 ]);
337+ T dx = static_cast <T>(xbits.get_val () - 1.0 ) *
338+ (std::is_same<T, double >::value ? static_cast <T>(ONE_OVER_F[p1])
339+ : ONE_OVER_F_FLOAT[p1]);
327340
328- float p = fputil::polyeval (dx2, dx, c1, c2, c3) ;
341+ T dx2 = dx * dx ;
329342
330- float result = fputil::multiply_add (ex, 0x1 .62e42ep-1f , LOG_F_FLOAT[p1] + p);
331- return result;
332- }
333-
334- // x should be positive, normal finite value
335- LIBC_INLINE static double log_eval (double x) {
336- // For x = 2^ex * (1 + mx)
337- // log(x) = ex * log(2) + log(1 + mx)
338- using FPB = fputil::FPBits<double >;
339- FPB bs (x);
340-
341- double ex = static_cast <double >(bs.get_exponent ());
342-
343- // p1 is the leading 7 bits of mx, i.e.
344- // p1 * 2^(-7) <= m_x < (p1 + 1) * 2^(-7).
345- int p1 = static_cast <int >(bs.get_mantissa () >> (FPB::FRACTION_LEN - 7 ));
343+ const T *coeffs = nullptr ;
344+ T log2_val;
345+ if constexpr (std::is_same<T, double >::value) {
346+ coeffs = LOG_COEFFS_DOUBLE;
347+ log2_val = LOG2_DOUBLE;
348+ } else {
349+ coeffs = LOG_COEFFS_FLOAT;
350+ log2_val = LOG2_FLOAT;
351+ }
346352
347- // Set bs to (1 + (mx - p1*2^(-7))
348- bs.set_uintval (bs.uintval () & (FPB::FRACTION_MASK >> 7 ));
349- bs.set_biased_exponent (FPB::EXP_BIAS);
350- // dx = (mx - p1*2^(-7)) / (1 + p1*2^(-7)).
351- double dx = (bs.get_val () - 1.0 ) * ONE_OVER_F[p1];
353+ T c1 = fputil::multiply_add (dx, coeffs[1 ], coeffs[0 ]);
354+ T c2 = fputil::multiply_add (dx, coeffs[3 ], coeffs[2 ]);
355+ T c3 = fputil::multiply_add (dx, coeffs[5 ], coeffs[4 ]);
352356
353- // Minimax polynomial of log(1 + dx) generated by Sollya with:
354- // > P = fpminimax(log(1 + x)/x, 6, [|D...|], [0, 2^-7]);
355- const double COEFFS[6 ] = {-0x1 .ffffffffffffcp -2 , 0x1 .5555555552ddep-2 ,
356- -0x1 .ffffffefe562dp -3 , 0x1 .9999817d3a50fp-3 ,
357- -0x1 .554317b3f67a5p-3 , 0x1 .1dc5c45e09c18p-3 };
358- double dx2 = dx * dx;
359- double c1 = fputil::multiply_add (dx, COEFFS[1 ], COEFFS[0 ]);
360- double c2 = fputil::multiply_add (dx, COEFFS[3 ], COEFFS[2 ]);
361- double c3 = fputil::multiply_add (dx, COEFFS[5 ], COEFFS[4 ]);
357+ T p = fputil::polyeval (dx2, dx, c1, c2, c3);
362358
363- double p = fputil::polyeval (dx2, dx, c1, c2, c3);
364- double result =
365- fputil::multiply_add (ex, /* log(2) */ 0x1 .62e42fefa39efp- 1 , LOG_F[p1] + p);
366- return result ;
359+ if constexpr (std::is_same<T, double >::value)
360+ return fputil::multiply_add (ex, log2_val, LOG_F[p1] + p);
361+ else
362+ return fputil::multiply_add (ex, log2_val, LOG_F_FLOAT[p1] + p) ;
367363}
368364
369365// Rounding tests for 2^hi * (mid + lo) when the output might be denormal. We
0 commit comments