mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 20:19:19 +00:00
[ruby/json] Avoid scientific notation before exponent 15
Fix: https://github.com/ruby/json/issues/861 It's not incorrect to use scientific notation, but it tend to throw people off a bit, so it's best to keep it for very large numbers. https://github.com/ruby/json/commit/1566cd01a6
This commit is contained in:
parent
807faf5445
commit
dc406e9b5b
@ -1345,12 +1345,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
||||
}
|
||||
|
||||
/* This implementation writes directly into the buffer. We reserve
|
||||
* the 28 characters that fpconv_dtoa states as its maximum.
|
||||
* the 32 characters that fpconv_dtoa states as its maximum.
|
||||
*/
|
||||
fbuffer_inc_capa(buffer, 28);
|
||||
fbuffer_inc_capa(buffer, 32);
|
||||
char* d = buffer->ptr + buffer->len;
|
||||
int len = fpconv_dtoa(value, d);
|
||||
|
||||
/* fpconv_dtoa converts a float to its shortest string representation,
|
||||
* but it adds a ".0" if this is a plain integer.
|
||||
*/
|
||||
|
||||
23
ext/json/vendor/fpconv.c
vendored
23
ext/json/vendor/fpconv.c
vendored
@ -29,6 +29,10 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef JSON_DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#define npowers 87
|
||||
#define steppowers 8
|
||||
#define firstpower -348 /* 10 ^ -348 */
|
||||
@ -320,15 +324,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
|
||||
{
|
||||
int exp = absv(K + ndigits - 1);
|
||||
|
||||
int max_trailing_zeros = 7;
|
||||
|
||||
if(neg) {
|
||||
max_trailing_zeros -= 1;
|
||||
}
|
||||
|
||||
/* write plain integer */
|
||||
if(K >= 0 && (exp < (ndigits + max_trailing_zeros))) {
|
||||
|
||||
if(K >= 0 && exp < 15) {
|
||||
memcpy(dest, digits, ndigits);
|
||||
memset(dest + ndigits, '0', K);
|
||||
|
||||
@ -432,10 +428,12 @@ static int filter_special(double fp, char* dest)
|
||||
*
|
||||
* Input:
|
||||
* fp -> the double to convert, dest -> destination buffer.
|
||||
* The generated string will never be longer than 28 characters.
|
||||
* Make sure to pass a pointer to at least 28 bytes of memory.
|
||||
* The generated string will never be longer than 32 characters.
|
||||
* Make sure to pass a pointer to at least 32 bytes of memory.
|
||||
* The emitted string will not be null terminated.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Output:
|
||||
* The number of written characters.
|
||||
*
|
||||
@ -474,6 +472,9 @@ static int fpconv_dtoa(double d, char dest[28])
|
||||
int ndigits = grisu2(d, digits, &K);
|
||||
|
||||
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
|
||||
#ifdef JSON_DEBUG
|
||||
assert(str_len <= 32);
|
||||
#endif
|
||||
|
||||
return str_len;
|
||||
}
|
||||
|
||||
@ -825,26 +825,41 @@ class JSONGeneratorTest < Test::Unit::TestCase
|
||||
assert_equal object.object_id.to_json, JSON.generate(object, strict: true, as_json: :object_id)
|
||||
end
|
||||
|
||||
def assert_float_roundtrip(expected, actual)
|
||||
assert_equal(expected, JSON.generate(actual))
|
||||
assert_equal(actual, JSON.parse(JSON.generate(actual)), "JSON: #{JSON.generate(actual)}")
|
||||
end
|
||||
|
||||
def test_json_generate_float
|
||||
values = [-1.0, 1.0, 0.0, 12.2, 7.5 / 3.2, 12.0, 100.0, 1000.0]
|
||||
expecteds = ["-1.0", "1.0", "0.0", "12.2", "2.34375", "12.0", "100.0", "1000.0"]
|
||||
assert_float_roundtrip "-1.0", -1.0
|
||||
assert_float_roundtrip "1.0", 1.0
|
||||
assert_float_roundtrip "0.0", 0.0
|
||||
assert_float_roundtrip "12.2", 12.2
|
||||
assert_float_roundtrip "2.34375", 7.5 / 3.2
|
||||
assert_float_roundtrip "12.0", 12.0
|
||||
assert_float_roundtrip "100.0", 100.0
|
||||
assert_float_roundtrip "1000.0", 1000.0
|
||||
|
||||
if RUBY_ENGINE == "jruby"
|
||||
values << 1746861937.7842371
|
||||
expecteds << "1.7468619377842371E9"
|
||||
else
|
||||
values << 1746861937.7842371
|
||||
expecteds << "1746861937.7842371"
|
||||
end
|
||||
if RUBY_ENGINE == "jruby"
|
||||
assert_float_roundtrip "1.7468619377842371E9", 1746861937.7842371
|
||||
else
|
||||
assert_float_roundtrip "1746861937.7842371", 1746861937.7842371
|
||||
end
|
||||
|
||||
if RUBY_ENGINE == "ruby"
|
||||
values << -2.2471348024634545e-08 << -2.2471348024634545e-09 << -2.2471348024634545e-10
|
||||
expecteds << "-0.000000022471348024634545" << "-0.0000000022471348024634545" << "-2.2471348024634546e-10"
|
||||
end
|
||||
if RUBY_ENGINE == "ruby"
|
||||
assert_float_roundtrip "100000000000000.0", 100000000000000.0
|
||||
assert_float_roundtrip "1e+15", 1e+15
|
||||
assert_float_roundtrip "-100000000000000.0", -100000000000000.0
|
||||
assert_float_roundtrip "-1e+15", -1e+15
|
||||
assert_float_roundtrip "1111111111111111.1", 1111111111111111.1
|
||||
assert_float_roundtrip "1.1111111111111112e+16", 11111111111111111.1
|
||||
assert_float_roundtrip "-1111111111111111.1", -1111111111111111.1
|
||||
assert_float_roundtrip "-1.1111111111111112e+16", -11111111111111111.1
|
||||
|
||||
values.zip(expecteds).each do |value, expected|
|
||||
assert_equal expected, value.to_json
|
||||
end
|
||||
assert_float_roundtrip "-0.000000022471348024634545", -2.2471348024634545e-08
|
||||
assert_float_roundtrip "-0.0000000022471348024634545", -2.2471348024634545e-09
|
||||
assert_float_roundtrip "-2.2471348024634546e-10", -2.2471348024634545e-10
|
||||
end
|
||||
end
|
||||
|
||||
def test_numbers_of_various_sizes
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user