Skip to content

Commit 193df55

Browse files
ydahbyroot
authored andcommitted
Preserve float precision in RFC 8785 number formatting
1 parent 37a48ef commit 193df55

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

‎lib/json/ext.rb‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ def shareable_lambda(block) # :nodoc:
6666
if num < 0
6767
num, sign = -num, '-'
6868
end
69-
native_rep = "%.15E" % num
70-
decimal, exponential = native_rep.split('E')
69+
native_rep = num.to_s
70+
decimal, exponential = native_rep.split('e')
7171
exp_val = exponential.to_i
7272
exponential = exp_val > 0 ? ('+' + exp_val.to_s) : exp_val.to_s
7373

‎test/json/json_generator_test.rb‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,48 @@ def test_rfc8785_numbers
12661266
assert_rfc8785 '999999999999999700000', 999999999999999700000
12671267
assert_rfc8785 '999999999999999900000', 999999999999999900000
12681268
assert_rfc8785 '333333333.3333333', 333333333.33333329
1269+
assert_rfc8785 '0.30000000000000004', 0.1 + 0.2
1270+
end
1271+
1272+
# https://www.rfc-editor.org/rfc/rfc8785.html#appendix-B
1273+
{
1274+
'0000000000000000' => '0',
1275+
'8000000000000000' => '0',
1276+
'0000000000000001' => '5e-324',
1277+
'8000000000000001' => '-5e-324',
1278+
'7fefffffffffffff' => '1.7976931348623157e+308',
1279+
'ffefffffffffffff' => '-1.7976931348623157e+308',
1280+
'4340000000000000' => '9007199254740992',
1281+
'c340000000000000' => '-9007199254740992',
1282+
'4430000000000000' => '295147905179352830000',
1283+
'7fffffffffffffff' => nil,
1284+
'7ff0000000000000' => nil,
1285+
'44b52d02c7e14af5' => '9.999999999999997e+22',
1286+
'44b52d02c7e14af6' => '1e+23',
1287+
'44b52d02c7e14af7' => '1.0000000000000001e+23',
1288+
'444b1ae4d6e2ef4e' => '999999999999999700000',
1289+
'444b1ae4d6e2ef4f' => '999999999999999900000',
1290+
'444b1ae4d6e2ef50' => '1e+21',
1291+
'3eb0c6f7a0b5ed8c' => '9.999999999999997e-7',
1292+
'3eb0c6f7a0b5ed8d' => '0.000001',
1293+
'41b3de4355555553' => '333333333.3333332',
1294+
'41b3de4355555554' => '333333333.33333325',
1295+
'41b3de4355555555' => '333333333.3333333',
1296+
'41b3de4355555556' => '333333333.3333334',
1297+
'41b3de4355555557' => '333333333.33333343',
1298+
'becbf647612f3696' => '-0.0000033333333333333333',
1299+
'43143ff3c1cb0959' => '1424953923781206.2',
1300+
}.each do |bits, expected|
1301+
define_method("test_rfc8785_number_#{bits}") do
1302+
omit "Float#to_s is not always shortest on this engine" unless RUBY_ENGINE == "ruby"
1303+
number = [bits].pack('H*').unpack('G').first
1304+
if expected
1305+
assert_rfc8785 expected, number
1306+
assert_equal number, JSON.parse(JSON.generate(number, rfc8785: true)).to_f
1307+
else
1308+
assert_raise(JSON::GeneratorError) { JSON.generate(number, rfc8785: true) }
1309+
end
1310+
end
12691311
end
12701312

12711313
fixtures_path = File.expand_path('../fixtures/rfc8785/', __FILE__)

0 commit comments

Comments
 (0)