Recent

Author Topic: StrToFloat - formatted  (Read 4648 times)

Paolo

  • Hero Member
  • *****
  • Posts: 510
Re: StrToFloat - formatted
« Reply #15 on: June 25, 2022, 07:28:10 pm »
I see in the doc
Code: Pascal  [Select][+][-]
  1. function Int(d: Extended):Extended;
  2.  

so if you do this

Code: Pascal  [Select][+][-]
  1. Ratio : single or double;
  2. ...
  3. good:=(G1*Ratio) = Int(G1*Ratio)
  4.  

probably you are comparing "extended value" of Int e probably G1*Ratio expanded as Extended (it depends also the compiler target Win23, win64,..).

if you do that
Code: Pascal  [Select][+][-]
  1. with A, B : single;
  2. A := T1*Ratio;
  3. B := Int(A);
  4. Good := A = B;
  5.  

you are comparing two "single value" with Int value after trouncation at single

and as I said before the results can be different because single values are differenet wrt respective extended values.

very likely if you use Extended everywhere all is "good(true)".

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: StrToFloat - formatted
« Reply #16 on: June 25, 2022, 07:31:53 pm »
Well that was a short lived excursion into ReadStr . . . .

In an attempt to further understand the  - what I consider 'Weird'  -  behaviour, I've been trying to evaluate the value assigned to A & B   -  ie. the result of   (T1*Ratio)  -  by assigning it to a String Variable (TmpStr)  using ReadStr(TmpStr,A). This appeared to work - the project compiled and ran showing 'A' in a memo.

However I'd had a Compile OK but a 106 error at run-time indicating that the argument should be 'Char' ???  This was when I'd created a second 'String' variable - RStr : exactly the same as TmpStr - and using ReadStr(RStr,A) is not acceptable!   As I said  -  Weird.

Code: Pascal  [Select][+][-]
  1.     Repeat
  2.  
  3.       A := T1*Ratio;
  4.       B := Int(A);
  5.  
  6.       if T1< 22 then
  7.         begin
  8.           TmpStr := IntToStr(T1);
  9. //          ReadStr(RStr,T1);
  10.           WriteMemo('T1-  I2S '+TmpStr,false);
  11.           ReadStr(TmpStr,T1);
  12.           WriteMemo('T1-  Read '+TmpStr,false);
  13.  
  14.           TmpStr := FloatToStr(Ratio);
  15.           WriteMemo('Ratio -  F2S '+TmpStr,false);
  16.           ReadStr(TmpStr,Ratio);
  17.           WriteMemo('Ratio -  Read '+TmpStr,false);
  18.  
  19.           TmpStr := FloatToStr(A);
  20.           WriteMemo('  A-  F '+TmpStr,false);
  21.           ReadStr(TmpStr,A);
  22.           WriteMemo('  A-  R '+TmpStr,false);
  23.  
  24. //          ReadStr(RStr,B);
  25.           TmpStr := FloatToStr(B);
  26.           WriteMemo('  B-  F '+TmpStr+'  R - '+RStr,true);
  27.         end;
  28.  
  29.       Good := A = B;
  30.  

If I un-comment lines 9 or 24 then although it compiles the runtime error 106 always fires.

Whilst I've been evaluating and writing this, Paolo & WP have made further suggestions and I've now successfully incorporated WPs 'SameValue' suggestion - I'd tried many variants previously but always got something wrong!  :-[   often being warned that 'You can't do that' but never fully understanding why.

I'll not bother trying to understand why ReadStr seems to dislike my use of RStr any further and thank all contributors for their stirling efforts to solve my issues.

« Last Edit: June 25, 2022, 07:39:25 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: StrToFloat - formatted
« Reply #17 on: June 25, 2022, 07:38:13 pm »
... you are comparing two "single value" with Int value after trouncation at single

and as I said before the results can be different because single values are differenet wrt respective extended values.

very likely if you use Extended everywhere all is "good(true)".
I think that you are right on the money Paolo - to some extent I was only pursuing the issue out of curiosity, but hopefully I've learned a valuable lesson which may also be useful to others :)
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Thaddy

  • Hero Member
  • *****
  • Posts: 14367
  • Sensorship about opinions does not belong here.
Re: StrToFloat - formatted
« Reply #18 on: June 25, 2022, 08:28:49 pm »
Just playing "Oh  well"
https://www.youtube.com/watch?v=0yq-Fw7C26Y
Why are you trying to mimic morons????
https://www.youtube.com/watch?v=vZw35VUBdzo
« Last Edit: June 25, 2022, 08:35:08 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: StrToFloat - formatted
« Reply #19 on: June 25, 2022, 08:43:12 pm »
Just playing "Oh  well"
https://www.youtube.com/watch?v=0yq-Fw7C26Y
Why are you trying to mimic morons????
https://www.youtube.com/watch?v=vZw35VUBdzo
I do appreciate your input Thaddy (though not your choice of music  ;D   -  I'm currently rehearsing Haydn's 'The Creation')  and I will evaluate ReadStr & WriteStr further - just not today.  :o   

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: StrToFloat - formatted
« Reply #20 on: June 25, 2022, 08:58:58 pm »
Just playing "Oh  well"
https://www.youtube.com/watch?v=0yq-Fw7C26Y

