Recent

Author Topic: How to avoid rounding in result of StrToFloat function.  (Read 9686 times)

toplek

  • Jr. Member
  • **
  • Posts: 53
How to avoid rounding in result of StrToFloat function.
« on: December 03, 2016, 07:40:25 pm »
Hi,

I'm trying to convert string '12.111119999999999999999' into Double, using function StrToFloat:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button3Click(Sender: TObject);
  2. var temp: Double;
  3. begin
  4.  DefaultFormatSettings.DecimalSeparator := '.' ;
  5.  
  6.  temp := StrToFloat('12.111119999999999999999');
  7.  
  8.  ShowMessage(FloatToStr(temp));
  9. end;
  10.  

The result of the conversion is '12.11112', so It's looks like, the StrToFloat function is rounding results, the question is how to avoid rounding in such conversion ?

br
Piotr Polok

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: How to avoid rounding in result of StrToFloat function.
« Reply #1 on: December 03, 2016, 07:53:59 pm »
Floating points have limited precision.  Double has about 17 significant positions but you specify over 20.

If you really need such precisions, you need a library that emulates higher order precision types than implemented in hardware. This will of course be a lot slower.

GMP is a library that offers such emulated floating point type, and the headers of that library come with FPC.

I would seriously consider using 20+ digits though, there are quite few real world applications for such precisions.

toplek

  • Jr. Member
  • **
  • Posts: 53
Re: How to avoid rounding in result of StrToFloat function.
« Reply #2 on: December 03, 2016, 08:03:57 pm »
You are right 20 is too much, I need 16 significant positions. If there is a StringToDouble function ?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: How to avoid rounding in result of StrToFloat function.
« Reply #3 on: December 03, 2016, 08:10:08 pm »
Strtofloat is overloaded for double.

toplek

  • Jr. Member
  • **
  • Posts: 53
Re: How to avoid rounding in result of StrToFloat function.
« Reply #4 on: December 03, 2016, 08:15:56 pm »
Yes, you are right, the function StrToFloat('12.11111999999999') gives rounded result: 12.1112 ...

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: How to avoid rounding in result of StrToFloat function.
« Reply #5 on: December 03, 2016, 08:20:15 pm »
----- And will give you the same result. Since the last 9 is rounded, the rest becomes zeros and two is rounded because the last 9.
So that will also give you 12.11112 and that is correct. (You can adjust the -global - round mode, though, to rmDown and scale back and forth)

In fact, you were already using the overloaded version for double ;)
« Last Edit: December 03, 2016, 08:23:12 pm by Thaddy »
Specialize a type, not a var.

toplek

  • Jr. Member
  • **
  • Posts: 53
Re: How to avoid rounding in result of StrToFloat function.
« Reply #6 on: December 03, 2016, 08:29:57 pm »
I'm not getting, I do not want to have rounded number.

The function StrToFloat('2.11111999999999') gives Doble number: 2.11111999999999.
The function StrToFloat('12.11111999999999') gives Doble number: 12.1112.

I need full number - not rounded, how to get it ? ;).

totya

  • Hero Member
  • *****
  • Posts: 720
Re: How to avoid rounding in result of StrToFloat function.
« Reply #7 on: December 03, 2016, 08:36:20 pm »
I think this round is correct.

With other number, you can get all digits.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var temp: double;
  3.     tempstr: string;
  4. begin
  5.  DefaultFormatSettings.DecimalSeparator := '.' ;
  6.  
  7.  temp := StrToFloat('12.1111199999999999');
  8.    tempstr:= FloatToStrF(temp,  ffGeneral, 16, 0);
  9.    Memo1.Lines.Add(tempstr+' length:'+IntTostr(Length(tempstr)));
  10.  temp := StrToFloat('12.1234567890123456');
  11.    tempstr:= FloatToStrF(temp,  ffGeneral, 16, 0);
  12.    Memo1.Lines.Add(tempstr+' length:'+IntTostr(Length(tempstr)));
  13. end;

Quote
12.11112 length:8
12.1234567890123 length:16

totya

  • Hero Member
  • *****
  • Posts: 720
Re: How to avoid rounding in result of StrToFloat function.
« Reply #8 on: December 03, 2016, 08:41:08 pm »
I'm not getting, I do not want to have rounded number.

The function StrToFloat('2.11111999999999') gives Doble number: 2.11111999999999.
The function StrToFloat('12.11111999999999') gives Doble number: 12.1112.

I need full number - not rounded, how to get it ? ;).

Code: Pascal  [Select][+][-]
  1. StrToFloat('12.1111199999999');

Quote
12.1111199999999 length:16

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: How to avoid rounding in result of StrToFloat function.
« Reply #9 on: December 03, 2016, 08:46:18 pm »
Yes, you are right, the function StrToFloat('12.11111999999999') gives rounded result: 12.1112 ...

It will read out the maximum number of digits that match the operand type (significant digits of double) and then round to the nearest power of two, since floating point numbers are binary.

Any excess digits are ignored, and you can add 500 additionals 9's but that won't matter.

toplek

  • Jr. Member
  • **
  • Posts: 53
Re: How to avoid rounding in result of StrToFloat function.
« Reply #10 on: December 03, 2016, 09:13:14 pm »
OK, so It's the reason why the converted number is rounded, thank you for the answers.

munair

  • Hero Member
  • *****
  • Posts: 798
  • compiler developer @SharpBASIC
    • SharpBASIC
Re: How to avoid rounding in result of StrToFloat function.
« Reply #11 on: December 03, 2016, 09:17:32 pm »
Try to assign the string to temp as a value:
Code: Pascal  [Select][+][-]
  1.  temp :=  12.111119999999999999999;
and debug that code. what you see is the same approximation of that value. Even if temp is of type extended you will get 12.111120000000000000023314683517128.

It is the old story of binary approximations of real numbers. The StrToFloat result is correct (from a binary point of view).
keep it simple

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: How to avoid rounding in result of StrToFloat function.
« Reply #12 on: December 04, 2016, 11:16:17 am »
It will read out the maximum number of digits that match the operand type (significant digits of double) and then round to the nearest power of two, since floating point numbers are binary.
Furthermore, some numbers cannot be represented in binary form:
Code: Pascal  [Select][+][-]
  1. var
  2.   D: Double = 0.35; // It is never equal to 0.35!
  3.  

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: How to avoid rounding in result of StrToFloat function.
« Reply #13 on: December 04, 2016, 11:23:37 am »
Not entirely true, one could use BCD throughout for better accuracy.
0.35 can be coded exact in BCD format.

example:
Code: Pascal  [Select][+][-]
  1. program untitled;
  2. {$ifdef fpc}{$mode delphi}{$endif}
  3. uses fmtbcd,sysutils;
  4. var
  5. d: double;
  6. b:Tbcd;
  7. s:string;
  8. begin
  9.  b := strtobcd('0.35');
  10.  d := strtofloat('0.35');
  11.  writeln('any loss? ',d);
  12.  s := bcdtostr(b);  // convert back
  13.  writeln('any loss? ',s);
  14. end.
« Last Edit: December 04, 2016, 11:32:54 am by Thaddy »
Specialize a type, not a var.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: How to avoid rounding in result of StrToFloat function.
« Reply #14 on: December 04, 2016, 02:33:00 pm »
Not entirely true, one could use BCD throughout for better accuracy...
Entirely true. See double?
BCD, char, decimal computer etc of course possible.

 

TinyPortal © 2005-2018