# Wrong numerical value while exporting to a JSON string

The following code:

ExportString[{"a" -> 2000000., "b" -> 0.000001}, "JSON"]


Gives the results

{"a" : 2.e60,
"b" : 1.e-6}


The first one is obviously having a wrong numerical value. Also, 1.e-6 is not parsable by python, but 1.0e-6 and 1e-6 works, so I guess it is not following the standard. The same problem also exists for Export[]. I need it to exchange data with other programs. What is the easiest way to fix this kind of problem?

-
This looks like bug introduced in version 9. Version 8 doesn't have this problem. Tagging as bug. You could report it to support@wolfram.com. –  Szabolcs Oct 31 '13 at 16:48
I expect you'd have to write your own JSON exporter to fix this. What is the most general kind of expression you need to export, to save effort and not implement what's not needed? –  Szabolcs Oct 31 '13 at 16:50
@Szabolcs All of them are numerical values in a tree structure. I am offloading the numerical work to other program. –  hwlau Oct 31 '13 at 21:13

The bug is in the SystemConvertJSONDumptoString[] function which is defined like this:

toString[num_?NumberQ, t_Integer] :=
If[Head[num] === Real && IntegerPart[num] == num,
ToString[CForm[N[num]]] ~~ "0", ToString[CForm[N[num]]]]


If my guess is correct, the purpose of the ~~ "0" part is to change 1. to 1.0. I am not very familiar with JSON, but I don't think this is really necessary (correct me if I'm wrong). So let's remove it like this:

First, use ExportString to export something (anything) to JSON. This'll trigger loading the conversion functions. Next, just evaluate this to overwrite the definition:

SystemConvertJSONDumptoString[num_?NumberQ, t_Integer] :=
If[Head[num] === Real && IntegerPart[num] == num,
ToString[CForm[N[num]]], ToString[CForm[N[num]]]]


Actually you might simplify it to:

SystemConvertJSONDumptoString[num_?NumberQ, t_Integer] := ToString[CForm[N[num]]]


Now it works fine:

ExportString[{"a" -> 2000000.}, "JSON"]

(* "{\"a\" : 2.e6}" *)


Please verify that this is correct JSON. As I said, I am not very familiar with the format.

-
I think it is not standard as the expression cannot be parsed by the both javascript, python and C++ propertytree. There should be no single dot at the end of numerical value. Also, it seems that they are trying to fix this by the extra zero at the end, but instead introducing an even bigger bug here. Do you know how to replace the "number dot" ("2.") by a simple "number" ("2"), I think it could fix this problem. –  hwlau Oct 31 '13 at 21:22
@hwlau you'll need to write a little function that formats numbers correctly for JSON and use it as I describe above. Unfortunately I don't have time for this now, but this shouldn't be difficult, just time consuming. –  Szabolcs Oct 31 '13 at 22:45
Thank you very much, I get the answer already. –  hwlau Oct 31 '13 at 23:24

See Szabolcs answer for the explanation. The number form there needs to be corrected because JSON needs a digit between . and e:

Therefore, here the solution:

SystemConvertJSONDumptoString[num_?NumberQ, t_Integer] :=
StringReplace[ToString[CForm[N[num]]], RegularExpression["\\.(($)|(e))"] -> ".0$1"];


For the following input:

ExportString[{"a" -> 2000000., "b" -> 0.0000012, "c" -> 30000.}, "JSON"]


Now, it gives the correct output for all the JSON parser:

{"a" : 2.0e6, "b" : 1.2e-6, "c" : 30000.0}

-

Perhaps this might work to add the zeros after the decimal point:

SystemConvertJSONDumptoString[num_?NumberQ,t_Integer]:=
StringReplace[
StringReplace[
ToString[CForm[N[num]]],
RegularExpression["\\.&"]->".0"
],
".e"->".0e"
]
`

I cannot check, but this seems to comply with the format descriptions provided by hwlau.

-
+1, but the end of line matching character is "\$", not "&" –  hwlau Oct 31 '13 at 23:22
@hwlau You are right! I am sorry. –  user8074 Oct 31 '13 at 23:27