Re: [fpc-pascal] Floating point question

2024-02-20 Thread James Richters via fpc-pascal
>>If you're using Win64, then the answer is simple: x86_64-win64 unlike any
other x86 target does not support Extended, so neither the compiler nor the
code in runtime will ever calculate anything with that precision.
To clarify,  I am using i386-win32 on a 64 bit specifically because Extended
is really just a Double on x86_64-win64.  All my test programs were done
with Win32.

>>you see the pattern? You simply have to rotate the six digits in a certain
manner ...
I see it now that you pointed it out and I think that it is really cool that
it's the same digits rotated!   Thanks!

>>I don't think you need the cast to extended around the divisions;   
Correct, I don't need to do this and I should not need to do it, but I also
should not need to re-cast the terms of the division, but with constants
that's what I must do to get the correct result.

Also, my programs would never re-cast the constants, I was just making it
clear that a byte divided by a single in fact does produce a correct
extended answer when done with variables, and I didn't want any doubt that
it was dividing a byte by a single.
This is the correct behavior.  My point was that the problem isn't that the
3.5 was stored or cast as a single,  It's valid for it to be a single,  and
that should make no difference at all, and in fact my results as exactly the
same without all the casting, 
But the only way to get the correct answer with constants is to do what
should be an unnecessary cast to extended of terms in my expression:

program Const_Vs_Var;

Const
   A_const = 1;
   B_const = 3.5;
Var
   A_Var : Byte;
   B_Var : Single;
   Const_Ans1, Var_Ans1, Difference1 : Extended;
   Const_Ans2, Var_Ans2, Difference2 : Extended;


Begin
   A_Var := A_Const;
   B_Var := B_Const;

   Const_Ans1  := A_Const/B_Const;
   Var_Ans1:= A_Var/B_Var;
   Difference1 := Var_Ans1-Const_Ans1;
   Const_Ans2  := A_Const/Extended(B_Const);   //I should not need to cast
B_Const in this way
   Difference2 := Var_Ans1-Const_Ans2;
   
   WRITELN ( '  Const_Ans1 = ', Const_Ans1);
   WRITELN ( 'Var_Ans1 = ', Var_Ans1);
   WRITELN ( ' Difference1 = ', Difference1);
   Writeln;
   WRITELN ( '  Const_Ans2 = ', Const_Ans2);
   WRITELN ( 'Var_Ans1 = ', Var_Ans1);
   WRITELN ( ' Difference2 = ', Difference2);

End.
  Const_Ans1 =  2.85714298486709594727E-0001 //This is a single precision
calculation stored in an extended
Var_Ans1 =  2.85714285714285714282E-0001   //The nice repeating decimal
I expect
 Difference1 = -1.27724238804447203649E-0008  //This should have been 0

  Const_Ans2 =  2.85714285714285714282E-0001  //I should not have had to
cast Extended(B_Var) to get this
Var_Ans1 =  2.85714285714285714282E-0001   // The correct answer again
just for clarification
 Difference2 =  0.E+  //Now it is 0 as I expected


>>When casting this way
>>Byte(A_Var)/Single(B_Var)
>>I would expect the division to be done with single precision, but
apparently it is done 
>>using extended (or another) precision ... on Windows, not on Linux. And
this is what 
>>causes your headaches.

I would NOT expect this to result in single precision,  when I divide a Byte
by a single in Turbo Pascal and assign it to a Double, the result is correct
in double precision.  
The ONLY way to get a single for an answer in Turbo Pascal is to define a
variable as a single and use that to do that calculation.
MySingle := A_Var/B_Var;

If the variable is a double:
MyDouble := A_Var/B_Var;
Then no matter what B_Var is, whether it's a single or a double, MyDouble is
the same correct number

If I want the result to be a single then:
Single(A_Var/B_Var)  
Should be what I require.

It doesn't matter in Turbo Pascal if I am dividing by a variable defined as
a single or a variable defined as a double, or an undefined constant,
and it does not matter in FPC either as long as my division is done with
variables.

It's FPC with Constants that is making MyByte/MySingle come out as a single,
and that is incorrect.   Division by a single does not force the answer to
be a single.
Please See this:

program Const_Vs_Var;

Const
   A_const = 1;
   B_Const = 3.5;
   C_Const = 7;
Var
   A_Var : Byte;
   B_Var : Single;
   C_Var : Byte;
   VPi : Extended;
   Const_Ans1, Var_Ans1, Difference1 : Extended;
   Const_Ans2, Var_Ans2, Difference2 : Extended;
   Const_Ans3, Var_Ans3, Difference3 : Extended;


