Recent

Author Topic: [SOLVED] fpjson - float numbers formatting  (Read 933 times)

artem101

  • Jr. Member
  • **
  • Posts: 84
[SOLVED] fpjson - float numbers formatting
« on: October 06, 2022, 01:01:11 pm »
Hello!

My program generates and writes data to JSON file. I use FormatJSON() method to make output more readable. I'm not quite satisfied how numbers with float point looks:
Code: [Select]
"coordinates" : [
      3.7195156336091998E+001,
      5.5978631048365003E+001,
      2.2100000000000000E+002
]

I'm know that it is scientific notation, but I want to see normal form:
Code: [Select]
"coordinates" : [
      37.195156336091998,
      55.978631048365003,
      221.0
]

I'm not found suitable parameter in TFormatOption. How to do this?

Thanks.
« Last Edit: October 06, 2022, 07:56:30 pm by artem101 »

alpine

  • Hero Member
  • *****
  • Posts: 1062
Re: fpjson - float numbers formatting
« Reply #1 on: October 06, 2022, 01:34:59 pm »
If you want for example just 4 digits of precision:
Code: Pascal  [Select][+][-]
  1. uses
  2.   fpjson;
  3.  
  4. type
  5.   TJSONFloat4Number = class(TJSONFloatNumber)
  6.   protected
  7.     function GetAsString: TJSONStringType; override;
  8.   end;
  9.  
  10. function TJSONFloat4Number.GetAsString: TJSONStringType;
  11. var
  12.   F: TJSONFloat;
  13. begin
  14.   F := GetAsFloat;
  15.   Str(F:0:4, Result); // format with your preferences
  16. end;

Later:
Code: Pascal  [Select][+][-]
  1.   ...
  2.   SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
  3.   S := JsonData.AsJSON;
  4.  

I'm afraid that SetJSONInstanceType works globally.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

AlexTP

  • Hero Member
  • *****
  • Posts: 2401
    • UVviewsoft
Re: fpjson - float numbers formatting
« Reply #2 on: October 06, 2022, 01:40:13 pm »
« Last Edit: October 06, 2022, 03:41:06 pm by AlexTP »

avk

  • Hero Member
  • *****
  • Posts: 752
Re: fpjson - float numbers formatting
« Reply #3 on: October 06, 2022, 03:53:46 pm »
If you want for example just 4 digits of precision:
...
I guess that's not what the OP is asking for.
Probably some kind of subclassing is required to solve this problem within FpJson.
And I'm not sure if all conversions will result in what the OP indicated.

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: fpjson - float numbers formatting
« Reply #4 on: October 06, 2022, 04:13:31 pm »
I guess that's not what the OP is asking for.
Why not. It's just that Str() needs the exact decimal point and will pad with zeros.
So it should be FloatToStr() instead.

For OP it's actually this:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   fpjson,
  5.   jsonparser,
  6.   SysUtils;
  7.  
  8. type
  9.   TJSONFloat4Number = class(TJSONFloatNumber)
  10.   protected
  11.     function GetAsString: TJSONStringType; override;
  12.   end;
  13.  
  14.   function TJSONFloat4Number.GetAsString: TJSONStringType;
  15.   var
  16.     F: TJSONFloat;
  17.   begin
  18.     F := GetAsFloat;
  19.     // Str(F:0:4, Result); // format with your preferences
  20.     Result := FloatToStr(F); // format with your preferences
  21.   end;
  22.  
  23.   procedure JSONTest;
  24.   var
  25.     jData: TJSONData;
  26.     jObject: TJSONObject;
  27.   begin
  28.     jData := GetJSON('{"String" : "Test"}');
  29.     try
  30.       jObject := jData as TJSONObject;
  31.       jObject.Floats['Number1'] := 100/3;
  32.       jObject.Floats['Number2'] := 100.1;
  33.       writeln(jData.AsJSON);
  34.     finally
  35.       jData.Free;
  36.     end;
  37.   end;
  38.  
  39. begin
  40.   SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
  41.   JSONTest;
  42.   Readln;
  43. end.
