diff --git a/README.md b/README.md index 36fc870..efb5300 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Errors are raised as exceptions. 2> Doc = {[{foo, [<<"bing">>, 2.3, true]}]}. {[{foo,[<<"bing">>,2.3,true]}]} 3> jiffy:encode(Doc). - <<"{\"foo\":[\"bing\",2.2999999999999998224,true]}">> + <<"{\"foo\":[\"bing\",2.3,true]}">> Data Format diff --git a/c_src/encoder.c b/c_src/encoder.c index 640aa68..a64c66d 100644 --- a/c_src/encoder.c +++ b/c_src/encoder.c @@ -4,12 +4,15 @@ #include #include #include +#include #include "erl_nif.h" #include "jiffy.h" #define BIN_INC_SIZE 2048 +#define FLOAT_BUFLEN (LDBL_DIG*2) + #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #define MAYBE_PRETTY(e) \ @@ -393,13 +396,18 @@ enc_double(Encoder* e, double val) size_t len; size_t i; - if(!enc_ensure(e, 32)) { + if(!enc_ensure(e, FLOAT_BUFLEN)) { return 0; } start = &(e->p[e->i]); - sprintf(start, "%0.20g", val); + // try to encode doubles using the fewest digits possible... + if (snprintf(start, FLOAT_BUFLEN, "%.*g", DBL_DIG, val) > FLT_DIG) + { + // ...fall back to full expansion to be safe + snprintf(start, FLOAT_BUFLEN, "%.*g", LDBL_DIG, val); + } len = strlen(start); // Check if we have a decimal point @@ -408,7 +416,7 @@ enc_double(Encoder* e, double val) goto done; } - if(len > 29) return 0; + if(len >= FLOAT_BUFLEN-2) return 0; // Force a decimal point start[len++] = '.'; diff --git a/test/003-numbers.t b/test/003-numbers.t index f580faf..916b43e 100755 --- a/test/003-numbers.t +++ b/test/003-numbers.t @@ -21,30 +21,25 @@ good() -> {<<"1234567890123456789012345">>, 1234567890123456789012345}, {<<"1310050760199">>, 1310050760199}, { - <<"1234567890123456789012345.0">>, - 1.23456789012345678e24, - <<"1.2345678901234568245e+24">> + 1.23456789012345678e24 }, { - <<"1234567890123456789012345.0E3">>, - 1.2345678901234569e27, - <<"1.2345678901234568502e+27">> + 1.2345678901234569e27 }, { <<"1234567890123456789012345012">>, - 1234567890123456789012345012, - <<"1234567890123456789012345012">> + 1234567890123456789012345012 }, {<<"1.0">>, 1.0}, { <<"0.000000000000000000000000000000000001">>, 1.0E-36, - <<"9.9999999999999994104e-37">> + <<"1e-36">> }, {<<"0.75">>, 0.75}, - {<<"2.0123456789">>, 2.0123456789, <<"2.0123456789000000455">>}, - {<<"2.4234324E24">>, 2.4234324E24, <<"2.4234323999999998107e+24">>}, - {<<"-3.1416">>, -3.1416, <<"-3.1415999999999999481">>}, + {2.0123456789}, + {2.4234324E24}, + {-3.1416}, {<<"1E4">>, 10000.0, <<"10000.0">>}, {<<"1.0E+01">>, 10.0, <<"10.0">>}, {<<"1e1">>, 10.0, <<"10.0">>}, diff --git a/test/util.erl b/test/util.erl index ceaef89..8c07762 100644 --- a/test/util.erl +++ b/test/util.erl @@ -22,6 +22,8 @@ do_encode(E, Options) -> error_mesg(J) -> lists:flatten(io_lib:format("Decoding ~p returns an error.", [J])). +check_good({E}, Options) -> + check_good({jiffy:encode(E), E}, Options); check_good({J, E}, Options) -> etap:is(jiffy:decode(J), E, ok_dec(J, E)), etap:is(do_encode(E, Options), J, ok_enc(E, J));