### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: StrToFloat - formatted  (Read 2257 times)

#### jamie

• Hero Member
• Posts: 4675
##### Re: StrToFloat - formatted
« Reply #30 on: June 26, 2022, 02:57:46 pm »
here is an old test project, I use this helper for a few things and the values are based from Excel etc.
The only true wisdom is knowing you know nothing

#### dseligo

• Hero Member
• Posts: 651
##### Re: StrToFloat - formatted
« Reply #31 on: June 26, 2022, 03:06:59 pm »
Here is a variant of the exp/ln sample with shows a difference although not as large as I had written. The difference becomes evident when an intermediate currency result gets close to 0.0000. In this particular example there will even be a runtime error when c1 is -9.9 or smaller so that the intermediate result is 0.0000 in the currency case because the ln(0.0000) cannot be calculated.

If you need more than 4 decimal places then use single or double, not currency. You could still use single or double for intermediate calculation and use currency for final value if that fits your need.

#### wp

• Hero Member
• Posts: 9908
##### Re: StrToFloat - formatted
« Reply #32 on: June 26, 2022, 03:29:42 pm »
If you need more than 4 decimal places then use single or double, not currency. You could still use single or double for intermediate calculation and use currency for final value if that fits your need.
Why should I switch number type for intermediate calculations? I never use Currency because I want the full accuracy of the calculation. I don't care about the appended '0's or '9's - even if this looks ugly on a quick and dirty output, its the highest accuracy than can be achieved on a computer with the finite resolution of single, double or extended. When it comes to display the results the numbers must be converted to strings anyway, and for this there are a lot of float-to-string conversion functions which can round to any number of decimals. Currency poses the risk of enhanced error propagation when multiple operations are chained. Even the requirement to have multiplication and division in a given order is against all that I am used to.

Currency is good only for adding monetary values, but even this can be done with single/double/extended since the error in them is way beyond the 4 decimals of Currency and never shows up in a string converted to 2 decimals.

The only problem with single/double/extended is in comparison operations. As main rule, never use the =, <, <= etc operators, use SameValue of the math unit (or combinations with it) instead. The reason why currency comparisons are always (?) exact is that they basically do nothing else than SameValue(a, b, 1E-4).

#### BrunoK

• Sr. Member
• Posts: 313
• Retired programmer
##### Re: StrToFloat - formatted
« Reply #33 on: June 26, 2022, 03:54:59 pm »
Currency is good only for adding monetary values, but even this can be done with single/double/extended since the error in them is way beyond the 4 decimals of Currency and never shows up in a string converted to 2 decimals.
t is that they basically do nothing else than SameValue(a, b, 1E-4).
Code: Pascal  [Select][+][-]
1. program Project1;
2.
3. var
4.   i : integer;
5.   d1, d2 : double;
6.   sd1, sd2 : double;
7.
8.   c1, c2 : currency;
9.   sc1, sc2 : currency;
10. begin
11.
12.   d1 := 0.1; d2 := 0.2;
13.   sd1 :=0; sd2 := 0;
14.   for I := 1 to 10 do
15.     sd1 := sd1 + d1;
16.   for I := 1 to 5 do
17.     sd2 := sd2 +d2;
18.   WriteLn('sd1 = sd2 : ', sd1 = sd2);
19.
20.   c1 := 0.1; c2 := 0.2;
21.   sc1 :=0; sc2 := 0;
22.   for I := 1 to 10 do
23.     sc1 := sc1 + c1;
24.   for I := 1 to 5 do
25.     sc2 := sc2 +c2;
26.   WriteLn('sc1 = sc2 : ', sc1 = sc2);
27.
29. end.
30.

#### dseligo

• Hero Member
• Posts: 651
##### Re: StrToFloat - formatted
« Reply #34 on: June 26, 2022, 03:58:36 pm »
If you need more than 4 decimal places then use single or double, not currency. You could still use single or double for intermediate calculation and use currency for final value if that fits your need.
Why should I switch number type for intermediate calculations? I never use Currency because I want the full accuracy of the calculation. I don't care about the appended '0's or '9's - even if this looks ugly on a quick and dirty output, its the highest accuracy than can be achieved on a computer with the finite resolution of single, double or extended. When it comes to display the results the numbers must be converted to strings anyway, and for this there are a lot of float-to-string conversion functions which can round to any number of decimals. Currency poses the risk of enhanced error propagation when multiple operations are chained. Even the requirement to have multiplication and division in a given order is against all that I am used to.

Currency is good only for adding monetary values, but even this can be done with single/double/extended since the error in them is way beyond the 4 decimals of Currency and never shows up in a string converted to 2 decimals.

You said: "I want the full accuracy of the calculation", "Currency poses the risk of enhanced error propagation" and "even this can be done with single/double/extended since the error in them is way beyond the 4 decimals of Currency and never shows up in a string converted to 2 decimals".
Look at this example:

Code: Pascal  [Select][+][-]
1. var cX: Currency = 0.0;
2.     dX: Double = 0.0;
3.     i: Integer;
4.     s: String;
5. begin
6.   For i := 1 to 10000 do begin
7.     cX := cX + 10000000.07;
8.     dX := dX + 10000000.07;
9.   end;
10.
11.   WriteLn(FormatFloat('0.0000', cX));
12.   WriteLn(FormatFloat('0.0000', dX));
13. end.

Result of double isn't accurate for me, there is error propagation and error is in 2nd decimal place already. Exactly opposite of what you said for single and double types.

If you think I consider that single/double isn't good and currency type is the best, you are wrong (it feels like that from tone of your post). You have to know advantages and limits of both type when you use them, and there are cases when one type is better than the other.

P.S.: Try single instead of double in my example, LOL

#### wp

• Hero Member
• Posts: 9908
##### Re: StrToFloat - formatted
« Reply #35 on: June 26, 2022, 04:02:29 pm »
Currency is good only for adding monetary values, but even this can be done with single/double/extended since the error in them is way beyond the 4 decimals of Currency and never shows up in a string converted to 2 decimals.
t is that they basically do nothing else than SameValue(a, b, 1E-4).
Code: Pascal  [Select][+][-]
1. program Project1;
2.
3. var
4.   i : integer;
5.   d1, d2 : double;
6.   sd1, sd2 : double;
7.
8.   c1, c2 : currency;
9.   sc1, sc2 : currency;
10. begin
11.
12.   d1 := 0.1; d2 := 0.2;
13.   sd1 :=0; sd2 := 0;
14.   for I := 1 to 10 do
15.     sd1 := sd1 + d1;
16.   for I := 1 to 5 do
17.     sd2 := sd2 +d2;
18.   WriteLn('sd1 = sd2 : ', sd1 = sd2);
19.
20.   c1 := 0.1; c2 := 0.2;
21.   sc1 :=0; sc2 := 0;
22.   for I := 1 to 10 do
23.     sc1 := sc1 + c1;
24.   for I := 1 to 5 do
25.     sc2 := sc2 +c2;
26.   WriteLn('sc1 = sc2 : ', sc1 = sc2);
27.
29. end.
30.
Did you read my post? I wrote: "never use the =, <, <= etc operators, use SameValue of the math unit (or combinations with it) instead."

#### wp

• Hero Member
• Posts: 9908
##### Re: StrToFloat - formatted
« Reply #36 on: June 26, 2022, 04:13:53 pm »
Code: Pascal  [Select][+][-]
1. var cX: Currency = 0.0;
2.     dX: Double = 0.0;
3.     i: Integer;
4.     s: String;
5. begin
6.   For i := 1 to 10000 do begin
7.     cX := cX + 10000000.07;
8.     dX := dX + 10000000.07;
9.   end;
10.
11.   WriteLn(FormatFloat('0.0000', cX));
12.   WriteLn(FormatFloat('0.0000', dX));
13. end.
Good example. But I stay with my opinion that currency is not good for anything else than addition and subtraction and multiplication. Division already may go wrong if the programmer is not careful.

#### BrunoK

• Sr. Member
• Posts: 313
• Retired programmer
##### Re: StrToFloat - formatted
« Reply #37 on: June 26, 2022, 04:21:09 pm »
In accounting :
sum of debits must be exactly equal to sum of credit.
OutOfTaxAmount + TaxAmount = TotalAmount must be exact.

Sum(OutOfTaxAmount) + Sum(TaxAmount)  = Sum(TotalAmount)

Sum(OutOfTaxAmount) * (1 + TaxRate) must, with small divergence be equal to Sum(TotalAmount). Thus well defined rounding strategy must be defined, especially when the total amount of, invoices for example, are rounded to 5 cents.

That's the most basic thing an auditor will check.

#### BrunoK

• Sr. Member
• Posts: 313
• Retired programmer
##### Re: StrToFloat - formatted
« Reply #38 on: June 26, 2022, 04:28:28 pm »
Just a small correction, if I would have to write an accounting system for a country that has an hyper inflating currency,  then I would do it all with the double/extended type.

#### BrunoK