Begin
   A_Var := A_Const;
   B_Var := B_Const;
   C_Var := C_Const;
   VPi := Pi;

   Const_Ans1  := A_Const/B_Const;
   Var_Ans1:= A_Var/B_Var;
   Difference1 := Var_Ans1-Const_Ans1;

   Const_Ans2  := A_Const/C_Const;
   Var_Ans2:= A_Var/C_Var;
   Difference2 := Var_Ans2-Const_Ans2;

   Const_Ans3  := Pi/B_Const;
   Var_Ans3:= VPi/B_Var;
   Difference3 := Var_Ans3-Const_Ans3;

   WRITELN ( '  Const_Ans1 = ', Const_Ans1);
   WRITELN ( 'Var_Ans1 = ', Var_Ans1);
   WRITELN ( ' Difference1 = ', Difference1);
   Writeln;
   WRITELN ( '  Const_Ans2 = ', Const_Ans2);
   WRITELN ( '  

Re: [fpc-pascal] Floating point question

2024-02-20 Thread Tomas Hajny via fpc-pascal

On 2024-02-20 08:03, Sven Barth via fpc-pascal wrote:

James Richters via fpc-pascal 
schrieb am Di., 20. Feb. 2024, 04:42:


I don't know why it would be different in Windows than on Linux.


If you're using Win64, then the answer is simple: x86_64-win64 unlike
any other x86 target does not support Extended, so neither the
compiler nor the code in runtime will ever calculate anything with
that precision.


Well, this probably isn't the (sole) reason in this particular case, 
because the results posted by Michael and coming from Linux (probably 
x86_64) were equal for constants and variables, but less precise than 
the result of run-time posted for Windows (unfortunately without 
specifying whether it was i386-win32 or x86_64-win64, but I'd guess for 
the former based on the results - exactly due to the reason mentioned by 
you).


Tomas
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Floating point question

2024-02-20 Thread Bernd Oppolzer via fpc-pascal

See below ...


Am 19.02.2024 um 02:00 schrieb James Richters via fpc-pascal:


>And if you have set the precision, then the calculation will be 
identical to the calculation when you use a variable of the same type 
(if not, it's indeed a bug).


This is what I have been trying to point out.Math with identical 
casting with variables and constants are not the same.


Maybe if I try with a simpler example:

program Const_Vs_Var;

Const

A_const = Byte(1);

B_const = Single(3.5);

Var

A_Var : Byte;

B_Var : Single;

Const_Ans1, Var_Ans1 : Extended;

Begin

A_Var := A_Const;

B_Var := B_Const;

Const_Ans1 := Extended(Byte(A_Const)/Single(B_Const));

Var_Ans1:= Extended(Byte(A_Var)/Single(B_Var));

WRITELN ( ' Const_Ans1 = ', Const_Ans1);

WRITELN ( 'Var_Ans1 = ',Var_Ans1);

End.

Const_Ans1 =2.85714298486709594727E-0001

Var_Ans1 =2.85714285714285714282E-0001

Windows 10 Calculator shows the answer to be

0.28571428571428571428571428571429Which matches up with the way 
variables have done this math, not the way constants have done it.




you don't need a calculator for 2 / 7 or 1 / 3.5. There is a simple rule 
for the decimal representation when dividing by 7:


1 / 7 = 0.142857 ...   repeat ad infinitum
2 / 7 = 0.285714
3 / 7 = 0.428571
4 / 7 = 0.571428
5 / 7 = 0.714285
6 / 7 = 0.857142

you see the pattern? You simply have to rotate the six digits in a 
certain manner ...



I am explicitly casting everything I possibly can.



I don't think you need the cast to extended around the divisions;
the divisions are done at different precision, which makes your problem,
but the cast to extended at the end doesn't help ... it will be done 
anyway,

because the target field is extended.

The problem indeed is that the division is done differently for consts 
and for vars,
and this seems to be the case for Windows only, as another poster 
pointed out.

This seems to be a real bug.

When casting this way

Byte(A_Var)/Single(B_Var)

I would expect the division to be done with single precision, but 
apparently it is done
using extended (or another) precision ... on Windows, not on Linux. And 
this is what

causes your headaches.


Without the :20:20 you can see that the result of each of these is in 
fact extended, but they are VERY different numbers, even though my 
casting is IDENTICAL , and I can’t make it any more the same, the 
results are very different.Math with Variables allows the result of a 
low precision entity, in this case a Byte, divided by a low precision 
entity, in this case a Single, to be calculated and stored in an 
Extended, Math with Constants does not allow this possibility, and 
this is where all the confusion is coming from.Two identical pieces of 
code not producing the same results.


Math with Constants is NOT the same as Math with Variables, and if 
this one thing was fixed, then all the other problems go away.


I am doing:

Const_Ans1 := Extended(Byte(A_Const)/Single(B_Const));

Var_Ans1:= Extended(Byte(A_Var)/Single(B_Var));

Just to make a point, but the code:

Const_Ans1 := A_Const/B_Const;

Var_Ans1:= A_Var/B_Var;

Should also produce identical results without re-casting, because 
A_Const and A_Var are both defined to be a Byte, and B_Const and B_Var 
are both defined to be a Single, and Const_Ans1 and Var_Ans1 are both 
defined to be Extended.


Why are the result different?

As I tried to explain before, if I force all constants to be Extended:

Const_Ans1 := Extended(Extended(A_Const)/Extended(B_Const));

Then I do get the correct results, but this should not be needed, and 
this casting is wrong,because a byte divided by a single should be 
able to be extended without first storing them in extended entities, 
the same as it is with variables.


With variables I do not need to re-cast every single term in an 
expression as Extended to get an Extended answer.


With constants this is the ONLY way I can get an extended answer.

Before the changes to 2.2, all constants WERE at highest precision, so 
the math involving constants never had to bother with considering that 
a low precision number divided by a low precision number could end up 
as an extended, because there were no low precision constants at all. 
But now there are, and that’s really fine, because we often have low 
precision variables, and that’s fine, but the math needs to be done 
the same way whether with constants or variables to produce identical 
results so now math with constants also has to take into consideration 
that math with low precision entities can and often does result in a 
high precision answer.


To demonstrate that a low precision entity divided by a low precision 
entity should always be able to be an Extended, use this example my 
constants as BYTES so there can be no lower precision:


program Const_Vs_Var;

Const

A_const = Byte(2);

B_const = Byte(7);

Var

A_Var : Byte;

B_Var : Byte;

Const_Ans1, Const_Ans2, Var_Ans1 : Extended;

Begin

A_Var := Byte(A_Const);

B_Var := Byte(B_Const);