### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: A computational problem  (Read 1046 times)

#### lazpas

• Jr. Member
• Posts: 59
##### A computational problem
« on: October 02, 2022, 03:26:33 am »
44950-7693*4.77=?
The code looks like this:

Code: Pascal  [Select][+][-]
1. ......
2. parser := TFPExpressionParser.Create(nil);
3.   try
4.     parser.BuiltIns := [bcMath];
5.     parser.Expression := '44950-7693*4.77';
6.     parserResult := parser.Evaluate;
7.     Caption:= FloatToStr(parserResult.ResFloat);
8.   finally
9.     parser.Free;
10.   end;
11.

The result is:8254.39000000001

The correct result is:8254.39

Is there a bug in my code?

Thanks

#### Bogen85

• Full Member
• Posts: 163
##### Re: A computational problem
« Reply #1 on: October 02, 2022, 04:20:20 am »
44950-7693*4.77=?
...

The result is:8254.39000000001

The correct result is:8254.39

Is there a bug in my code?

Thanks

No. Your code is fine. That is normal for binary to decimal conversion. You can't get an exact representation of the floating point number when you convert it to decimal due to base 10 not being a power of 2.
You need to display it with less precision then trim trailing zeros to get something that is more reasonable.
« Last Edit: October 02, 2022, 04:23:11 am by Bogen85 »

#### MarkMLl

• Hero Member
• Posts: 5595
##### Re: A computational problem
« Reply #2 on: October 02, 2022, 09:04:59 am »
Or rescale the numbers before the calculation and handle them as integers. 64 bits should be enough to handle most financial calculations for at least a few more months :-/

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

#### jcmontherock

• Full Member
• Posts: 152
##### Re: A computational problem
« Reply #3 on: October 02, 2022, 09:19:19 am »

#### Bogen85

• Full Member
• Posts: 163
##### Re: A computational problem
« Reply #4 on: October 02, 2022, 09:40:50 am »

The result was off by 0.0000000001 according to @lazpas.

That is a normal floating point to decimal conversion issue.

Adding parenthesis around the 7693*4.77 is not going to make floating point to decimal conversion issues magically disappear.

This problem is not limited to Pascal, specifically Free Pascal in this example. You would get the same results with C/C++/python/etc if you don't limit the precision on the displayed output.

#### Bogen85

• Full Member
• Posts: 163
##### Re: A computational problem
« Reply #5 on: October 02, 2022, 10:16:10 am »
44950-7693*4.77=?
...
The result is:8254.39000000001

The correct result is:8254.39

Is there a bug in my code?

Or just use sysutils.format. It will correct the display issues for you.
https://www.freepascal.org/docs-html/rtl/sysutils/format.html

Code: Pascal  [Select][+][-]
1. {\$mode delphi}
2.
3. program float_precision;
4.
5. uses
6.   fpexprpars,
7.   sysutils;
8.
9.   procedure primary (const parser: TFPExpressionParser);
10.
11.     procedure do_sample (const tag, fmt, expression: string);
12.       begin
13.         parser.expression := expression;
14.         writeln (tag, ': ', expression, ' = ', format (fmt, [parser.evaluate.resFloat]));
15.       end;
16.
17.     begin
18.
19.       do_sample ('1', '%f', '44950-7693*4.77');
20.       do_sample ('2', '%f', '(44950-7693)*4.77');
21.       do_sample ('3', '%f', '44950-(7693*4.77)');
22.       do_sample ('4', '%g', '44950-7693*4.77');
23.       do_sample ('5', '%e', '44950-7693*4.77');
24.
25.       parser.free;
26.     end;
27.
28.   function newParser: TFPExpressionParser;
29.     begin
30.       result := TFPExpressionParser.create (nil);
31.       result.builtIns := [bcMath];
32.     end;
33.
34. begin
35.   primary (newParser);
36. end.

Code: Text  [Select][+][-]
1. \$ fpc lazforum/60783/float_precision.pas && ./lazforum/60783/float_precision
2. Free Pascal Compiler version 3.3.1 [2022/10/01] for x86_64
3. Copyright (c) 1993-2022 by Florian Klaempfl and others
4. Target OS: Linux for x86-64
5. Compiling lazforum/60783/float_precision.pas
7. 36 lines compiled, 0.4 sec, 658752 bytes code, 361144 bytes data
8. 1: 44950-7693*4.77 = 8254.39
9. 2: (44950-7693)*4.77 = 177715.89
10. 3: 44950-(7693*4.77) = 8254.39
11. 4: 44950-7693*4.77 = 8254.3900000000067
12. 5: 44950-7693*4.77 = 8.2543900000000067E+003

Results from 1 or 3 are what you are looking for.
« Last Edit: October 02, 2022, 10:45:16 am by Bogen85 »

#### jamie

• Hero Member
• Posts: 4934
##### Re: A computational problem
« Reply #6 on: October 02, 2022, 03:26:50 pm »
Currency type
WriteStr(.... with Format speciifiers)