OH WELL!

One  of the worlds best blues guitar heroes.
Replaced Eric Claption at the Bluesbreakers.

Peter Green RIP

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: StrToFloat - formatted
« Reply #21 on: June 25, 2022, 11:10:53 pm »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   D:Single = 2.54999952;
  4. begin
  5.   D := RoundTo(D,-4)*20;
  6.   Caption := Int(D).Tostring;
  7. end;                            
  8.  

Produces 51

Does that help you at all?
Thanks Jamie  -   your post nearly got lost in the crowd  -  but I do like to acknowledge all contributions to any threads that I initiate.

It doesn't help specifically for this project but it does show me other ways to format numbers where the container needs a string, so it does help to further my education :)   - - -   so many new 'methods' have become available since I started programming with TP and my 'GoTo' reference work is still TP 4.0 documentation - though I do have TP 6.0 as well - and of course I have many Lazarus Tutorial pages permanently open.  To some extent there is 'information overload' so I often miss very useful newer methods.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: StrToFloat - formatted
« Reply #22 on: June 26, 2022, 01:09:29 am »
I've used the Currency type many times for Fixed point. the RTL seems to know how to handle it.

 it gives you 4 places to the right and is all binary in a 64bit integer.

if your values can fit in that then maybe that is what you need to use.

you can just create a morphing type if you wish..

Type
TMyNumberType = Currency;

 The Fix point type does not have the rounding issues etc.

 Just a thought.
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11915
Re: StrToFloat - formatted
« Reply #23 on: June 26, 2022, 09:57:18 am »
I've used the Currency type many times for Fixed point. the RTL seems to know how to handle it.
[...]
 The Fix point type does not have the rounding issues etc.
It may have HUGE rounding issues if applied thoughtlessly...

Currency is usable only for elemental math operations such as addition, subtraction and multiplication. Even division, if done in the wrong order, may be seriously in error because of the few decimal places.
Code: Pascal  [Select][+][-]
  1. var
  2.   c1, c2, c3: Currency;
  3. begin
  4.   c1 := 1;
  5.   c2 := 100000;
  6.   c3 := c1 / 3 * c2;
  7.   WriteLn(c1:0:6);
  8.   WriteLn(c2:0:6);
  9.   WriteLn(c3:0:6);
  10. end.
The result is expected to be 33333.3333, but it turns out to be 33330.0000. (The correct result is obtained, when the division is performed at the end, i.e. c3 := c1*c2/3, but strictly speaking, the order of multiplication and division is not important in math).

And "real" math can be a huge problem:
Code: Pascal  [Select][+][-]
  1. var
  2.   c1, c2, c3: Currency;
  3. begin
  4.   c1 := 0.5;
  5.   c2 := ln(c1);
  6.   c3 := exp(c3);
  7.   WriteLn(c1);
  8.   WriteLn(c2);
  9.   WriteLn(c3);
  10. end.
This code calculates the log of 0.5 and then the exp function of the result. Since ln and exp are inverse functions the final result should be equal to the initial value (0.5) - it turns out the be 1.0. however.

tetrastes

  • Sr. Member
  • ****
  • Posts: 481
Re: StrToFloat - formatted
« Reply #24 on: June 26, 2022, 11:00:23 am »
Code: Pascal  [Select][+][-]
  1. var
  2.   c1, c2, c3: Currency;
  3. begin
  4.   c1 := 0.5;
  5.   c2 := ln(c1);
  6.   c3 := exp(c3);
  7.   WriteLn(c1);
  8.   WriteLn(c2);
  9.   WriteLn(c3);
  10. end.
This code calculates the log of 0.5 and then the exp function of the result. Since ln and exp are inverse functions the final result should be equal to the initial value (0.5) - it turns out the be 1.0. however.

There is typo in your code:
Code: Pascal  [Select][+][-]
  1. c3 := exp(c3);
The result of
Code: Pascal  [Select][+][-]
  1. c3 := exp(c2);
is correct.

Though I agree with you about rounding issues and the usability of Currency type in general. Currency is for currency.

wp

  • Hero Member
  • *****
  • Posts: 11915
Re: StrToFloat - formatted
« Reply #25 on: June 26, 2022, 12:12:45 pm »
Oh...

But then I don't understand this data type at all. I thought it is stored as an Int64 (https://www.freepascal.org/docs-html/ref/refsu5.html: "The currency type is a fixed-point real data type which is internally used as an 64-bit integer type (automatically scaled with a factor 10000)"). How can it yield the exact result when all decimals after the 4th are truncated in the first calculation? Well, maybe, when the exp is calculated based on the rounded value the error is after the 4th decimal again and does not appear after truncating the final result. But such a coincidence is hard to believe. I am sure that there must be better examples...