• Sr. Member
• Posts: 313
• Retired programmer
##### Re: StrToFloat - formatted
« Reply #39 on: June 26, 2022, 04:40:37 pm »
And with SameValue :
Code: Pascal  [Select][+][-]
1. program Project1;
2.
3. uses
4.   math;
5. var
6.   i : integer;
7.   d1, d2 : double;
8.   sd1, sd2 : double;
9.
10.   c1, c2 : currency;
11.   sc1, sc2 : currency;
12. begin
13.
14.   d1 := 0.1; d2 := 0.15;
15.   sd1 :=0; sd2 := 0;
16.   for I := 1 to 75000 do
17.     sd1 := sd1 + d1;
18.   for I := 1 to 50000 do
19.     sd2 := sd2 +d2;
20.   WriteLn('sd1 = sd2 : ', sd1 = sd2);
21.   WriteLn('SameValue(sd1 = sd2) : ', SameValue(sd1, sd2));
22.
23.   c1 := 0.1; c2 := 0.15;
24.   sc1 :=0; sc2 := 0;
25.   for I := 1 to 75000 do
26.     sc1 := sc1 + c1;
27.   for I := 1 to 50000 do
28.     sc2 := sc2 +c2;
29.   WriteLn('sc1 = sc2 : ', sc1 = sc2);
30.
32. end.
Output :
sd1 = sd2 : FALSE
SameValue(sd1 = sd2) : FALSE
sc1 = sc2 : TRUE

#### wp

• Hero Member
• Posts: 9908
##### Re: StrToFloat - formatted
« Reply #40 on: June 26, 2022, 05:04:24 pm »
Code: Pascal  [Select][+][-]
1.   WriteLn('SameValue(sd1 = sd2) : ', SameValue(sd1, sd2, 1e-7));  // ---> TRUE

Of course this kind of calculation is a bit unfair because it adds always the same value and the same error value. Thus it causes maximum error propagation; and therefore, the relatively high tolerance value is needed to achieve a TRUE comparison (Note that Currency with 4 decimals is equivalent to a tolerance of 1E-4, though). If the accumulated addition is replaced by a single multiplication, the tolerance can be much smaller. And if different values were added, each having a different float error, positive or negative, the tolerance would be smaller either.

#### BrunoK

• Sr. Member
• Posts: 313
• Retired programmer
##### Re: StrToFloat - formatted
« Reply #41 on: June 26, 2022, 05:30:35 pm »
Of course this kind of calculation is a bit unfair ...
Agreed ;-)
But I could expose cases about bean counters making difficulties with small imbalances or also excessively exact balance where an small error (not imbalance) should logically have been found due to rounding.

#### J-G

• Hero Member
• Posts: 807
##### Re: StrToFloat - formatted
« Reply #42 on: June 26, 2022, 05:47:58 pm »
That's quite a flurry of posts while I had my back turned! --  mostly trying to dis @WPs opinion on the use of Currency.

I've never used Currency in the past - and I've written two accounting suites - I have attempted to use 'SameValue' on occasion but not been successful  ---  until educated in its proper use by WP in post #15, where he pointed out the anciliary issues of Int().

Essentially this discussion has been very useful (to me anyway) in bringing to the fore the importance of choosing the appropriate 'Type' to use, depending upon the particular application.  I used to use 'Real' for any float until I realized that its size and significance was platform dependant and then switched to 'Single' as my default  - -  Now I have a better understanding of the 'Pros' & 'Cons' of any 'Type' and can make an informed decision in future.

Hmm . . .   I started this post to raise the point about pBCD but got distracted!

I know (well think) that Packed Binary Coded Decimal gets around all these issue caused by not being able to store decimal numbers accurately in binary format so why isn't pBCD used - or have I missed some 'small but important' point?

« Last Edit: June 26, 2022, 06:14:57 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0
Win 7 Ult 64

#### jamie

• Hero Member
• Posts: 4675
##### Re: StrToFloat - formatted
« Reply #43 on: June 26, 2022, 05:54:28 pm »
https://community.atmel.com/projects/afp-arbitrary-fixed-point-lib

I guess I am not the only one in town that knows floats are a problem when you need exact values.

In my line of work I try not to use floats because of the unexpected fractional results that leads of confusion.

The link above is another contributor that thinks the say way and their LIB has some trig in it.
The only true wisdom is knowing you know nothing

#### PascalDragon

• Hero Member
• Posts: 4301
• Compiler Developer
##### Re: StrToFloat - formatted
« Reply #44 on: June 26, 2022, 11:01:02 pm »
It's interesting to see that each 'type' has issues with certain inputs, (the obvious ones being numbers ending in a 5 - [1.25] say) though D & E seem to have the same issue - try 5.125 . . . .

As written by various others already: some numbers can not be expressed exactly as floating point numbers. So 5.125 can only be approximated and the math system can't simply show 5.125, because what if you did try to use the number that 5.125 is approximated as? You'd simply change the numbers that are approximated. This is something you need to live with when dealing with floating point numbers. If you don't and you know the number of digits beyond the decimal point you need to deal with then go with a fixed point library.

The ReadStr/WriteStr also threw up some unexpected issues. ReadStr accepted the use of a TLable.Caption but WriteStr does not, it demands an intermediary 'String' variable which is currently beyond my understanding.

Same reason you can't take an address of a property (it could be a method call after all resulting in a temporary variable). For ReadStr the value of the string only needs to be read, thus it's perfectly find to pass a property. For WriteStr that's different however as the contents of the string are modified with each variable that is written to the string. Thus you can't use properties here.