Fixed Point math unit etc.

The only true wisdom is knowing you know nothing

#### J-G

• Hero Member
• Posts: 931
##### Re: A computational problem
« Reply #7 on: October 02, 2022, 06:51:24 pm »
I've taken to using my own two procs. to circumvent this issue.

In case it may be of interest :

Code: Pascal  [Select][+][-]
1. Var
2.   TmpStr :    String;
3.
4. procedure StripZero(Var S : String;NoTrail : Boolean);
5. begin
6.   while S[length(S)] = '0' do
7.     begin
8.       S := copy(S,1,Pred(Length(S)));
9.     end;
10.   if S[length(S)] ='.' then
11.     begin
12.       if NoTrail then
13.         S := copy(S,1,Pred(Length(S)))
14.       else
15.         S := S+'0';
16.     end;
17.   if Length(S) = 0 then
18.     S := '0';
19. end;
20.
21. procedure MakeStr(Val : single;Trail : boolean;DP : byte);
22. begin
23.   Str(Val:4:DP,TmpStr);
24.   StripZero(TmpStr,trail);
25. end;
26.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

#### jamie

• Hero Member
• Posts: 4934
##### Re: A computational problem
« Reply #8 on: October 02, 2022, 08:14:45 pm »
I've taken to using my own two procs. to circumvent this issue.

In case it may be of interest :

Code: Pascal  [Select][+][-]
1. Var
2.   TmpStr :    String;
3.
4. procedure StripZero(Var S : String;NoTrail : Boolean);
5. begin
6.   while S[length(S)] = '0' do
7.     begin
8.       S := copy(S,1,Pred(Length(S)));
9.     end;
10.   if S[length(S)] ='.' then
11.     begin
12.       if NoTrail then
13.         S := copy(S,1,Pred(Length(S)))
14.       else
15.         S := S+'0';
16.     end;
17.   if Length(S) = 0 then
18.     S := '0';
19. end;
20.
21. procedure MakeStr(Val : single;Trail : boolean;DP : byte);
22. begin
23.   Str(Val:4:DP,TmpStr);
24.   StripZero(TmpStr,trail);
25. end;
26.

Ah, you mean this
Code: Pascal  [Select][+][-]
1. RemoveTrailingChars(S,['0','.']);
2.

and this
Code: Pascal  [Select][+][-]
1. procedure TForm1.Button1Click(Sender: TObject);
2. Var
3.   S:String;
4. begin
5.    WriteStr(S,8254.000000001:0:2);
6.    RemoveTrailingChars(S,['0','.']);
7.    Caption := S;
8. end;
9.

Etc

The only true wisdom is knowing you know nothing

#### jamie

• Hero Member
• Posts: 4934
##### Re: A computational problem
« Reply #9 on: October 02, 2022, 08:28:22 pm »
To add a little bit to it

Code: Pascal  [Select][+][-]
1. Function RemoveTrailingCharsF(S:String; C:TSysCharSet;EmptyStr:String='0'):String;
2. Begin
3.    RemoveTrailingChars(S,C);
4.    If S ='' then S :=EmptyStr;
5.    Result := S;
6. end;
7.
8. procedure TForm1.Button1Click(Sender: TObject);
9. Var
10.   S:String;
11. begin
12.    WriteStr(S,8254.000000001:0:2);
13.    Caption := RemoveTrailingCharsF(S,['0','.']);
14. end;
15.
16.
The only true wisdom is knowing you know nothing

#### Arioch

• Sr. Member
• Posts: 414
##### Re: A computational problem
« Reply #10 on: October 02, 2022, 08:55:51 pm »
If S ='' then S :=EmptyStr;
end;

but why???

with short strings this is
Code: Pascal  [Select][+][-]
1. if s[0] = #0 then s[0] := #0;

with long strings this should be equal to
Code: Pascal  [Select][+][-]
1. if s = nil then s := nil;

in both cases nothing was gained...

#### jamie

• Hero Member
• Posts: 4934
##### Re: A computational problem
« Reply #11 on: October 02, 2022, 09:22:02 pm »
now just think about that for a moment.

Why limit the function?
The only true wisdom is knowing you know nothing

#### Arioch

• Sr. Member
• Posts: 414
##### Re: A computational problem
« Reply #12 on: October 02, 2022, 09:35:26 pm »
Ouch...

Code: Pascal  [Select][+][-]
1. EmptyStr:String='0'):

EmptyStr is parameter here....

There is RTL constant with same name AFAIR

#### jamie

• Hero Member
• Posts: 4934
##### Re: A computational problem
« Reply #13 on: October 02, 2022, 10:08:44 pm »
What if I wanted the Empty Value to be something other than a single digit char ?

what if it's a UTF8 for special symbols etc.?
The only true wisdom is knowing you know nothing

#### lazpas

• Jr. Member
• Posts: 59
##### Re: A computational problem
« Reply #14 on: October 26, 2022, 10:16:39 am »