Recent

Author Topic: Issue with FormatFloat  (Read 12332 times)

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Issue with FormatFloat
« Reply #15 on: October 22, 2016, 09:15:49 pm »
No, this "problem" appear too when the number is higher than 10000, see the topic starter example:

Yikes, that sure looks like a bug:

 WriteLn(FormatFloat('####,##0.00', 10000));     // 10000.00
 WriteLn(FormatFloat('##,##0.00', 10000));     // 10,000.00
 
For now, I would definitely not use this function.

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: Issue with FormatFloat
« Reply #16 on: October 22, 2016, 09:22:58 pm »

totya

  • Hero Member
  • *****
  • Posts: 720
Re: Issue with FormatFloat
« Reply #17 on: October 22, 2016, 09:49:08 pm »
Finally, I just repeat myself, in my opinion this isn't a bug.

Because see this:

Code: Pascal  [Select][+][-]
  1. FormatFloat(',0.00', 10000)

This is the perfect code. "," say: the number must appear with thousand operator.

"#" is absolutly unnecessary here. For example
Code: Pascal  [Select][+][-]
  1. FormatFloat('#######,0.00', 10000);
what is it say?
Show the numbers, like as #######, and where is the thousand operator? What is the priority in this case?


wp

  • Hero Member
  • *****
  • Posts: 11916
Re: Issue with FormatFloat
« Reply #18 on: October 22, 2016, 10:00:53 pm »
In my eyes the # in front of the decimal separator are only fillers which always should be neglected, with the only exception that the # is right before the decimal separator to get an American-style formatting of numbers < 1 where the 0 is suppressed:

FormatFloat('#.00', 0.512) = '.51'

Also the count of thousand separators should not be important. A different behavior looks like a bug because it is very surprising to the user.

(BTW, this kind of formatting cannot be achieved by Format(), because even Format('%.2f', [0.512]) shows the leading zero.)


sfeinst

  • Full Member
  • ***
  • Posts: 230
Re: Issue with FormatFloat
« Reply #19 on: October 23, 2016, 04:07:50 am »
What adds to the confusion is the help implies # can and should be used before the decimal point.  The help at:
http://www.freepascal.org/docs-html/rtl/sysutils/formatfloat.html

has examples using:
#,##0.00

and if I use that, it works.  It is only when I have more than one # before the thousand separator that I run into an issue. 

My mistake was thinking that I needed the number of # in front for the widest possible value or it might get truncated - just like after the decimal point (though after is rounding not truncating).  The help was not clear in this regard.

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Issue with FormatFloat
« Reply #20 on: October 23, 2016, 06:11:42 am »
The help was not clear in this regard.

In general, I'm not very enthusiastic about functions where you have pass in "special" characters. That includes FormatFloat and Format. You will always need carefully-written documentation to use these functions correctly. Looking at the function source may not help either if there are subtle things to be aware of as is the case with FormatFloat. Not very much in the spirit of readable Pascal.

It's possible this function is only there for Delphi compatibility. If so, it might be worthwhile just to point that out and recommend something else if possible, such as FloatToStrF, which does not expect special codes as part of its parameters.

Thaddy

  • Hero Member
  • *****
  • Posts: 14373
  • Sensorship about opinions does not belong here.
Re: Issue with FormatFloat
« Reply #21 on: October 23, 2016, 10:09:10 am »
In general, I'm not very enthusiastic about functions where you have pass in "special" characters.
That's why you can usually escape those. Nothing wrong with it as long as they can be escaped.
There is not a real way you can program your way out of that.... Live with it .. :'( O:-)

As an aside: one could have used writestr and test that against the problem.
The separation in formatting and data is way more clear - likely as you refer to, want - but less flexible.
« Last Edit: October 23, 2016, 10:11:55 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

totya

  • Hero Member
  • *****
  • Posts: 720
Re: Issue with FormatFloat
« Reply #22 on: October 23, 2016, 02:06:35 pm »
...and if I use that, it works.  It is only when I have more than one # before the thousand separator that I run into an issue. 

Your problem is solved in reply #2 from me long time ago, then what is your problem again and again? I wrote many times, "#" sign is unnecessarry and pointless before "," thats all, simple do not use it. :-) Do you want generate endless flame?