dseligo

  • Hero Member
  • *****
  • Posts: 1220
Re: StrToFloat - formatted
« Reply #26 on: June 26, 2022, 12:30:23 pm »
Oh...

But then I don't understand this data type at all. I thought it is stored as an Int64 (https://www.freepascal.org/docs-html/ref/refsu5.html: "The currency type is a fixed-point real data type which is internally used as an 64-bit integer type (automatically scaled with a factor 10000)"). How can it yield the exact result when all decimals after the 4th are truncated in the first calculation? Well, maybe, when the exp is calculated based on the rounded value the error is after the 4th decimal again and does not appear after truncating the final result. But such a coincidence is hard to believe. I am sure that there must be better examples...

ln(0,5) is rounded to -0,6931

exp(-0,6931) is 0,50002359083648271601454137665035 (Windows calc).
That is rounded to 0,5000, so the result is correct.

I use currency a lot, and didn't encounter any significant problems with it.

It is great for me e.g. when I have to sum many financial values which have 2 decimal places. When I used double I always have differences with final sum. With currency I always have correct result.
It would be great to have more decimal places though, I would find it even more useful.

wp

  • Hero Member
  • *****
  • Posts: 11915
Re: StrToFloat - formatted
« Reply #27 on: June 26, 2022, 01:30:02 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.
Code: Pascal  [Select][+][-]
  1. Program Test;
  2. uses
  3.   Math;
  4. var
  5.   c1, c2, c3: Currency;
  6.   d1, d2, d3: Double;
  7. begin
  8.   WriteLn('Calculation with double:');
  9.   d1 := -9.8;
  10.   d2 := exp(d1);
  11.   d3 := ln(d2);
  12.   WriteLn('d1 = ', d1:0:9);
  13.   WriteLn('d2 = ', d2:0:9);
  14.   WriteLn('d3 = ', d3:0:9, ' (should be equal to d1)');
  15.  
  16.   writeln;
  17.  
  18.   WriteLn('Calculation with currency:');
  19.   c1 := -9.8;
  20.   WriteLn('c1 = ', c1:0:4);
  21.   c2 := exp(c1);
  22.   if c2 = 0 then
  23.     WriteLn('c2 = (Cannot calculate ln(0.0000))')
  24.   else
  25.   begin
  26.     WriteLn('c2 = ', c2:0:4);
  27.     c3 := ln(c2);
  28.     WriteLn('c3 = ', c3:0:4, ' (should be equal to c1)');
  29.   end;
  30.  
  31.   ReadLn;  
  32. end.

Output:
Code: [Select]
Calculation with double:
d1 = -9.800000000
d2 = 0.000055452
d3 = -9.800000000 (should be equal to d1)

Calculation with currency:
c1 = -9.8000
c2 = 0.0001
c3 = -9.2103 (should be equal to c1)

J-G

  • Hero Member
  • *****
  • Posts: 953
Re: StrToFloat - formatted
« Reply #28 on: June 26, 2022, 01:54:27 pm »
To help me better understand not only the potential problems with choice of 'Type' to use (Currency, Double, Extended) but also the use of ReadStr & WriteStr, I've knocked up a quick project (.Zip attached) to take an argument (default at 0.5 as suggested by WP) and show these results.

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 . . . .

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.

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

tetrastes

  • Sr. Member
  • ****
  • Posts: 481
Re: StrToFloat - formatted
« Reply #29 on: June 26, 2022, 02:07:57 pm »
I am sure that there must be better examples...

The most obvious is trigonometry:
Code: Pascal  [Select][+][-]
  1. uses math;
  2.  
  3. var
  4.   f1, f2, f3: single;     // Not very precise, but proper, not to say about double
  5.   c1, c2, c3: Currency;
  6. begin
  7.   f1 := 0.01;
  8.   f2 := cos(f1);
  9.   f3 := arccos(f2);
  10.   WriteLn(f1);
  11.   WriteLn(f2);
  12.   WriteLn(f3);
  13.   f1 := f1+2*PI;
  14.   f2 := cos(f1);
  15.   f3 := arccos(f2);
  16.   WriteLn(f1);
  17.   WriteLn(f2);
  18.   WriteLn(f3);
  19.   writeln;
  20.  
  21.   c1 := 0.01;
  22.   c2 := cos(c1);       // Improper
  23.   c3 := arccos(c2);    // Improper (not equals 0.01)
  24.   WriteLn(c1);
  25.   WriteLn(c2);
  26.   WriteLn(c3);
  27.   c1 := c1+2*PI;
  28.   c2 := cos(c1);       // Not equals cos(0.01)
  29.   c3 := arccos(c2);     // Improper (not equals 0.01)
  30.   WriteLn(c1);
  31.   WriteLn(c2);
  32.   WriteLn(c3);
  33.   ReadLn;
  34. end.
  35.  
« Last Edit: June 26, 2022, 02:12:34 pm by tetrastes »

 

TinyPortal © 2005-2018