Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

Author Topic: Converting variables and subtracting them  (Read 462 times)

andhunter

• Newbie
• Posts: 3
Converting variables and subtracting them
« on: January 24, 2023, 04:06:14 pm »
Hi everyone!

Can you please tell me why I get wrong number when subtracting? Here is an example 5.05 - 5 = 0.0499999999999998
And this always happens when the integer parts of the numbers are the same (10 and 10.05, 20 and 20.05, etc.). As far as I understand, this can be bypassed using StrToFloatF . But I would like to know what causes this result.

Code: Pascal  [Select][+][-]
1. unit Unit1;
2.
3. {\$mode objfpc}{\$H+}
4.
5. interface
6.
7. uses
8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
9.
10. type
11.
12.   { TForm1 }
13.
14.   TForm1 = class(TForm)
15.     Button1: TButton;
16.     Edit1: TEdit;
17.     Edit2: TEdit;
18.     Edit3: TEdit;
19.     Label1: TLabel;
20.     procedure Button1Click(Sender: TObject);
21.   private
22.
23.   public
24.
25.   end;
26.
27. var
28.   Form1: TForm1;
29.   a,b,c:extended;
30. implementation
31.
32. {\$R *.lfm}
33.
34. { TForm1 }
35.
36. procedure TForm1.Button1Click(Sender: TObject);
37. begin
38.     a:= StrToFloat(Edit1.Text);
39.     b:= StrToFloat(Edit2.Text);
40.     c:= a-b;                           // 5,05 - 5 = 0,0499999999999998
41.     Label1.Caption:= floattostr(c);
42.
43. end;
44.
45. end.

KodeZwerg

• Hero Member
• Posts: 1189
Re: Converting variables and subtracting them
« Reply #1 on: January 24, 2023, 04:08:43 pm »
Because Floats are no natural number. Even a float of 10 is something like 10.00000000000952436593264593214
« Last Edit: Tomorrow at 31:76:97 by KodeZwerg »

KodeZwerg

• Hero Member
• Posts: 1189
Re: Converting variables and subtracting them
« Reply #2 on: January 24, 2023, 04:15:30 pm »
Try something like:
Code: Pascal  [Select][+][-]
1. Label1.Caption := FloatToStrF(c, ffFixed, 2, 2);
« Last Edit: Tomorrow at 31:76:97 by KodeZwerg »

andhunter

• Newbie
• Posts: 3
Re: Converting variables and subtracting them
« Reply #3 on: January 24, 2023, 04:23:28 pm »
Try something like:
Code: Pascal  [Select][+][-]
1. Label1.Caption := FloatToStrF(c, ffFixed, 2, 2);

Thank you for the explanation. The Windows calculator also apparently uses a similar rounding method.

Warfley

• Hero Member
• Posts: 1075
Re: Converting variables and subtracting them
« Reply #4 on: January 24, 2023, 04:49:46 pm »
Because Floats are no natural number. Even a float of 10 is something like 10.00000000000952436593264593214
I don't know how you get this number, but thats not true. Floats can display any whole number thats between 0 and 2^m (where m is the number of mantissa bits) correctly. The reason for this is that an IEEE 754 float is of the form 1.mantissa *2^exponent. Where the mantissa can be any bitstring. Meaning for any number whose bit representation fits the mantissa, an exponent can be chosen, such that the whole mantissa is shifted over the decimal separator.

What cannot be fully realized are fractions. Because the of the form 1.mantissa, with mantissa being a bitstring, only combinations of fractions with exponent 2 can be expressed. For example 0.5 (1/2), 0.25 (1/4), 0.75 (1/2+1/4), etc. can be written this way.
We humans usually use the decimal system, which is base 10. As 10 is a prime combination of 2 and 5, this means that every fraction of an exponent of 2 can also be written as a decimal number. But as some decimal numbers contain fractions of base 5, not all can be dispalyed as binary fractions.

The same phenomena can be seen when looking at our decimal system and fractions of neither exponent 2 or 5. 1/3 for example cannot be represented as a decimal number, but is 0.333333... So at some point it must be cut of, for example to 0.333, but now this number is 0.0003333... = 1/3000 different from the original number (i.e. we now display 1/3-1/3000 rather than just 1/3). And the exact same thing happens when we try to convert decimal fractions to binary and vice versa.

For example, the 5.05 is 5 + 0.05. Again whole numbers can be fully represented, but looking at the fraction 0.05 = 1/2 * 1/5 * 1/2. As you can see it contains a fraction of base 5 (1/5), so it cannot be represented as a binary fraction.
This is why it is just barely wrong in the computer, and when outputting without any rounding, it will show you all the digits up to the error bit in the end.
« Last Edit: January 24, 2023, 04:52:08 pm by Warfley »

KodeZwerg

• Hero Member
• Posts: 1189
Re: Converting variables and subtracting them
« Reply #5 on: January 24, 2023, 04:54:08 pm »
Because Floats are no natural number. Even a float of 10 is something like 10.00000000000952436593264593214
I don't know how you get this number, but thats not true.
I just literal pressed all over my numkey-pad to illustrate that a float 10 is not a natural 10. That there is always something behind. I am sorry if I confused you and apology for my misinterpretation, please forgive me.
« Last Edit: Tomorrow at 31:76:97 by KodeZwerg »

andhunter

• Newbie
• Posts: 3
Re: Converting variables and subtracting them
« Reply #6 on: January 24, 2023, 06:10:49 pm »

What cannot be fully realized are fractions. Because the of the form 1.mantissa, with mantissa being a bitstring, only combinations of fractions with exponent 2 can be expressed. For example 0.5 (1/2), 0.25 (1/4), 0.75 (1/2+1/4), etc. can be written this way.
We humans usually use the decimal system, which is base 10. As 10 is a prime combination of 2 and 5, this means that every fraction of an exponent of 2 can also be written as a decimal number. But as some decimal numbers contain fractions of base 5, not all can be dispalyed as binary fractions.

The same phenomena can be seen when looking at our decimal system and fractions of neither exponent 2 or 5. 1/3 for example cannot be represented as a decimal number, but is 0.333333... So at some point it must be cut of, for example to 0.333, but now this number is 0.0003333... = 1/3000 different from the original number (i.e. we now display 1/3-1/3000 rather than just 1/3). And the exact same thing happens when we try to convert decimal fractions to binary and vice versa.

For example, the 5.05 is 5 + 0.05. Again whole numbers can be fully represented, but looking at the fraction 0.05 = 1/2 * 1/5 * 1/2. As you can see it contains a fraction of base 5 (1/5), so it cannot be represented as a binary fraction.
This is why it is just barely wrong in the computer, and when outputting without any rounding, it will show you all the digits up to the error bit in the end.

Thanks for the clarification.