-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support single precision floats in grisu formatting #1361
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -423,6 +423,18 @@ class fp { | |
lower.f <<= lower.e - upper.e; | ||
lower.e = upper.e; | ||
} | ||
|
||
void compute_float_boundaries(fp& lower, fp& upper) const { | ||
constexpr int min_normal_e = std::numeric_limits<float>::min_exponent - | ||
std::numeric_limits<double>::digits; | ||
significand_type half_ulp = 1 << (std::numeric_limits<double>::digits - | ||
std::numeric_limits<float>::digits - 1); | ||
if (min_normal_e > e) half_ulp <<= min_normal_e - e; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the float is normal, |
||
upper = normalize<0>(fp(f + half_ulp, e)); | ||
lower = fp(f - (half_ulp >> (f == implicit_bit && e > min_normal_e)), e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The condition is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Great catch! It's definitely a bug which fortunately doesn't affect the output. Will be fixed in eb879a6. |
||
lower.f <<= lower.e - upper.e; | ||
lower.e = upper.e; | ||
} | ||
}; | ||
|
||
// Returns an fp number representing x - y. Result may not be normalized. | ||
|
@@ -1045,7 +1057,11 @@ bool grisu_format(Double value, buffer<char>& buf, int precision, | |
buf.resize(to_unsigned(handler.size)); | ||
} else { | ||
fp lower, upper; // w^- and w^+ in the Grisu paper. | ||
fp_value.compute_boundaries(lower, upper); | ||
if ((options & grisu_options::binary32) != 0) | ||
fp_value.compute_float_boundaries(lower, upper); | ||
else | ||
fp_value.compute_boundaries(lower, upper); | ||
|
||
// Find a cached power of 10 such that multiplying upper by it will bring | ||
// the exponent in the range [min_exp, -32]. | ||
const auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The smallest positive normal float is
2^-126
.fp(2^-126)
isfp(2^52, -178)
. float min_exponent is -125, double digits is 53: both of these numbers are off by one from what we need, but these 1s cancel each other out.