Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions stdlib/std.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -590,15 +590,17 @@ limitations under the License.
// Render floating point in decimal form
local render_float_dec(n__, zero_pad, blank, plus, ensure_pt, trailing, prec) =
local n_ = std.abs(n__);
local whole = std.floor(n_);
local is_integral = std.floor(n_) == n_;
// Represent the rounded number as an integer * 1/10**prec.
// Note that it can also be equal to 10**prec and we'll need to carry
// over to the wholes. We operate on the absolute numbers, so that we
// don't have trouble with the rounding direction.
local denominator = std.pow(10, prec);
local numerator = std.abs(n_) * denominator + 0.5;
local whole = std.sign(n_) * std.floor(numerator / denominator);
local frac = std.floor(numerator) % denominator;
// Integral values already have a zero fraction. Scaling them can lose
// whole digits, introduce a spurious remainder, or overflow.
local whole = if is_integral then n_ else std.sign(n_) * std.floor(numerator / denominator);
local frac = if is_integral then 0 else std.floor(numerator) % denominator;
local dot_size = if prec == 0 && !ensure_pt then 0 else 1;
local zp = zero_pad - prec - dot_size;
local str = render_int(n__ < 0, whole, zp, 0, blank, plus, 10, '');
Expand Down
9 changes: 9 additions & 0 deletions test_suite/format.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,15 @@ std.assertEqual(std.format('%10.5G', [1100]), ' 1100') &&
std.assertEqual(std.format('%10.5G', [110]), ' 110') &&
std.assertEqual(std.format('%10.5G', [1.1]), ' 1.1') &&

// Scaling integral floats by the precision must not invent fractional digits.
std.assertEqual(std.format('%f', 1e20), '100000000000000000000.000000') &&
std.assertEqual(std.format('%.3f', -1e20), '-100000000000000000000.000') &&
std.assertEqual(std.format('%+.0f', 1e20), '+100000000000000000000') &&
std.assertEqual(std.format('%#.0f', 1e20), '100000000000000000000.') &&
std.assertEqual(std.format('%.6f', 9007199254740991), '9007199254740991.000000') &&
std.assertEqual(std.format('%08.2f', 42), '00042.00') &&
std.assertEqual(std.format('%.2f', 1.999), '2.00') &&

// lots together, also test % operator
std.assertEqual('%s[%05d]-%2x%2x%2x%c' % ['foo', 3991, 17, 18, 17, 100], 'foo[03991]-111211d') &&

Expand Down