Re: [fpc-pascal] Floating point question
>>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
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
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);