@@ -340,6 +340,14 @@ template <typename T> struct bits {
340
340
class fp ;
341
341
template <int SHIFT = 0 > fp normalize (fp value);
342
342
343
+ // Lower (upper) boundary is a value half way between a floating-point value
344
+ // and its predecessor (successor). Boundaries have the same exponent as the
345
+ // value so only significands are stored.
346
+ struct boundaries {
347
+ uint64_t lower;
348
+ uint64_t upper;
349
+ };
350
+
343
351
// A handmade floating-point number f * pow(2, e).
344
352
class fp {
345
353
private:
@@ -417,29 +425,28 @@ class fp {
417
425
// where a boundary is a value half way between the number and its predecessor
418
426
// (lower) or successor (upper). The upper boundary is normalized and lower
419
427
// has the same exponent but may be not normalized.
420
- template <typename Double>
421
- void assign_with_boundaries (Double d, fp& lower, fp& upper) {
428
+ template <typename Double> boundaries assign_with_boundaries (Double d) {
422
429
bool is_lower_closer = assign (d);
423
- lower = is_lower_closer ? fp ((f << 2 ) - 1 , e - 2 ) : fp ((f << 1 ) - 1 , e - 1 );
430
+ fp lower =
431
+ is_lower_closer ? fp ((f << 2 ) - 1 , e - 2 ) : fp ((f << 1 ) - 1 , e - 1 );
424
432
// 1 in normalize accounts for the exponent shift above.
425
- upper = normalize<1 >(fp ((f << 1 ) + 1 , e - 1 ));
433
+ fp upper = normalize<1 >(fp ((f << 1 ) + 1 , e - 1 ));
426
434
lower.f <<= lower.e - upper.e ;
427
- lower.e = upper.e ;
435
+ return boundaries{ lower.f , upper.f } ;
428
436
}
429
437
430
- template <typename Double>
431
- void assign_float_with_boundaries (Double d, fp& lower, fp& upper) {
438
+ template <typename Double> boundaries assign_float_with_boundaries (Double d) {
432
439
assign (d);
433
440
constexpr int min_normal_e = std::numeric_limits<float >::min_exponent -
434
441
std::numeric_limits<double >::digits;
435
442
significand_type half_ulp = 1 << (std::numeric_limits<double >::digits -
436
443
std::numeric_limits<float >::digits - 1 );
437
444
if (min_normal_e > e) half_ulp <<= min_normal_e - e;
438
- upper = normalize<0 >(fp (f + half_ulp, e));
439
- lower = fp (
445
+ fp upper = normalize<0 >(fp (f + half_ulp, e));
446
+ fp lower = fp (
440
447
f - (half_ulp >> ((f == implicit_bit && e > min_normal_e) ? 1 : 0 )), e);
441
448
lower.f <<= lower.e - upper.e ;
442
- lower.e = upper.e ;
449
+ return boundaries{ lower.f , upper.f } ;
443
450
}
444
451
};
445
452
@@ -451,28 +458,28 @@ inline fp operator-(fp x, fp y) {
451
458
return {x.f - y.f , x.e };
452
459
}
453
460
454
- // Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
455
- // with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be
456
- // normalized.
457
- FMT_FUNC fp operator *(fp x, fp y) {
458
- int exp = x.e + y.e + 64 ;
461
+ inline uint64_t multiply (uint64_t lhs, uint64_t rhs) {
459
462
#if FMT_USE_INT128
460
- auto product = static_cast <__uint128_t >(x. f ) * y. f ;
463
+ auto product = static_cast <__uint128_t >(lhs ) * rhs ;
461
464
auto f = static_cast <uint64_t >(product >> 64 );
462
- if ((static_cast <uint64_t >(product) & (1ULL << 63 )) != 0 ) ++f;
463
- return {f, exp };
465
+ return (static_cast <uint64_t >(product) & (1ULL << 63 )) != 0 ? f + 1 : f;
464
466
#else
465
467
// Multiply 32-bit parts of significands.
466
468
uint64_t mask = (1ULL << 32 ) - 1 ;
467
- uint64_t a = x. f >> 32 , b = x. f & mask;
468
- uint64_t c = y. f >> 32 , d = y. f & mask;
469
+ uint64_t a = lhs >> 32 , b = lhs & mask;
470
+ uint64_t c = rhs >> 32 , d = rhs & mask;
469
471
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
470
472
// Compute mid 64-bit of result and round.
471
473
uint64_t mid = (bd >> 32 ) + (ad & mask) + (bc & mask) + (1U << 31 );
472
- return fp ( ac + (ad >> 32 ) + (bc >> 32 ) + (mid >> 32 ), exp );
474
+ return ac + (ad >> 32 ) + (bc >> 32 ) + (mid >> 32 );
473
475
#endif
474
476
}
475
477
478
+ // Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
479
+ // with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be
480
+ // normalized.
481
+ inline fp operator *(fp x, fp y) { return {multiply (x.f , y.f ), x.e + y.e + 64 }; }
482
+
476
483
// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its
477
484
// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`.
478
485
FMT_FUNC fp get_cached_power (int min_exponent, int & pow10_exponent) {
@@ -1062,8 +1069,7 @@ int format_float(T value, int precision, float_spec spec, buffer<char>& buf) {
1062
1069
int cached_exp10 = 0 ; // K in Grisu.
1063
1070
if (precision != -1 ) {
1064
1071
if (precision > 17 ) return snprintf_float (value, precision, spec, buf);
1065
- fp fp_value (value);
1066
- fp normalized = normalize (fp_value);
1072
+ fp normalized = normalize (fp (value));
1067
1073
const auto cached_pow = get_cached_power (
1068
1074
min_exp - (normalized.e + fp::significand_size), cached_exp10);
1069
1075
normalized = normalized * cached_pow;
@@ -1081,33 +1087,33 @@ int format_float(T value, int precision, float_spec spec, buffer<char>& buf) {
1081
1087
buf.resize (to_unsigned (num_digits));
1082
1088
} else {
1083
1089
fp fp_value;
1084
- fp lower, upper; // w^- and w^+ in the Grisu paper.
1085
- if (spec.binary32 )
1086
- fp_value.assign_float_with_boundaries (value, lower, upper);
1087
- else
1088
- fp_value.assign_with_boundaries (value, lower, upper);
1089
- // Find a cached power of 10 such that multiplying upper by it will bring
1090
+ auto boundaries = spec.binary32
1091
+ ? fp_value.assign_float_with_boundaries (value)
1092
+ : fp_value.assign_with_boundaries (value);
1093
+ fp_value = normalize (fp_value);
1094
+ // Find a cached power of 10 such that multiplying value by it will bring
1090
1095
// the exponent in the range [min_exp, -32].
1091
- const auto cached_pow = get_cached_power ( // \tilde{c}_{-k} in Grisu.
1092
- min_exp - (upper.e + fp::significand_size), cached_exp10);
1093
- fp normalized = normalize (fp_value);
1094
- normalized = normalized * cached_pow;
1095
- lower = lower * cached_pow; // \tilde{M}^- in Grisu.
1096
- upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
1097
- assert (min_exp <= upper.e && upper.e <= -32 );
1098
- auto result = digits::result ();
1099
- --lower.f ; // \tilde{M}^- - 1 ulp -> M^-_{\downarrow}.
1100
- ++upper.f ; // \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}.
1096
+ const fp cached_pow = get_cached_power (
1097
+ min_exp - (fp_value.e + fp::significand_size), cached_exp10);
1098
+ // Multiply value and boundaries by the cached power of 10.
1099
+ fp_value = fp_value * cached_pow;
1100
+ boundaries.lower = multiply (boundaries.lower , cached_pow.f );
1101
+ boundaries.upper = multiply (boundaries.upper , cached_pow.f );
1102
+ assert (min_exp <= fp_value.e && fp_value.e <= -32 );
1103
+ --boundaries.lower ; // \tilde{M}^- - 1 ulp -> M^-_{\downarrow}.
1104
+ ++boundaries.upper ; // \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}.
1101
1105
// Numbers outside of (lower, upper) definitely do not round to value.
1102
- grisu_shortest_handler handler{buf.data (), 0 , (upper - normalized).f };
1103
- result = grisu_gen_digits (upper, upper.f - lower.f , exp , handler);
1104
- int size = handler.size ;
1106
+ grisu_shortest_handler handler{buf.data (), 0 ,
1107
+ boundaries.upper - fp_value.f };
1108
+ auto result =
1109
+ grisu_gen_digits (fp (boundaries.upper , fp_value.e ),
1110
+ boundaries.upper - boundaries.lower , exp , handler);
1105
1111
if (result == digits::error) {
1106
- exp = exp + size - cached_exp10 - 1 ;
1112
+ exp += handler. size - cached_exp10 - 1 ;
1107
1113
fallback_format (value, buf, exp );
1108
1114
return exp ;
1109
1115
}
1110
- buf.resize (to_unsigned (size));
1116
+ buf.resize (to_unsigned (handler. size ));
1111
1117
}
1112
1118
return exp - cached_exp10;
1113
1119
}
0 commit comments