#1 2019-03-28 18:04:50

tbo
Member
Registered: 2015-04-20
Posts: 353

Trouble with JSON and Double

Hello,

I'm in trouble with JSON and Double.

Win10 German, Delphi XE, mORMot: 1.18.4299

var
  v: Variant;
  vo: TDocVariantOptions;
begin
  vo := [dvoReturnNullForUnknownProperty, dvoAllowDoubleValue];
  v := VariantLoadJSON('{"TestDouble":"16.2"}', @vo, True);
  ShowMessage(FloatToStr(v.TestDouble)); 

For the following inputs:
- {"TestDouble":16.2}  => Everything Ok, the value is Double
- {"TestDouble":"16,2"}  => Everything Ok, the value is Double
- {"TestDouble":"16.2"}  => This is where trouble starts. The result is 162

The problem is the double quoted Double value with DecimalSeparator '.'.
The existing JSON is formatted as described under point 3. I have no influence on it. 

How can I solve this problem?

With best regards

Offline

#2 2019-03-29 01:38:37

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,671
Website

Re: Trouble with JSON and Double

There are hidden conversion when you call FloatToStr(v.TestDouble).
v.TestDouble returns a variant of kind tkVariant pointing to the value inside v, for performance, and the compiler is lost.
This is a Delphi bug/limitation.

For correct process, you need to make an explicit conversion:

  v: Variant;
  vo: TDocVariantOptions;
  vd: double;
begin
  vo := [dvoReturnNullForUnknownProperty, dvoAllowDoubleValue];
  v := VariantLoadJSON('{"TestDouble":"16.2"}', @vo, True);
  vd := v.testdouble;
  ShowMessage(FloatToStr(vd));

IMHO the best is to use directly a TDocVariantData, then its GetAsDouble() method, or the D[] property.

BTW dvoAllowDoubleValue and the True parameter are redundant.

Offline

#3 2019-03-29 10:25:07

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: Trouble with JSON and Double

Hello,

thank you very much for the quick answer. But she doesn't solve my problem.
If I test it with your suggestion, the result will be wrong (Result = 162).

In my program I use TDocVariantData with the D[] property. When the double
values were empty after reading the JSON file, I searched for the error. I have
read the help again and the test functions in the source code. But whatever
combination I tried, the double quoted Double values from the JSON file
were wrong. After that, I did this little test scenario.

If I test this combination with your suggestion on my computer:
- {"TestDouble":"16.2E-2"}  => Wrong: Result 1,62
- {"TestDouble":"16,2E-2"}  => Ok: Result 0,162

I also tested it with Win 7 German and Delphi 2007. Same problems.
I think it's a problem with the decimal separator. The decimal separator on
my Windows system is '',''. But that's just my guess.

Thank you very much for your help.

With best regards

Last edited by tbo (2019-03-29 10:37:58)

Offline

#4 2019-03-29 12:48:12

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,571
Website

Re: Trouble with JSON and Double

In fact in your JSON {"TestDouble":"16.2"} TestDouble attribute is STRING, so the most correct way is to get it from JSON as string and transform to double using StrToFloat with FormatSettings. But you can try to force DecimalSeparatot := '.' if you app is single-thread

Offline

#5 2019-03-29 13:35:45

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,671
Website

Re: Trouble with JSON and Double

As mpv wrote, TestDouble is a string, so your problem has nothing to do with mORMot, I am afraid...
This is how variants and FloatToStr() works with Delphi.

mORMot never uses the system decimal separator, and only uses '.' as with JSON.
You encounter the "16.2E-2" problem because it is how Delphi converts string to floats...

Offline

#6 2019-03-29 14:14:48

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: Trouble with JSON and Double

Hello,

@mvp, thanks for your answer.
What you are recommending is what I am currently doing as a workaround.
But I think there's a bug after all. Otherwise I can explain the results in
my last example.

@ab, when I look at this test:
- {"TestDouble":"16.2E-2"}  => Wrong: Result 1,62

For me, the input value is parsed to 162 and then converted to a float value.
The decimal separator is simply ignored (is not taken into account). Otherwise
I cannot explain the result. If I test with {"TestDouble":"16,2E-2"} everything
is fine.

I don't know the JSON specification. But I can't imagine that specific country
settings should have an impact on the result. And there should be no difference
if a value is double quoted. Because without double quotes {"TestDouble":16.2E-2},
it works right. Maybe I'm just making a thinking mistake.
I hope I'm not too persistent with my questions.

With best regards

Last edited by tbo (2019-03-29 14:19:52)

Offline

#7 2019-03-29 18:52:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,671
Website

Re: Trouble with JSON and Double

You are missing an important point.
Your code calls FloatToStr(v.TestDouble).

For v.testdouble, the framework returns a variant containing the '16.2E-2' string.
This is as per the JSON specification.

Then, Delphi - not the framework - makes an hidden conversion from variant to float, since FloatToStr() expect a float as input parameter.
This is this hidden conversion which doesn't what you expect.
This conversion is done in the Delphi RTL - Variant.pas unit IIRC.

So you need to make the conversion explicit, e.g. using: FloatToStr(VariantToDoubleDef(v.testdouble)).

Offline

Board footer

Powered by FluxBB