Result:
Quote
{ "String" : "Test", "Number1" : 33,3333333333333, "Number2" : 100,1 }

Without the modification it would be
Quote
{ "String" : "Test", "Number1" : 3.3333333333333336E+001, "Number2" : 1.0009999999999999E+002 }
« Last Edit: October 06, 2022, 04:23:45 pm by rvk »

AlexTP

  • Hero Member
  • *****
  • Posts: 2401
    • UVviewsoft
Re: fpjson - float numbers formatting
« Reply #5 on: October 06, 2022, 04:20:48 pm »
@rvk,
Can you fix the mem-leak in JSONTest?

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: fpjson - float numbers formatting
« Reply #6 on: October 06, 2022, 04:24:14 pm »
@rvk,
Can you fix the mem-leak in JSONTest?
Woops, forgot to run it with heaptrc on  :-[
Fixed now.

AlexTP

  • Hero Member
  • *****
  • Posts: 2401
    • UVviewsoft
Re: fpjson - float numbers formatting
« Reply #7 on: October 06, 2022, 04:28:14 pm »

avk

  • Hero Member
  • *****
  • Posts: 752
Re: fpjson - float numbers formatting
« Reply #8 on: October 06, 2022, 04:45:49 pm »
Why not ...

Initial data of the OP:
Code: Text  [Select][+][-]
  1. "coordinates" : [
  2.       3.7195156336091998E+001,
  3.       5.5978631048365003E+001,
  4.       2.2100000000000000E+002
  5. ]
  6.  

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   fpjson,
  5.   jsonparser,
  6.   SysUtils;
  7.  
  8. type
  9.   TJSONFloat4Number = class(TJSONFloatNumber)
  10.   protected
  11.     function GetAsString: TJSONStringType; override;
  12.   end;
  13.  
  14. function TJSONFloat4Number.GetAsString: TJSONStringType;
  15. var
  16.   F: TJSONFloat;
  17. begin
  18.   F := GetAsFloat;
  19.   Result := FloatToStr(F);
  20. end;
  21.  
  22. procedure JSONTest;
  23. var
  24.   jData: TJSONData;
  25. begin
  26.   jData := GetJSON('{"coordinates":[3.7195156336091998E+001,5.5978631048365003E+001,2.2100000000000000E+002]}');
  27.   writeln(jData.FormatJSON);
  28. end;
  29.  
  30. begin
  31.   SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
  32.   JSONTest;
  33.   Readln;
  34. end.
  35.  

The problem is that(AFAIK) FloatToStr(Double) returns at most 15 significant digits.
Result:
Code: Text  [Select][+][-]
  1. {
  2.   "coordinates" : [
  3.     37,195156336092,
  4.     55,978631048365,
  5.     221
  6.   ]
  7. }
  8.  

But the OP asked
Code: Text  [Select][+][-]
  1. "coordinates" : [
  2.       37.195156336091998,
  3.       55.978631048365003,
  4.       221.0
  5. ]
  6.  

abouchez

  • Full Member
  • ***
  • Posts: 111
    • Synopse
Re: fpjson - float numbers formatting
« Reply #9 on: October 06, 2022, 04:57:20 pm »
Yes, FloatToStr() is not correct: it uses the current RTL separator, which is locale, and here ','.
And this is no valid JSON, which requires '.'.

Just using str(doublevalue:0:15) for instance.

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: fpjson - float numbers formatting
« Reply #10 on: October 06, 2022, 05:00:29 pm »
Why not ...
But the OP asked
Code: Text  [Select][+][-]
  1. "coordinates" : [
  2.       37.195156336091998,
  3.       55.978631048365003,
  4.       221.0
  5. ]
  6.  
Ok. Like this?

Result:
Quote
{
  "coordinates" : [
    37,195156336091998,
    55,978631048365003,
    221,0
  ]
}

You do note the " // format with your preferences" so OP can change it to their own preferences.
(At least there is no subclassing required)

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   fpjson,
  5.   jsonparser,
  6.   SysUtils;
  7.  
  8. type
  9.   TJSONFloat4Number = class(TJSONFloatNumber)
  10.   protected
  11.     function GetAsString: TJSONStringType; override;
  12.   end;
  13.  
  14. function TJSONFloat4Number.GetAsString: TJSONStringType;
  15. var
  16.   F: TJSONFloat;
  17. begin
  18.   F := GetAsFloat;
  19.   Result := FormatFloat('0.0###############', F); // format with your preferences
  20. end;
  21.  
  22. procedure JSONTest;
  23. var
  24.   jData: TJSONData;
  25. begin
  26.   jData := GetJSON('{"coordinates":[3.7195156336091998E+001,5.5978631048365003E+001,2.2100000000000000E+002]}');
  27.   writeln(jData.FormatJSON);
  28.   jData.Free;
  29. end;
  30.  
  31. begin
  32.   SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
  33.   JSONTest;
  34.   Readln;
  35. end.

« Last Edit: October 06, 2022, 05:03:04 pm by rvk »

avk

  • Hero Member
  • *****
  • Posts: 752
Re: fpjson - float numbers formatting
« Reply #11 on: October 06, 2022, 05:36:43 pm »
@rvk, thanks.
This seems to be the answer for the OP.

wp

  • Hero Member
  • *****
  • Posts: 11915
Re: fpjson - float numbers formatting
« Reply #12 on: October 06, 2022, 06:29:45 pm »
Code: Pascal  [Select][+][-]
  1. function TJSONFloat4Number.GetAsString: TJSONStringType;
  2. var
  3.   F: TJSONFloat;
  4. begin
  5.   F := GetAsFloat;
  6.   Result := FormatFloat('0.0###############', F); // format with your preferences
  7. end;
FormatFloat() will not necessarily use a decimal point as separator. You must use an adapted copy of the FormatSetting here:
Code: Pascal  [Select][+][-]
  1. function TJSONFloat4Number.GetAsString: TJSONStringType;
  2. var
  3.   F: TJSONFloat;
  4.   fs: TFormatSettings;
  5. begin
  6.   fs := DefaultFormatSettings;
  7.   fs.DecimalSeparator := '.';
  8.   F := GetAsFloat;
  9.   Result := FormatFloat('0.0###############', F, fs); // format with your preferences
  10. end;

artem101

  • Jr. Member
  • **
  • Posts: 84
Re: fpjson - float numbers formatting
« Reply #13 on: October 06, 2022, 06:31:13 pm »
If you want for example just 4 digits of precision:
Code: Pascal  [Select][+][-]
  1. uses
  2.   fpjson;
  3.  
  4. type
  5.   TJSONFloat4Number = class(TJSONFloatNumber)
  6.   protected
  7.     function GetAsString: TJSONStringType; override;
  8.   end;
  9.  
  10. function TJSONFloat4Number.GetAsString: TJSONStringType;
  11. var
  12.   F: TJSONFloat;
  13. begin
  14.   F := GetAsFloat;
  15.   Str(F:0:4, Result); // format with your preferences
  16. end;

Later:
Code: Pascal  [Select][+][-]
  1.   ...
  2.   SetJSONInstanceType(jitNumberFloat, TJSONFloat4Number);
  3.   S := JsonData.AsJSON;
  4.  

I'm afraid that SetJSONInstanceType works globally.

Thanks, that is what I need.

Yes, FloatToStr() is not correct: it uses the current RTL separator, which is locale, and here ','.
And this is no valid JSON, which requires '.'.

Just using str(doublevalue:0:15) for instance.
I use this:
Code: Pascal  [Select][+][-]
  1.   Fmt.DecimalSeparator := '.';
  2.   Result := FloatToStr(F, Fmt);

 

TinyPortal © 2005-2018