[Lazarus] formatfloat negative zero (-0)

Lukasz Sokol el.es.cr at gmail.com
Wed Jul 9 11:02:37 CEST 2014


Hello Dymitry & Andrea,

(see my answer below)

On 07/07/14 15:35, Dmitry Boyarintsev wrote:
> Very true, sorry for the typo.
> I meant give an idea, not an actual solution.
> Plus it might won't work, if FormatFloat is not called directly, but rather by a 3d party component.
> 
> thanks,
> Dmitry
> 
> 
> On Mon, Jul 7, 2014 at 6:31 PM, Philippe <philippe at quarta.com.br <mailto:philippe at quarta.com.br>> wrote:
> 
>     __
> 
>     if (Result<>'') and (Result[1]='-1') then begin
> 
>     maybe ( '-1' -> '-' )
> 
>     if (Result<>'') and (Result[1]='-') then begin
> 
>     ?
> 
>      
> 
>      
> 
>     Em 07.07.2014 10:48, Dmitry Boyarintsev escreveu:
> 
>>     Will straight forward solution work?
>>     how about this:
>>      
>>     unit MySysUtils;
>>      
>>     interface
>>      
>>     uss SysUtils;
>>      
>>     // the function will cut heading "-" if all digits in the number are zeros. 
>>     // it will leave the result unchanged otherwise.
>>      
>>     function FormatFloat(const fmt: string; num: double): string;
>>     var 
>>       i : integer;
>>     begin
>>       Result:= SysUtils.FormatFloat(fmt, num);
>>       if (Result<>'') and (Result[1]='-1') then begin
>>         for i:=2 to length(Result) do
>>          if Result[i] in ['1'..'9'] then Exit;
>>         Result:=Copy(Result, 2, length(Result)-1);
>>       end;
>>       
>>     end;
>>     ....
>>     in your program. Put "MySysUtils" as the last unit in the uses section (so your working unit would use MySysUtils FormatFloat, instead of the implementation at SysUtils)
>>      
>>     thanks,
>>     Dmitry
>>      
>>
>>
>>     On Mon, Jul 7, 2014 at 5:00 PM, Andrea Mauri <andrea.mauri.75 at gmail.com <mailto:andrea.mauri.75 at gmail.com>> wrote:
>>
>>
>>                 using formatfloat function I got an unexpected behaviour.
>>                 If I round negative numbers I can get as result of formatfloat = '-0'.
>>                 I think it is a bug, since -0 has no meaning, zero is zero.
>>                 How can I make a workaround?
>>                 e.g.
>>                 label1.Caption:= FormatFloat('0.###', strtofloat(edit1.Text));
>>                 if in edit1.text I have -0.000001 I got -0 as result while I would like to get 0.
>>
>>                 Is it a bug, what can I do?
>>
>>
>>             Minus-zero is a recognized computational 'feature' of floats on computers, not a bug (AFAIK).
>>
>>             The float variable value of StrToFloat(edit1.text) is still -0.000001 though;
>>             (try assigning it to a float type variable and watch it)
>>
>>         OK, I understand that computationally -0 has meaning (since as you said the float variable value of StrToFloat(edit1.text) is still -0.000001).
>>         Anyway It has no meaning for the final user of the application (at least for any standard user of an application).
>>         The final user does not care that -0 has meaning for the computer.
>>         e.g. I would like to represent a float value with 3 decimal digits. I don't care of the remaining digits, -0.000 has no meaning, it just means that there are some digits (somewhere after the third decimal digits) that are not equal to zero and that if they are considered the value is negative (but I don't want to consider any digit after the third decimal one!).
>>         Try to do it in excel or libreoffice:
>>         - write in a cell -0.00001 and set to 3 the decimal digits, you got -0.000 or 0.000?
>>         And you got the same results using any software that deals with numbers..
>>
>>
>>
>>             Does the same happen if you Round() it to integer?
>>             e.g.
>>             label1.caption := Format('%d',[Round(strtofloat(edit1.text))]);
>>             (I know this isn't what you're after
>>
>>         In this way I got 0.
>>         Anyway I used as example formatfloat since it has the same behaviour of TFloatField.DisplayFormat, additionally DisplayFormat is a property that is used to represent a formatted value to the final user (a human being not a pc) for whom -0 has no meaning.
>>
>>         A.
>>
>>
>>
>>
>>                 Best regards,
>>                 Andrea Mauri
>>
>>             -L.

(p.s. please avoid top-posting unless you have to...)

I think manipulating this in string is also wrong on some levels.

What you need is a function that eats away the value but still does it in a float compute,
like

function EatFloatBelow(Num : double; DecimalPlaces: Integer; EatSign:boolean=true): double;
var Temp : Integer; 
begin
  (* Preprocess the float for displaying with fixed decimal places
   * if Num is smaller than 10**DecimalPlaces, it should also eat the sign by default
   * WARNING some of this function is pseudocode please check for proper variables *)
  
(* DecimalPlaces is supposed to be positive *)
  if DecimalPlaces < 0 then exit;

  (* preflight checks : check that DecimalPlaces is sane *)
  if 10**(-DecimalPlaces) < DoublePrecision then exit;  (* or Power(10,(-DecimalPlaces)) *)

  Temp := RoundDown(Num*(10**DecimalPlaces)); // first 'shift it' left and get rid of the remaining decimals by rounding down to integer
  Result := Temp / (10**DecimalPlaces);   // now restore the proper order and back to float

  (* can also combine the above 2 steps and use one less variable
   * Result := Trunc(Num*(10**DecimalPlaces)) / (10**DecimalPlaces) ; *)

  (* if we ended with something close to zero but still negative, eat the sign *)
  if (Result < 0) and EatSign and (Result < 10**(-DecimalPlaces))  then
    Result := Result * (-1) ;
  
end;

then use
label1.Caption:= FormatFloat('0.###', EatFloat(strtofloat(edit1.Text),3));

-L.





More information about the Lazarus mailing list