Okay, I wrote a function for you, name is: PointlessUserErrorCorrection, see this sample:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, LazUTF8;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Memo1: TMemo;
  16.     procedure FormCreate(Sender: TObject);
  17.   private
  18.     function PointlessUserErrorCorrection (FormatString: string): string;
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. { TForm1 }
  29.  
  30. function TForm1.PointlessUserErrorCorrection (FormatString: string): string;
  31. const
  32.   c_ThousandSeparator = ',';
  33.   c_DigitPlaceHolder = '#';
  34.  
  35.   function GetThousandSeparatorPosition : word;
  36.   begin
  37.     Result:= UTF8pos(c_ThousandSeparator, FormatString);
  38.   end;
  39.  
  40. begin
  41.   if GetThousandSeparatorPosition > 0 then
  42.   begin
  43.     while GetThousandSeparatorPosition > 0 do
  44.       UTF8Delete(FormatString, 1, GetThousandSeparatorPosition);
  45.  
  46.     while UTF8Copy(FormatString, 1, 1) = c_DigitPlaceHolder do
  47.       UTF8Delete(FormatString, 1, 1);
  48.  
  49.     UTF8Insert(c_ThousandSeparator, FormatString, 1);
  50.   end;
  51.  
  52.   Result:= FormatString;
  53. end;
  54.  
  55. procedure TForm1.FormCreate(Sender: TObject);
  56.   function WriteFormatFloat
  57.              (const FormatString: string;
  58.               const Number: real): string;
  59.   var
  60.     fs: TFormatSettings;
  61.   begin
  62.     fs.DecimalSeparator := '.';
  63.     fs.ThousandSeparator := ',';
  64.  
  65.     Result:=
  66.       FormatFloat(FormatString, Number, fs)+
  67.       ' ('+FormatString+') '+
  68.       'PointlessUserErrorCorrection OFF'+LineEnding;
  69.  
  70.     Result:=
  71.       Result+
  72.         FormatFloat(PointlessUserErrorCorrection(FormatString), Number, fs)+
  73.         ' ('+PointlessUserErrorCorrection(FormatString)+') '+
  74.         'PointlessUserErrorCorrection ON'+ LineEnding;
  75.  
  76.     Result:=
  77.       Result+ LineEnding;
  78.   end;
  79.  
  80. var
  81.   Temp: string;
  82.  
  83. begin
  84.   Memo1.Lines.Clear;
  85.   Memo1.ScrollBars:=ssBoth;
  86.  
  87.   Temp := '';
  88.  
  89.   Temp := Temp + WriteFormatFloat('###,##0.00', 1000);
  90.   Temp := Temp + WriteFormatFloat('###,##0.00', 10000);
  91.   Temp := Temp + WriteFormatFloat('###,##0.00', 10000000 / 1024);
  92.   Temp := Temp + WriteFormatFloat('###,##0.00', 10000000000 / 1024);
  93.   Temp := Temp + WriteFormatFloat('###,##0.00', 10000000000 / (1024*1024));
  94.   Temp := Temp + WriteFormatFloat('###,##0.00', 100000000000 / (1024*1024));
  95.  
  96.   Temp := Temp + WriteFormatFloat('#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,0.00', 1000);
  97.   Temp := Temp + WriteFormatFloat('###,,,###,,,###,,,###,,,###,,,0.00', 1000);
  98.  
  99.   Memo1.Lines.Add(Temp);
  100. end;
  101.  
  102. end.
  103.  

The result:

Quote
1000.00 (###,##0.00) PointlessUserErrorCorrection OFF
1,000.00 (,0.00) PointlessUserErrorCorrection ON

1,0000.00 (###,##0.00) PointlessUserErrorCorrection OFF
10,000.00 (,0.00) PointlessUserErrorCorrection ON

9765.63 (###,##0.00) PointlessUserErrorCorrection OFF
9,765.63 (,0.00) PointlessUserErrorCorrection ON

9,765,625.00 (###,##0.00) PointlessUserErrorCorrection OFF
9,765,625.00 (,0.00) PointlessUserErrorCorrection ON

9536.74 (###,##0.00) PointlessUserErrorCorrection OFF
9,536.74 (,0.00) PointlessUserErrorCorrection ON

9,5367.43 (###,##0.00) PointlessUserErrorCorrection OFF
95,367.43 (,0.00) PointlessUserErrorCorrection ON

1000.00 (#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,0.00) PointlessUserErrorCorrection OFF
1,000.00 (,0.00) PointlessUserErrorCorrection ON

1000.00 (###,,,###,,,###,,,###,,,###,,,0.00) PointlessUserErrorCorrection OFF
1,000.00 (,0.00) PointlessUserErrorCorrection ON

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Issue with FormatFloat
« Reply #23 on: October 23, 2016, 05:05:53 pm »
That's why you can usually escape those. Nothing wrong with it as long as they can be escaped.

Sorry, you misunderstood. I meant the "special" characters in the format string that have "special" meaning but can only be used after reading the docs. Example: Decimal and thousand separator placeholders are "." and ",", but clearly some people thought that this literally meant "." and ",". Only by reading the docs is it clear that these are replaced by TFormatSettings record's DecimalSeparator and ThousandSeparator.

sfeinst

  • Full Member
  • ***
  • Posts: 230
Re: Issue with FormatFloat
« Reply #24 on: October 23, 2016, 06:56:30 pm »
it might be worthwhile just to point that out and recommend something else if possible, such as FloatToStrF, which does not expect special codes as part of its parameters.

Phil,
Thanks for pointing out FloatToStrF.  Using that with FFNumber format type gives good results and the benefit of the help being much more straight forward.

Thaddy,
I didn't look at writestr because I wanted a function as opposed to a procedure.  Using writestr would have required 2 lines of code for every line needing the formatting.  But you are correct I should have looked at it originally if for nothing else to verify my other output.

 

TinyPortal © 2005-2018