Re: [fpc-pascal] PTCGraph resolution detection
I found another way to get the screen resolution in Windows that is consistent between 32bit and 64bit programs using GetSystemMetrics. uses Windows; var ScreenWidth, ScreenHeight: Integer; begin ScreenWidth := GetSystemMetrics(SM_CXSCREEN); ScreenHeight := GetSystemMetrics(SM_CYSCREEN); WriteLn('Screen Width: ', ScreenWidth, ' pixels'); WriteLn('Screen Height: ', ScreenHeight, ' pixels'); end. This works well, and with PTCGraph, there is really no need to bother figuring out what video modes are available anyway, especially now that we can have custom resolutions for the PTCGraph window, I just need to make sure it fits on the screen so it really doesn't matter how I get the screen resolution. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] PTCGraph resolution detection
>>No idea, but it does sound like a Windows issue to me. >>Or a video card driver issue? >>The API is the same. The mechanism for obtaining the list of resolutions is >>also the same. >>Perhaps Microsoft uses a fake DirectDraw shim in 64-bit Windows that presents >>a fake resolutions list, because they can? >>Perhaps it is an issue, related to the video card drivers? >>What are the video cards on the two machines that you have tested? I added the following line in the while m loop Write(m^.MaxX+1, 'x', m^.MaxY+1,' Mode ',m^.ModeNumber,'-', m^.MaxColor,'Colors '); and with 64 bit on just the one machine with the 1080x2560 monitor, it lists all modes, including 1080x2560 and goes all the way to 2160x3840... but it is correctly only showing portrait resolutions. On the 1280x1024 PC with the 64bit version, it goes up to all the modes that have 1280x1024 and stops, because the monitor cannot display more than that. when I compile it as Win32 it stops at the monitor resolution on both computers. The computers are identical: Intel i3-4170 with motherboard intel graphics, no separate video card. They both have Windows 10 Pro. I just stuck my own variables in there were I can just tell it the resolution of the monitor, and if I put in 0x0 it does the original autodetect thing. With me supplying the monitor resolution, everything is now working correctly. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] PTCGraph resolution detection
I am trying to compile a program that uses PTCGraph for Windows 64 bit, and it's not behaving the same as it does on Win32. When I compile it for Win32, it is correctly detecting my monitor resolution I have a vertical monitor with a resolution of 1080x2560 When I run the Win32 program I correctly get: Max resolution:1080x2560 The 64bit version incorrectly produces: Max resolution:2160x3840 I tried it on another computer with a 1280x1024 monitor and it correctly identifies it on both versions. Below is the procedure that gets the monitor resolution. I am using the current trunk of FPC installed today. Does anyone have any idea why the 64bit version would work differently than the 32bit version? James Uses Windows,ptcgraph,ptccrt,crt,sysutils; Procedure WindowsGRAPHINIT; Var gd,gm:smallint; m: PModeInfo; graphinitialize,MaxX,MaxY:Integer; Begin Windowtitle:='ptcgraph'; graphinitialize:=1234; MaxX:=0; MaxY:=0; m := QueryAdapterInfo; while m <> nil do begin If m^.MaxX+1>MaxX then MaxX:=m^.MaxX+1; If m^.MaxY+1>MaxY then MaxY:=m^.MaxY+1; m := m^.next; end; Writeln ('Max resolution:',MaxX,'x',MaxY); gd:=VESA; gm:=InstallUserMode(WindowXResolution,WindowYResolution,65536,1,1,1) ; If gm<0 Then Begin Writeln('Error Installing Graphics ',gm,' ',grapherrormsg(gm)); Halt(70); End; PtcGraph.InitGraph(gd,gm,''); . snip . ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I seem to recall there is some way to get 80 Bit Extended on 64 Bit Windows, but it involved compiling a 64bit version of FPC myself somehow, and I can't remember what it was all about, I'm pretty sure I was doing that for a while, but then I wanted to upgrade and couldn't remember how it was all done, so I went back to Win32, just to get 80 Bit Extended. It's something to do with the cross compiler to 64 bit makes extended a double on 64bit, but if you weren't cross compiling and had just a native 64bit compiler then Extended is 80 bits again. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
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
>I would not put too much trust in Windows calculator, since there you have no control over the precision at all. The actual CORRECT answer according to https://www.wolframalpha.com/input?i=1%2F3.5 Is 0.285714 Repeating forever Which is what I get on windows only when using Variables. Var_Ans1 = 2.85714285714285714282E-0001 Which as you can see the .285714 repeats exactly 3 times with two more correct digits, for a total of 20 correct digits before we run out of precision. >It seems to be a windows-specific problem. Here is the result of your program when executed on Linux: > Const_Ans1 = 2.85714298486709594727E-0001 >Var_Ans1 = 2.85714298486709594727E-0001 >As you can see, the result is identical. Great, Linux is consistently giving you the wrong answer, and I notice it's the same wrong I answer I get when I use constants. I don't know why it would be different in Windows than on Linux. I am curious what you get in Linux for: A_const = (2/7); // should be 0.285714 Repeating forever also Or B_const = (2/7)-(1/3.5); //should always be 0; Just for fun I ran it on Turbo Pascal 7.0 for DOS and got: Const_Ans1 = 2.85714285714286E-0001 Var_Ans1 = 2.85714285714286E-0001 I also noticed that re-casting constants is not allowed by Turbo Pascal 7.0, so I removed the unnecessary re-casting so it would compile, but I did get the expected answer even without re-casting it... as I expected I should. The fact that Turbo Pascal gives be the correct answer to 14 digits even though in Turbo Pascal I also divided a byte by a single shows that I should expect my pascal programs to provide THIS correct answer, 0.285714 repeating until you run out of precision, not something else. And it shows that a byte divided by a single is in fact able to be an extended... it also proves that in Pascal the result of a byte divided by a single is NOT limited to single precision. 2.85714298486709594727E-0001 makes no sense to me at all, It's like it did the calculation in Single precision, then stored it in an extended, but if I wanted to work in single precision, I would not have set my variable to extended. There is some flawed logic somewhere that says if you do math with a single, the result is a single, but this is simply not correct, you can divide a byte by a byte and get an extended, and you can divide a single by a single and get an extended, Pascal has ALWAYS worked that way. Forcing the result of an equation to be a single because one term is a single is just not right. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>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.28571428571428571428571428571429 Which matches up with the way variables have done this math, not the way constants have done it. I am explicitly casting everything I possibly can. 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); Const_Ans1 := A_Const/B_Const; Var_Ans1 := A_Var/B_Var; WRITELN ( ' Const_Ans1 = ', Const_Ans1); WRITELN ( ' Var_Ans1 = ', Var_Ans1); End. Const_Ans1 = 2.85714285714285714282E-0001 Var_Ans1 = 2.85714285714285714282E-0001 Now as you can see math with constants is EXCATLY the same as math with variables again, and I did not need to do any ridiculous casting to get the correct answer. I hope this makes sense. I know exactly what is happening, but I don’t know why and I don’t know how to explain it other than to give these examples. 1/3.5 == 2/7 What should this program produce? program Const_Vs_Var; Const A_const = (2/7)-(1/3.5); Begin WRITELN ( ' A_Const = ', A_Const); End. How can this possibly be right? A_Const = -1.27724238804447203649E-0008 James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>But the reduced precision should not come unexpectedly simply because the compiler attaches type attributes to constants (which can't be easily >explained), and then the outcome of simple decimal arithmetic is incorrect. How are you disagreeing? This is EXACTLY what I am saying. My math with variables is ALWAYS correct, my math with Constants is not coming out the same and can't be easily explained. I guess I should have re-posted the example because it's not as it seems, this is a counterexample I had provided to show the incorrect math indeed could force an INCREASE in Precision, but even if I don't cast the variables you still get the same unexpected results.. this is just to demonstrate that the problem is not the reduction and assignment itself, but it's the way calculations are done by the compiler being wrong. The math with constants is what's wrong, not the reduction in precision. Look closely at the following example. I am ALWAYS adding an integer to a byte divided by a Single... The reduction in precision has been removed from this example because I explicitly cast what I wanted. This proves that the math with constants is what the problem is, not that the constants themselves were reduced in precision. The results of Const_Ans1 MUST Equal Var_Ans1 EXACTLY or all kinds of problems will arise. I have no reason to expect that the results of Var_Ans1 and Const_Ans1 would be different, yet they are. THIS is the Problem, and that's pretty much exactly what you just said, so I believe we are in agreement. The problem isn't that the reduction in precision assigned a type attribute to the constant, it's that the math with that type is being done wrong, because I can do the math with the EXACT same typed variables and it comes out correctly. I'm trying to show where the real problem is, (not very successfully) Math with Variables in the executing program, a byte / single can very well be extended. With the compiler math a byte / single is FORCED to be a single, which is incorrect. Dividing by a single does NOT imply the result should be a single. Before the changes in v2.2, this was NEVER an issue, because all the constants were full precision, so this could never possible come up as there would be no math with a single in it. My point is, no matter what is wrong, the result of math with constants must always be exactly the same as math with variables otherwise no one can figure out what the heck is going on. James program Const_Vs_Var; Const A_const = Integer(8427); B_const = Byte(33); C_const = Single(1440.5); Win_Calc = 16854.045817424505380076362374176; Const_Ans = 16854.045817424505380076362374176 / (8427 + 33 / 1440.5); Var A_Var : Integer; B_Var : Byte; C_Var : Single; Const_Ans1, Var_Ans1 : Extended; Begin A_Var := A_Const; B_Var := B_Const; C_Var := C_Const; Var_Ans1 := Win_Calc / (A_Var+B_Var/C_Var); Const_Ans1 := Win_Calc / (A_Const+B_Const/C_Const); WRITELN ( ' Const_Ans = ', Const_Ans:20:20); WRITELN ( ' Const_Ans1 = ', Const_Ans1:20:20); WRITELN ( ' Var_Ans1 = ', Var_Ans1:20:20); End. The result is: Const_Ans = 2.0010627116630224 Const_Ans1 = 2.0010627116630224 Var_Ans1 = 2. When I do: Var_Ans1 := Win_Calc / (A_Var+B_Var/C_Var); Const_Ans1 := Win_Calc / (A_Const+B_Const/C_Const); -Original Message- From: fpc-pascal On Behalf Of Bernd Oppolzer via fpc-pascal Sent: Friday, February 16, 2024 10:48 AM To: James Richters via fpc-pascal Cc: Bernd Oppolzer Subject: Re: [fpc-pascal] Floating point question Am 16.02.2024 um 15:57 schrieb James Richters via fpc-pascal: >> So you are saying when constant propagation is on, an expression should have a different result than with constant propagation off? > The result of math when using constants MUST be the same as the result of identical math using variables. > > There should never be a difference if I did my formula with hard coded constants vs variables. > >Const_Ans = 2.0010627116630224 > Const_Ans1 = 2.0010627116630224 > Var_Ans1 = 2. > > This should not be happening. > > James See my other post; if the developer explicitly wants reduced precision, then this is what happens. But the reduced precision should not come unexpectedly simply because the compiler attaches type attributes to constants (which can't be easily explained), and then the outcome of simple decimal arithmetic is incorrect. So I have to disagree, sorry. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>So you are saying when constant propagation is on, an expression should have a >different result than with constant propagation off? The result of math when using constants MUST be the same as the result of identical math using variables. There should never be a difference if I did my formula with hard coded constants vs variables. Const_Ans = 2.0010627116630224 Const_Ans1 = 2.0010627116630224 Var_Ans1 = 2. This should not be happening. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Ok, maybe this example will prove why it's not happening correctly: program Const_Vs_Var; Const A_const = Integer(8427); B_const = Byte(33); C_const = Single(1440.5); Win_Calc = 16854.045817424505380076362374176; Const_Ans = 16854.045817424505380076362374176 / (8427 + 33 / 1440.5); Var A_Var : Integer; B_Var : Byte; C_Var : Single; Const_Ans1, Var_Ans1 : Extended; Begin A_Var := A_Const; B_Var := B_Const; C_Var := C_Const; Var_Ans1 := Win_Calc / (A_Var+B_Var/C_Var); Const_Ans1 := Win_Calc / (A_Const+B_Const/C_Const); WRITELN ( ' Const_Ans = ', Const_Ans:20:20); WRITELN ( ' Const_Ans1 = ', Const_Ans1:20:20); WRITELN ( ' Var_Ans1 = ', Var_Ans1:20:20); End. The result is: Const_Ans = 2.0010627116630224 Const_Ans1 = 2.0010627116630224 Var_Ans1 = 2. Now you can see, if the math was done the same as the way math is done for variables, we could have stored the constants as Byte(2). But because the math is being carried out after the reduction in precision we are left with storing this as extended. If the result of all the math can be reduced, or if there is no math, then it's great to reduce precision, but if the reduction in precision happens before the math, you can end up with the opposite of what you intended. Sure the compiler is working with faster math, but who cares what the compiler has to do, now we're going to be stuck with a program using extended(2.0010627116630224) for any calculations that use Const_Ans instead of byte(2); if Const_Ans is used in some kind of iterative process, it the program could be using this extended millions of times when it could have been using a byte. Notice when I do the EXACT same math with variables, it DOES give me a result of 2, and THAT can be reduced. If the answer after all the math can be reduced, it should be reduced, if it can't be, then it should not be. Math with constants should be the same as math with variables. I'm trying to show there doesn't need to be a trade off at all, the math with constants just needs to be done correctly... as in the exact same way math with variables is done. What has happened is the math with constants was written and tested with the assumption that all constants would be full precision, because it was impossible for constants to be anything other than full precision, but now that is no longer the case and the math with constants isn't working correctly anymore. Either the math needs to happen before the reduction in precision or the math needs to be fixed so it works the same as math with variables, either way there won't need to be a trade off and everything will work the way everyone wants it to.. performance when possible and precision when needed. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>As Jonas said, this would result in less efficient code, since all the math will then be done at full precision, which is slower. I don't think I'm explaining it well, I'm saying where there is an entire formula that the compiler needs to evaluate, what's happening now, is that each term is being reduced in precision first, Then the math happens, and the result it stored. If instead the compiler did all the math first, THEN ran the function that determines if the entire answer should be reduced in precision, then the math would work correctly. But we don't care how long it takes to do the math during the compile, the constants are only compiled once and stored in the executable. The reason to do all this is to make the executing program that ends up using the constants over and over many times more efficient, the speed of the compilation is irrelevant. >As usual, it is a trade-off between size (=precision) and speed. I agree with that, but only in the executing program, not the compiler. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Sorry for the kind of duplicate post, I submitted it yesterday morning and I thought it failed, so I re-did it and tried again.. then after that the original one showed up. A thought occurred to me. Since the complier math is expecting all the constants would be in full precision, then the compiler math doesn't need to change, it's just that the reduction in precision is just happening too soon. It's evaluating and reducing each term of an expression, then the math is happening, and the answer is not coming out right. If instead everything was left full precision until after the compiler math (because this is what the compiler math expects), and then the final answer was reduced in precision where possible, then it would work flawlessly. So the reduction in precision function only needs to run once on the final answer, not on every term before the calculation. Sorry again for the duplicate. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>>Overall, the intermediate float precision is a very difficult topic. I agree it's a difficult topic, it all comes down to what your program is doing, and whether you need performance or precision. >>And generate the slowest code possible on most platforms. I can appreciate the need to reduce precision where it's possible for the sake of performance, especially when it won't make any difference. What makes it difficult is there are many different reasons for wanting it one way, or the other, it depends on the purpose of the program, and the compiler has no way to know what the purpose is. It occurs to me that one could want part of a program to be optimized for performance and another part of the same program to be optimized for precision, for example if you are doing calculations to generate geometry, and also want to display the geometry on the screen, the data you write out to a file you would want maximum precision, but since what you will display on the screen will eventually become only integer values of pixels you want to do that math as fast as possible, especially if you want to pan / zoom / rotate, and even though what the screen data is based on might be double precision or more, I can see how reducing its precision as fast as possible would be beneficial to increase performance. So Im trying to learn something, I agree it would be better have performance where its possible and precision when needed. But I just don't understand what is going on. I'm not trying to say that this reduction in precision should not be done, I'm understanding the value in it. Im trying to figure out why the math done with constants where the compiler is doing the math is not the same as when the program does with math with variables. If the solution is to typecast where needed to get the desired results, they why isnt it working the way I expect it to? Below is a sample program, Im not trying to make everything extended, in fact quite the opposite, there is no need for the input constants / variables to be Extended because they all fit perfectly in smaller data types, so I put them all into smaller datatypes as an example. I am defining constants explicitly and defining variables the exact same way, so Im comparing apples to apples here, I have A as always an Integer, B as always a Byte, and C as always a single, with a value the fits in a single. My goal is to add the integer to a byte thats been divided by a single and get the result in Extended. When I do this with the variables, everything is as I expected, when I do this with constants, its not as I expect. This is what I dont understand, and if this worked as expected then I think everyone is happy.What ever is happening for it to work correctly during program execution should also be happening when the compiler does the math. The problem isnt that the constants got stored in lower precision its that they are somehow forcing the result of the calculation to also be at the lower precision and not re-evaluated after the math. Its completely legitimate to divide a low precision number by a low precision number and get a high precision result, it works with Variables, why doesnt it work with Constants? I suspect that whats happened is that there is something missing in the way the compiler does math, something that is not needed if it was always done at maximum precision, but that is needed with mixed precision. Its not that the fact that the constants were reduced in precision, its something to do with the way the math is done with constants of reduced precision that isnt being accounted for, and that is not necessary if calculating with full precision. Its not that the changes in 2.2 are the problem at all, its that something else needed to be done at the same time that was missed. The only way I can get the correct result when using constants is to re-cast ALL of them as extended, not just the ones involving division, and not the entire formula, but every single constant. This is what I dont understand. >>The evaluation of the expression on the right of := does not know (and should not know) what the type is of the expression on the left. Why cant the compiler do tall the math at full precision and then evaluate only the result to see if that can be stored in a lower precision. If the expression on the right cannot and should not know the type on the left, then there is a good possibility that its a high precision data type, and then there should be some provision to safeguard against data loss if the type is of high precision. Why doesnt this work?JJ := Extended(A_Const+B_Const/C_Const); It requires no knowledge of what is on the left. Why cant the math be done with high precision and the result be reduced to the smallest datatype, Math with low precision data types often results in high precision results. If I want to have a mixed program with portions in high precision and portion
Re: [fpc-pascal] Floating point question
It occurs to me that there is merit in reduction of precision to increase performance, and so I'm trying to learn how to do this correctly, but the thing that confuses me is that math with constants doesn't seem to be the same as math with variables, and I don't know why. It also looks to me like when there is an expression such as: e := 8427.0 + 33.0 / 1440.0; what is happening each term of the expression is evaluated individually to see if it can be reduced in precision, and then the math is carried out, but if the math was carried out at full precision first by the compiler, THEN the entire answer was evaluated to see if it can be reduced in precision, the results would be what we are all expecting. Regardless of that however, when I am working with variables, an integer added to a byte that has been divided by a single results in an extended...it's legitimate to expect you could get an extended result from such an operation, just as dividing a byte by another byte could result in an extended answer. With variables, this seems to always be the case, but with constants, it does not seems to be the case. If constants just did the math the same as variables, then all this reduction in precision stuff would work flawlessly for everyone without re-casting everything. Please consider the code below, I am comparing the results to what I get when I perform this math with the Windows Calculator, as you can see no matter how I cast it, when using variables, I get the expected answer, but when the compiler does the math, it's not working the same way. What seems to be happening with variables is that the answer to lower precision entities can result in higher precision results, while with constants, the resulting precision is limited in some way, but in a way I don't understand, because it's being reduced to single precision, but the lowest precision element is a byte. In other words with variables a byte / single is perfectly capable of producing an extended result, without re-casting. But with constants doing the exact same thing forces the result to always be a single. I don't think the real issue has anything to do with this reduction in precision at all, I think it has to do with whatever causes the compiler to do math differently than the executing program does with variables. I don't understand why I must individually re-cast every element of the equation using constants to extended, while when I do the exact same thing with variables it's not necessary. I am wondering if the way the compiler does the math, it's is expecting that all constants would be full precision, and therefore the way it did the math before always came out right, but when the change was made in 2.2 to reduce the precision to variables, no corresponding adjustment was made to the way the compiler carries out math to compensate for the possibility that there was such a thing as a constant with reduced precision. So the compiler is doing math as if all input terms are at highest precision, therefore not needing to bother considering the answer might be higher precision than the input terms, but now that there is the possibility of the result being of higher precision, some adjustment to the way math is done by the compiler is necessary. I just think if the compiler did all the math the same way the executing program does with math with variables, then everything is solved for everyone... without any re-casting or unexpected results due to division, and while also preventing unnecessary precision. this has nothing to do with the reduction of precision, only the way the compiler is doing it's calculations needs to be adjusted for this new situation. Just fixing the way the compiler does the math also requires no knowledge of the left side of the equation by the right. The compiler just needs to do the calculations the same way as variables are calculated with the extra step of re-evaluating to see if the precision can be reduced when it's done. James program Const_Vs_Var; Const A_const = Integer(8427); B_const = Byte(33); C_const = Single(1440.5); Win_Calc = 8427.0229087122526900381811870878; Const_Ans = A_Const+B_Const/C_Const; Var A_Var : Integer; B_Var : Byte; C_Var : Single; Const_Ans1, Const_Ans2, Const_Ans3, Var_Ans1, Var_Ans2, Var_Ans3 : Extended; Begin A_Var := A_Const; B_Var := B_Const; C_Var := C_Const; Var_Ans1 := A_Var+B_Var/C_Var; Const_Ans1 := A_Const+B_Const/C_Const; Var_Ans2 := Integer(A_Var)+Byte(B_Var)/Single(C_Var); Const_Ans2 := Integer(A_Const)+Byte(B_Const)/Single(C_Const); Var_Ans3 := Extended(A_Var)+Extended(B_Var)/Extended(C_Var); Const_Ans3 := Extended(A_Const)+Extended(B_Const)/Extended(C_Const); WRITELN ( ' Win_Calc = ', Win_Calc:20:20) ; WRITELN ( ' Const_Ans = ', Const_Ans:20:20 ,' Win_Calc-Const_Ans = ',Win_Calc-Const_Ans:20:20) ; WRITELN ( ' Const_Ans1 = ', Const_Ans1:20:20 ,' Win_Calc-Const_Ans1 = ',Win_Ca
Re: [fpc-pascal] Floating point question
>However, adding support for an option called -CFMax or similar should be no problem. It would be VERY much appreciated! James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>Because 1440.1 cannot be represented exactly as a single precision floating point number. Nor as a double or extended precision floating point >number for that matter, and in that case the compiler uses the maximum precision is supported by the target platform. I see that now, I think someone pointed out that 1440.5 would also be a problem since it fits in a single. So my idea of trying to change all the x.0s to x only helps some cases, not all cases, as I can't change x.5 to anything quickly with a global search. There could be anything that happens to fit in a single, making my Extended calculation come out to a Single. How does one get the old behavior for programs that use Extended without analyzing and re-writing thousands of lines of code? Is there any way we can please get -CF80 or {$MINFPCONSTPREC 80} or some other way to turn off the new behavior for applications that use Extended. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>IMO, the computations of AA+BB/CC (right hand side) should be carried out the >same way, regardless of the type >on the left hand side of the assignment. So I would expect the values in DD, >EE and FF being the same. In this example DD hold the value 8427.0224610 because DD it defined as a single and a single cannot hold the value 8427.022916625000, there aren’t enough bits. There is a typo on line: WRITELN ( 'EE = ',FF: 20 : 20 ) ; It should have been WRITELN ( 'EE = ',EE: 20 : 20 ) ; And the result of it should have been: EE = 8427.022916668000 Which is not the same as FF = 8427.022916625000 Again because 8427.022916625000 won’t fit in a double. The intention with all that was to show that everything works correctly if variables are used. The problem is when you use constants you get the 8427.0224... for everything, even when you have defined a double or an extended >That said: wouldn't it make more sense to give EVERY FP CONSTANT the FP type >with the best available precision? Yes, that is the old way, before the change in 2.2, but there are times when it would be more efficient to reduce the precision in the example of: Const MyConst = 2.0; That doesn't have to be floating point, and if you later use it as the denominator in a divide, it's less efficient than it would be if it was an integer.. I argue that on modern computers, who cares, but if you do want to reduce precision to increase performance, it NEEDS to be done in a way that guarantees no loss of precision with no modification of code. The changes in v2.2 fails in this regard. The thing I don't understand is that this was released as the default for all modes and indeed with no good way to turn it off for extended, even though it was already known that there would be inaccuracies when using constants with divides. The change in 2.2 should NOT have been the default for everyone, it should have been an option for those who want performance at the cost of precision, but nearly everyone will not notice the performance increase on a modern computer, but we will all do not want to risk a loss of precision... >GG in this case would have the same value as HH, because the computation >involving the constants >(hopefully done by the compiler) would be done with the best available >precision. Yes, it would be! And that is precisely why this is a bug! GG not matching HH is a problem. GG and HH should be identical, the compiler should to math exactly the same way as an executing program, otherwise it's a mess. The computation SHOULD always be done at maximum precision, and that's the way it used to work before this: https://wiki.freepascal.org/User_Changes_2.2.0#Floating_point_constants "Old behaviour: all floating point constants were considered to be of the highest precision available on the target platform" This is the correct way that guarantees precision. "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" This is GREAT if you can pull it off in a way that doesn't cause data loss in ANY condition. I believe this bug can be fixed and we can have efficiency and guaranteed no data loss, and then the "Effect" and "Remedy" below would not be needed... But if it's not possible to guarantee no data loss, and the "Effect" is still a possibility, then this entire thing should be an OPTION. " Effect: some expressions, in particular divisions of integer values by floating point constants, may now default to a lower precision than in the past. " What This IS data loss!!! This precisely describes the BUG. This is the reason this should NEVER have been made the default for everyone, it should have required a compiler directive to turn on this behavior. This lower precision is in direct violation of the 'New behavior' statement! There is NO reason why anyone writing a Pascal program would expect this behavior. It's NOT the way Pascal has EVER behaved. " Remedy: if more precision is required than the default, typecast the floating point constant to a higher precision type, e.g. extended(2.0). Alternatively, you can use the -CF command line option to change the default precision of all floating point constants in the compiled modules. " This is unreasonable. How is anyone supposed to know that now to get it to work correctly as it should work, we need to cast out constants, old code should work the way it always did, and people writing new code will NEVER expect this needs to be done. On top of that the -CF option only works for -CF32 and -CF64 so its no solution for Extended.. why do I need a special option to do things correctly?' How about this.. if one variable is defined as a Double or Extended, then shut this 'feature' off, because it's asking for trouble. Nobody uses Doubles or Extended in a program because they want low precision results. Jame
Re: [fpc-pascal] Floating point question
>Jonas has argued, not without reason, that calculating everything always at full precision has its disadvantages too. I agree with that, and I do see the value in reducing the precision when it is possible, but not when it's causing data loss. The intention is perfectly fine, it's the execution that has a bug in it. I think that any reasonable person reading the following code would conclude that FF, GG, HH, and II should be exactly the same. I am defining constants, in FF I define variables of the same type to the constants, and it comes out correctly, in GG I use the constants directly, and its wrong. There is nothing about this that any programmer should understand because it's a bug. FF and GG are both adding an integer to a byte divided by a single, there is no difference to any reasonable programmer between what FF and GG are saying, and the programmer should not have to resort to ridiculous typecasting as in II to get almost the correct answer, but is still wrong. By the way notice that even with the casting, it's still wrong. II SHOULD have produced the right answer, because it's perfectly legitimate to divide a byte by a single and expect the answer to be an extended. program Constant_Bug; Const A_const = Integer(8427); B_const = Byte(33); C_const = Single(1440.0); Var A_Var : Integer; B_Var : Byte; C_Var : Single; FF, GG, HH, II : Extended; begin A_Var := A_Const; B_Var := B_Const; C_Var := C_Const; FF := A_Var+B_Var/C_Var; GG := A_Const+B_Const/C_Const; HH := Extended(A_Const+B_Const/C_Const); II := Extended(A_Const+Extended(B_Const/C_Const)); WRITELN ( ' FF = ',FF: 20 : 20 ) ; WRITELN ( ' GG = ',GG: 20 : 20 ) ; WRITELN ( ' HH = ',HH: 20 : 20 ) ; WRITELN ( ' II = ',II: 20 : 20 ) ; end. FF = 8427.022916625000 GG = 8427.022460937500 HH = 8427.022460937500 II = 8427.02291666716337204000 FF and II are correct, GG and HH are wrong. I understand now WHY this is happening, but I argue, that it's not obvious to anyone that it should be happening, it's just a hidden known bug waiting to bite you. No reasonable programmer would think that FF and GG would come out differently, the datatypes are all defined legitimately, and the same, the results should also be the same. In my opinion the changes in v2.2 break more things than they fix, and should be reverted, and used ONLY if asked for by a compiler directive, we should not have to do special things to get it to work correctly. If you give the compiler directive to use this feature, then you know you might have to cast some things yourself, but to apply this globally and then require a directive to not do it, is just not right, unless ALL code can be run the way it did pre 2.2 without modification, this is CLEARLY not the case. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question (Rafael Picanço)
This is my opinion from my testing, but others may have something else to say. 1) Does it affects constants only? Not really, if you set a variable with constant terms, it is affected, if you set a variable with other variables, it is not affected. Cont Mycontant := 8432+33/1440.0;//Is affected; Var MyDoubleVariable:Double; MyDoubleVariable := 8432+33/1440.0; //Is affected Var MyInteger : Ineger; MyByte : Byte MySingle : Single; MyDouble : Double; MyInteger := 8432; MyByte := 33; MySingle := 1440.0; MyDouble := MyInteger + MyByte / MySingle; // is NOT affected; 2) Does it affects the LargerFloat type? I don’t know what you mean by LargerFloat, but Double an d Extended are affected, and even Real if your platform defines Real as a Double. Anything that is not Single precision is affected. 3) Should I use {$MINFPCONSTPREC 64} in {$mode objfpc} too to avoid it? Everyone should use {$MINFPCONSTPREC 64} in all programs until the bug is fixed, unless you use extended, then you have no good solution. Because you can’t set it to 80. 4) BONUS: Is the LargerFloat type really the larger, or should one do something else? I’m afraid I don’t qualify for the bonus, because I don’t know what LargerFloat is. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
What's apparently happening now is: MyExtended := ReducePrecisionIfNoLossOfData (8246) + ReducePrecisionIfNoLossOfData (33.0) / ReducePrecisionIfNoLossOfData (1440.0); But it is not being done correctly, the 1440.0 is not being reduced all the way to an integer, because it was, everything would work. The 1440.0 is being considered a single, and the division is also being now considered a single, even though that is incorrect. But 1440.1 is not being considered a single, because 1440.1 is not breaking everything. What should be happening is: MyExtended := ReducePrecisionIfNoLossOfData(8246+33.0/1440.0); I just realized something... regardless of when or how the reduction in precision is happening, the bug is different than that, because the result of a byte divided by a single when stored in a double is a double, NOT a single, there should be no problem here, there is a definite bug. Consider this: program TESTDBL1 ; Const HH = 8427.02291667; Var AA : Integer; BB : Byte; CC : Single; DD : Single; EE : Double; FF : Extended; GG : Extended; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := AA+BB/CC; FF := AA+BB/CC; GG := 8427+33/1440.0; WRITELN ( 'DD = ',DD: 20 : 20 ) ; WRITELN ( 'EE = ',FF: 20 : 20 ) ; WRITELN ( 'FF = ',FF: 20 : 20 ) ; WRITELN ( 'GG = ',GG: 20 : 20 ) ; WRITELN ( 'HH = ',HH: 20 : 20 ) ; end. When I do the division of a byte by a single and store it in an extended, I get the division carried out as an extended. FF, GG, and HH should all be exactly the same if there is not a bug. But: DD = 8427.02246100 EE = 8427.022916625000 FF = 8427.022916625000 GG = 8427.022460937500 HH = 8427.022916625000 GG, the one with constants, is doing it wrong... If the entire formula was calculated the original way at full precision, then only result was reduced if there was no loss in precision right before storing as a constant, then this solves the problems for everyone, and this is the correct way to do this. Then everyone is happy, no Delphi warnings, no needlessly complex floating point computations if the result of all the math is a byte, and no confusion as to why it works with 1440.1 and not 1440.0 Compatibility with all versions of Pascal, etc.. This calculation is only done once by the compiler, the calculation should be done at full possible precision and only the result stored in a reduced way if it makes sense to do so. The problem I have with the changes made with v2.2, is that it's obvious that the change was going to introduce a known bug at the time: "Effect: some expressions, in particular divisions of integer values by floating point constants, may now default to a lower precision than in the past." How is this acceptable or the default?? "Remedy: if more precision is required than the default, typecast the floating point constant to a higher precision type, e.g. extended(2.0). Alternatively, you can use the -CF command line option to change the default precision of all floating point constants in the compiled modules." The first remedy is unreasonable, I should not have to go through thousands of lines of code and cast my constants, it was never a requirement of Pascal to do this. Great if -CF80 worked, but even if you are happy with -CF64, my problem is: how is anyone coming into FPC after 2.2 supposed to know that their constants that always worked before are going to no longer be accurate?? The better thing to do would be to do it RIGHT before releasing the change so that it can't be a problem for anyone, and make: "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" a true statement. If the entire formula was evaluated at full precision, and only the result was stored as a lower precision if possible, then there is never a problem for anyone. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I have the exact same intuition and expectation. I think this whole issue is easy to fix, just detect the .0s and cast them to integers by default instead of singles, because then everything does work fine. If I had a clue where the code for this might reduction in precision might be, I would try to fix it, but it's way over my head I'm afraid. I think the intention and theory behind doing it the new way is great, it just has this one flaw in it that could be fixed so the true behavior matches what is in the documentation, that things will be reduced that would not cause a loss in precision. That is true for almost all cases except when you put a .0 then it fails... it's losing precision. Reducing the .0 to an integer solves the problem... and I think if you had X = 2.0 it would be reduced to an integer or a byte, it's just when it's in a formula that it's getting set to a single, and that single is throwing everything off... it just wasn't reduced far enough. James -Original Message- From: fpc-pascal On Behalf Of Thomas Kurz via fpc-pascal Sent: Tuesday, February 6, 2024 7:53 AM To: 'FPC-Pascal users discussions' Cc: Thomas Kurz Subject: Re: [fpc-pascal] Floating point question Well, this is funny because I *did* compile it on DOS with Turbo Pascal 5.5, and I got the correct result there. Cross-compiling with FPC to msdos target gave the "wrong" (aka unexpected) result again. There were so many factors involved which caused great confusion. >From my point of view, an expression being an assigned to a variable of type "double" should be evaluated with double precision, not single. This is obviously the way integers are handled by internally using int64. A few weeks ago, I had incosistent behavior between x64 and x86 modes and it turned out that 32-bit code did internal castings to int64 thus resulting in the expected value whereas 64-bit cannot cast to int128 (because there is no int128) and thus gives an unexpected result (well, at least to me). So my intuition would (and obviously did!) expect double precision throughout the calculation. Kind regards, Thomas - Original Message - From: James Richters To: 'FPC-Pascal users discussions' Sent: Tuesday, February 6, 2024, 13:44:37 Subject: [fpc-pascal] Floating point question I don't think you were doing anything wrong, that's what I am simply trying to point out. If you ran your code on Turbo Pascal 7.0, you would not have an issue, it would be fine. There is no reason for a programmer to expect this behavior and it's very confusing when it does come up. There is a bug here and it should be acknowledged instead of defended. Discovering bugs is a good thing, it can lead to improvements to make the system better for everyone, but only if the discovery is learned from and acted upon. I'm sure everyone here can relate to how frustrating it can be to encounter a bug and have no idea whatsoever what the problem is. Undiscovered bugs are much worse than those which have been figured out. I think this is one that can be very frustrating for a lot of people, and it's very difficult to figure out what's happening, because everything happens correctly >99.9% of the time. If you put anything from x.001 to x.999 it has no problem, if you put x.0, you have a problem. Put as many decimals as you like to see why there is no reason why any programmer should expect this behavior. On top of that x has no problem, and many programmers use x.0 when x would have been fine, they are just in the habit of putting the .0 and in Turbo Pascal, there was never a problem with doing this. I am glad we at least have an explanation, but how many others are going to need to re-discover this issue that should not even be an issue? It can still be a problem for people who didn't happen to come across this. I didn't expect it to be an issue. While compiling with -CF64 or using {$MINFPCONSTPREC 64} fixes it for programs that use doubles, there is no good solution I can find for programs that use extended, because you can't put 80 into either of those. So for extended programs the only solution I can think of at the moment is to go through the WHOLE thing and replace all the x.0's with x Which I have started doing but it's a tedious chore. I appreciate the discussion here, because I had noticed inaccuracies from time but I was never able to get far enough in to realize this is what was happening. It's very frustrating indeed and I think if something can be done to save others this frustration and unexpected behavior, it would be helpful. James -Original Message- From: fpc-pascal On Behalf Of Thomas Kurz via fpc-pascal Sent: Tuesday, February 6, 2024 6:59 AM To: 'FPC-Pascal users discussions' Cc: Thomas Kurz Subject: Re: [fpc-pascal] Floating point question I'd li
Re: [fpc-pascal] Floating point question
I don't think you were doing anything wrong, that's what I am simply trying to point out. If you ran your code on Turbo Pascal 7.0, you would not have an issue, it would be fine. There is no reason for a programmer to expect this behavior and it's very confusing when it does come up. There is a bug here and it should be acknowledged instead of defended. Discovering bugs is a good thing, it can lead to improvements to make the system better for everyone, but only if the discovery is learned from and acted upon. I'm sure everyone here can relate to how frustrating it can be to encounter a bug and have no idea whatsoever what the problem is. Undiscovered bugs are much worse than those which have been figured out. I think this is one that can be very frustrating for a lot of people, and it's very difficult to figure out what's happening, because everything happens correctly >99.9% of the time. If you put anything from x.001 to x.999 it has no problem, if you put x.0, you have a problem. Put as many decimals as you like to see why there is no reason why any programmer should expect this behavior. On top of that x has no problem, and many programmers use x.0 when x would have been fine, they are just in the habit of putting the .0 and in Turbo Pascal, there was never a problem with doing this. I am glad we at least have an explanation, but how many others are going to need to re-discover this issue that should not even be an issue? It can still be a problem for people who didn't happen to come across this. I didn't expect it to be an issue. While compiling with -CF64 or using {$MINFPCONSTPREC 64} fixes it for programs that use doubles, there is no good solution I can find for programs that use extended, because you can't put 80 into either of those. So for extended programs the only solution I can think of at the moment is to go through the WHOLE thing and replace all the x.0's with x Which I have started doing but it's a tedious chore. I appreciate the discussion here, because I had noticed inaccuracies from time but I was never able to get far enough in to realize this is what was happening. It's very frustrating indeed and I think if something can be done to save others this frustration and unexpected behavior, it would be helpful. James -Original Message- From: fpc-pascal On Behalf Of Thomas Kurz via fpc-pascal Sent: Tuesday, February 6, 2024 6:59 AM To: 'FPC-Pascal users discussions' Cc: Thomas Kurz Subject: Re: [fpc-pascal] Floating point question I'd like to apologize, because my intention hasn't been to raise controverse discussions. I'm very thankful about the explanation. From the beginning, I knew that the error was on my side, but I didn't know *what* I'm doing wrong. Again, thanks for helping. Kind regards, Thomas - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Sunday, February 4, 2024, 18:25:39 Subject: [fpc-pascal] Floating point question I agree with Aadrian 100% "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" We are getting data loss So it's doing it WRONG. So we are all living with a stupid way of doing things so some Delphi code won't have warnings? Who came up with this??? The old way was CORRECT, instead of changing it for everyone making it wrong for most users, a compiler directive should have been needed to get rid of the warnings, or ONLY applied in Mode Delphi. Not to make everything incorrect for everyone unless you add a directive. The problem with this that no one is expecting to need to add a directive to do things right. Consider this: Var MyVariable : Extended; MyVariable := 8427 + 33 / 1440.0; Since I am storing the result in an Extended, I DO NOT EXPECT the 33/1440 to be a SINGLE, that is NUTS!! I expect it to be all done in Extended. Why would anyone expect the contents of MyVariable to be butchered by storing the 33/1440 in single precision. In other words I expect the result of these both to be the same: program TESTDBL1 ; Var AA : Extended; BB : Extended; CC : Extended; DD : Extended; EE : Extended; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := 8427+33/1440.0; WRITELN ( 'DD =' , DD : 20 : 20 ) ; WRITELN ( 'EE =' , EE : 20 : 20 ) ; end. But they are NOT DD =8427.022916625000 EE =8427.022460937500 EE is WRONG and can never be considered right. Why would ANY user with the code above expect that the 33/1440 would be done as a single, thus causing a loss of precision. Again: "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" This was NOT done in the
[fpc-pascal] FW: Floating point question
Sorry if this ends up being a duplicate, but I thought since it did not show up after a few hours that is was blocked because I had attached a screen shot to it. So here I removed the attachment and instead link to the screen shot: https://drive.google.com/file/d/1IJWSqR8UYgWRoq9oVwuOSa-XFd35FXZP/view?usp=s haring James -Original Message- From: James Richters Sent: Monday, February 5, 2024 7:26 AM To: 'FPC-Pascal users discussions' Subject: RE: [fpc-pascal] Floating point question I ran this program in Borland Turbo Pascal 7.0 for DOS, and it does not have this problem. AA, BB, and CC all produce identical results, But FPC, even with {$Mode TP}, produces different results if I use 1440 vs 1440.0 I guess Delphi compatibility is more important than Turbo Pascal compatibility even if I am in Turbo Pascal Mode? I wonder if Delphi even has this bug. I propose that all modes should use the old way and only Mode Delphi should do it the other way, Or better yet require a switch to allow the reduction in precision, instead of always doing it and requiring a switch to turn it off, because if you are using extended, you can't effectively turn it off as there is no -CF80, or best of all figure out why it's a bug, and fix the bug. The bug is that using something like 1440.0 causes single precision and a loss of data, while 1440 or 1440.1, or anything else that isn't .0 does not have this problem. Precision should never be sacrificed, and the user should not have to do something special to protect against a reduction in precision. When I learned Turbo Pascal back in the 90's this was never a thing, I never needed to cast my constants to prevent low precision results. It wasn't in my Turbo Pascal text book in technical school, because it didn't need to be, constants were always evaluated at full precision. Delphi came along and did something which could make sense in certain circumstances, and I agree it's probably an improvement, but it's being implemented slightly incorrectly. The stipulation that precision is reduced to the lowest precision that doesn't cause data loss is not being followed, we are getting data loss. I don't know if Delphi got it right, because I don't have Delphi, but there seems to be a real bug here. We should not be getting Data Loss, and things I have done for decades should still work the same as they used to, but they are defiantly not working the way they used to. Below is the program I tested with, With TP7, I never get a reduction in precision. 1440 and 1440.0 yield the same results, full precision evaluation of constants, and the result is never 8427.0224... Unless I put it into a variable defined as a single. Even then, there is never any difference between AA, BB, or CC for any given variable type. I could not cut and paste the results from TP7 because I am running it in DosBox, and I can't copy and paste from the DosBox window, but I put the screenshot as an attachment. I don't know if images will go through the mailing list, if not, I'll put it somewhere and link it. My argument is that I never needed to cast my constants before to avoid a loss in precision, it never even crossed my mind to think I would have to do that, it's not the way Pascal works. In Turbo Pascal if I do Writeln(33/1440); and Writeln(33/1440.0); I get the exact same thing. In FPC I get very different results. I didn't need to cast the 1440.0 in Turbo Pascal to prevent a loss of data, it's not necessary. It may be the way Delphi works, but I doubt Delphi has the loss of precision bug. 90% of my code was ported over from Turbo Pascal, I skipped Delphi and didn't make a windows version until FPC, and I have a LOT of units with {$Mode TP} that still have my original code. I don't know if Turbo Pascal reduced the precision of constants to gain performance, but I do know it was never a problem, I never had a reduction in precision. I think it's great to make improvement like this, and I'm all for gaining performance, but it needs to be implemented the way it was intended, and it needs to work, there should be no loss of precision, and I should not have to do something special to prevent the loss of precision, it should be precise by default. James program TESTDBL1 ; Const AA = 8427+33/1440.0; BB = 8427+33/1440; CC = 8427.02291667; Var A_Ext : Extended; B_Ext : Extended; C_Ext : Extended; A_Dbl : Double; B_Dbl : Double; C_Dbl : Double; A_Sgl : Single; B_Sgl : Single; C_Sgl : Single; begin A_Ext := AA; B_Ext := BB; C_Ext := CC; A_Dbl := AA; B_Dbl := BB; C_Dbl := CC; A_Sgl := AA; B_Sgl := BB; C_Sgl := CC; WRITELN ( 'A_Ext = ',A_Ext: 20 : 20 ) ; WRITELN ( 'B_Ext = ',B_Ext: 20 : 20 ) ; WRITELN ( 'C_Ext = ',C_Ext: 20 : 20 ) ; WRITELN; WRI
Re: [fpc-pascal] Floating point question
What is the proper way to use $EXCESSPRECISION ? I tried: program TESTDBL1 ; {$EXCESSPRECISION ON} Const TT_Const = 8427 + 33 / 1440.0 ; SS_Const = 8427 + Double(33 / 1440.0) ; Begin WRITELN ( 'TT_Const = 8427 + 33 / 1440.0 ; =' , TT_Const : 20 : 20 ) ; WRITELN ( 'SS_Const = Double(8427 + 33 / 1440.0);=' , SS_Const : 20 : 20 ) ; end. I get TT_Const = 8427 + 33 / 1440.0 ; =8427.02246100 SS_Const = Double(8427 + 33 / 1440.0); =8427.0229166671634000 I expected them to be both the same. James -Original Message- From: fpc-pascal On Behalf Of James Richters via fpc-pascal Sent: Sunday, February 4, 2024 10:52 AM To: 'FPC-Pascal users discussions' Cc: James Richters Subject: Re: [fpc-pascal] Floating point question Hi Jonas, That’s Interesting, Thank you very much for the links!! Not only an explanation but a solution. The original is how I would expect it to work, If it's for Delphi compatibility why not only do that when in Mode Delphi? If not in mode Delphi who cares if it's compatible? Delphi is completely wrong to do it this way. I'm glad there is $EXCESSPRECISION I am Immediately putting that in every single program I have, because that is I always thought it would work, and I do have divisions where this can be a problem. James -Original Message- From: fpc-pascal < <mailto:fpc-pascal-boun...@lists.freepascal.org> fpc-pascal-boun...@lists.freepascal.org> On Behalf Of Jonas Maebe via fpc-pascal Sent: Sunday, February 4, 2024 7:21 AM To: <mailto:fpc-pascal@lists.freepascal.org> fpc-pascal@lists.freepascal.org Cc: Jonas Maebe < <mailto:jo...@freepascal.org> jo...@freepascal.org> Subject: Re: [fpc-pascal] Floating point question On 03/02/2024 18:42, James Richters via fpc-pascal wrote: > Constants are also evaluated wrong,you don’t know what that constant > is going to be used for, so all steps of evaluating a constant MUST be > done in extended by the compiler, or the answer is just wrong. See <https://wiki.freepascal.org/User_Changes_2.2.0#Floating_point_constants> https://wiki.freepascal.org/User_Changes_2.2.0#Floating_point_constants and <https://www.freepascal.org/daily/doc/prog/progsu19.html> https://www.freepascal.org/daily/doc/prog/progsu19.html fpc-pascal maillist - <mailto:fpc-pascal@lists.freepascal.org> fpc-pascal@lists.freepascal.org <https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I got the -CF argument to work... it's not just -CF, it's is -CF and then the limiting precision... -CF32 for single, or -CF64 for double, but it won't take -CF80 so Extended still doesn't come out right. With -CF64 I get better results but it's not completely doing it the old way. BB = 8427+33/1440.0; comes out the same as doing: BB = Extended(8427+Double(33/1440)); which is 8427.0229166678793000 But BB = 8427+33/1440; still comes out right: 8427.022916625000 I still can't get $EXCESSPRECISION to work. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
So I need to do this? AA = Extended(8427+Extended(33/Extended(1440.0))); That seems excessive when BB = 8427+33/1440.1; Has no problem The thing I have an issue with is BB = 8427+33/1440.1; is done the way I want it to, and BB = 8427+33/1440.01; is done the way I want it to, and BB = 8427+33/1440;is done the way I want it to, but BB = 8427+33/1440.0; is done a different way. To me these should all be done the same way. And they would have all been done the same way before the 2.2 change, that change works for every case except when there is a .0, A .01 at the end is fine, a .001234 at the end is fine, its JUST .0 that's not fine. This is inconsistent, why didn't the 1440.1 version reduce to a single? It fits in a single, and I didn't specify it any differently than 1440.0. This lack of consistency is that's leading me to think it's more of a bug.. Everything I put in the denominator, other than something that ends with .0 works as I expect, it's ONLY when there is a .0 that things go wrong. Why is 1440.0 different that 1440.1? Say I have a program with some constants at the top, and the program has been working flawlessly for years, and now I change one Constant from something with a .001 in the denominator to a .000 in the denominator, I know it's lazy, just change the 1 to a 0 and don't delete the useless 0's after the decimal point, , but now I have all kinds of imprecision, but if I would have changed it to .001 instead, it is still fine, and anything other than .0 is fine. Why is .0 special and .1 is not? Having one single way to do it that causes drastically differently results is a bug, it should be consistent. That way when I'm testing I will see that I need to cast the denominator as an extended and it will always work the same way. It's this working different ways with nearly the same input that I have an issue with.When I learned Turbo Pascal in technical school, no one EVER said you need to cast your constants, and it wasn't in the text book either. All of my examples above should be processed the same way, if 1440.1 doesn't force single precision, then 1440.0 should not force single precision either. James -Original Message- From: fpc-pascal On Behalf Of Jonas Maebe via fpc-pascal Sent: Sunday, February 4, 2024 5:25 PM To: fpc-pascal@lists.freepascal.org Cc: Jonas Maebe Subject: Re: [fpc-pascal] Floating point question On 04/02/2024 23:21, James Richters via fpc-pascal wrote: > Shouldn’t this do all calculations as Extended? > > AA = Extended(8427+33/1440.0); No, this only tells the compiler to interpret the result as extended. Jonas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Shouldn’t this do all calculations as Extended? AA = Extended(8427+33/1440.0); It does NOT Const AA = Extended(8427+33/1440.0); BB = 8427+33/1440; CC = 8427.02291667; A_Ext = 8427.022460937500 B_Ext = 8427.022916625000 C_Ext = 8427.022916625000 A_Dbl = 8427.022460937500 B_Dbl = 8427.022916668000 C_Dbl = 8427.022916668000 A_Sgl = 8427.02246100 B_Sgl = 8427.02246100 C_Sgl = 8427.02246100 James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>> Not specifying in a program, specially in a strict programming language like >> Pascal, will always result in implementation depending >> variations/assumptions. The problem is, I feel that I DID specify what should be by declaring my variable as Extended. And Apparently FPC agrees with me, because it DOES work the way I expect, except if I put a .0 in my constant terms. This is all just a bug if you put .0 after any integers in an expression. I just put a better example that shows how it works correctly except if you put a .0 Strangely, upon discovering this, the solution is opposite what I thought it should be. If all the terms of an expression were reduced to the lowest precision possible without loosing data, then my 1440.0 would be reduced from a float to a word, and then the entire problem would have went away, because when I put in 1440 without the .0, there is no problem.The .0 is apparently defining it to be a floating point and the smallest floating point is a single… but that’s not the smallest data structure, the smallest data structure that can be used is a word and that would have solved it. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Here is a more concise example that illustrates the issue. For me, being a human, I see 1440 and 1440.0 as exactly the same thing, but they are not acting as the same thing, and the 1440.0 is causing all the grief here. See how it makes a difference whether the .0 is there or not. Then replace the 1440.1, and notice how it's no longer an issue, note it's only a problem with .0 if it's a .1, or anything other than .0, it seems fine. program TESTDBL1 ; Const AA = 8427+33/1440.0; BB = 8427+33/1440; CC = 8427.02291667; //Windows Calculator Var A_Ext : Extended; B_Ext : Extended; C_Ext : Extended; A_Dbl : Double; B_Dbl : Double; C_Dbl : Double; A_Sgl : Single; B_Sgl : Single; C_Sgl : Single; begin A_Ext := AA; B_Ext := BB; C_Ext := CC; A_Dbl := AA; B_Dbl := BB; C_Dbl := CC; A_Sgl := AA; B_Sgl := BB; C_Sgl := CC; WRITELN ( 'A_Ext = ',A_Ext: 20 : 20 ) ; WRITELN ( 'B_Ext = ',B_Ext: 20 : 20 ) ; WRITELN ( 'C_Ext = ',C_Ext: 20 : 20 ) ; WRITELN; WRITELN ( 'A_Dbl = ',A_Dbl: 20 : 20 ) ; WRITELN ( 'B_Dbl = ',B_Dbl: 20 : 20 ) ; WRITELN ( 'C_Dbl = ',C_Dbl: 20 : 20 ) ; WRITELN; WRITELN ( 'A_Sgl = ',A_Sgl: 20 : 20 ) ; WRITELN ( 'B_Sgl = ',B_Sgl: 20 : 20 ) ; WRITELN ( 'C_Sgl = ',C_Sgl: 20 : 20 ) ; end. A_Ext = 8427.022460937500 B_Ext = 8427.022916625000 C_Ext = 8427.022916625000 A_Dbl = 8427.022460937500 B_Dbl = 8427.022916668000 C_Dbl = 8427.022916668000 A_Sgl = 8427.02246100 B_Sgl = 8427.02246100 C_Sgl = 8427.02246100 Notice for Double and Extended they are getting the value for Single for the division, throwing off the result, but only with 1440.0, not with 1440 With the constants defined as: Const AA = 8427+33/1440.10; BB = 8427+33/1440.1; CC = 8427.0229150753419901395736407194; //Windows Calculator Now notice: A_Ext = 8427.02291507534198978000 B_Ext = 8427.02291507534198978000 C_Ext = 8427.02291507534198978000 A_Dbl = 8427.0229150753421000 B_Dbl = 8427.0229150753421000 C_Dbl = 8427.0229150753421000 A_Sgl = 8427.02246100 B_Sgl = 8427.02246100 C_Sgl = 8427.02246100 All versions of Extended, Double, and Single are identical. As expected. Everything I try works, except for .0 James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>No need to yell. Yes, that's true, I apologize, I did not mean to come across that way. >This is how reasonable programing languages work. The result type depends only on the type of the involved variables/expressions. *Never* the variable it is assigned to. If it's never defined by the variable it's assigned to, then maximum precision should be used, because you don't know how it will be used. I understand that the result depends on the variables and expressions, The problem with constants used in an expression is that some determination needs to be made because it's not specified. Since it's not specified, then I think it should be implied to be the same as the variable it would be stored in, if that determination cannot be made, then maximum precision should be used. In fact sometimes it does use the precision of the variable being assigned to look at this: program TESTDBL1 ; Var AA : Extended; BB : Extended; CC : Extended; DD : Extended; EE : Extended; FF : Extended; GG : Double; HH : Single; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := 8427+33/1440.0; FF := 8427+33/1440; GG := 8427+33/1440; HH := 8427+33/1440; WRITELN ( 'DD =' , DD : 20 : 20 ) ; WRITELN ( 'EE =' , EE : 20 : 20 ) ; WRITELN ( 'FF =' , FF : 20 : 20 ) ; WRITELN ( 'GG =' , GG : 20 : 20 ) ; WRITELN ( 'HH =' , HH : 20 : 20 ) ; end. DD =8427.022916625000 EE =8427.022460937500 FF =8427.022916625000 GG =8427.022916668000 HH =8427.02246100 For FF, GG, and HH, I did not put the .0, so it must have made them al integers... but now the division is carried out in the way that makes sense for the variable it's being stored in, it's only when I force the 1440 to be a float by putting the .0 on that it gets it wrong. But if it was supposed to be 1440.1 then I couldn't leave the .1 off and maybe I still have the issue but no.. I DON'T have it... it's only getting it wrong if it's 1440.0 Look at THIS: program TESTDBL1 ; Var AA : Extended; BB : Extended; CC : Extended; DD : Extended; EE : Extended; FF : Extended; GG : Double; HH : Single; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := Extended(8427+Extended(33/Extended(1440.1))); FF := 8427+33/1440.1; GG := 8427+33/1440.1; HH := 8427+33/1440.1; WRITELN ( 'DD =' , DD : 20 : 20 ) ; WRITELN ( 'EE =' , EE : 20 : 20 ) ; WRITELN ( 'FF =' , FF : 20 : 20 ) ; WRITELN ( 'GG =' , GG : 20 : 20 ) ; WRITELN ( 'HH =' , HH : 20 : 20 ) ; end. DD =8427.022916625000 EE =8427.02291507534198978000 FF =8427.02291507534198978000 GG =8427.0229150753421000 HH =8427.02246100 Just FYI, windows calculator gives 8427.0229150753419901395736407194 so I expect to get the following for this: FF =8427.02291507534198978000 GG =8427.0229150753421000 HH =8427.02246100 And YES that is what I get. Things are only broken if I put 1440.0 there is a bug in this condition. FF := 8427+33/1440.0; GG := 8427+33/1440.0; HH := 8427+33/1440.0; Windows calculator gets: 8,427.02291667 I expect to get: FF =8427.022916625000 GG =8427.022916668000 HH =8427.02246100 But no, I get: FF =8427.022460937500 GG =8427.022460937500 HH =8427.02246100 If I leave off the .0 then it's correct: FF := 8427+33/1440; GG := 8427+33/1440; HH := 8427+33/1440; FF =8427.022916625000 GG =8427.022916668000 HH =8427.02246100 I feel much better about it all now.. I think it's SUPPOSED to work the way I expect, but there is a bug if you put something like 1440.0 in your constant expression. Sorry again for my earlier tone. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I can understand storing the constant in the lowest precision that doesn't cause data loss, thus making thing more efficient, but the actual calculation done by the compiler should be done at maximum precision and only the final result stored in the lowest required precision. This calculation is only carried out buy the compiler once, during compilation, not by the executing program. The calculation should be done completely using extended, and if the result of the entire calculation is a 2, then store it as a byte, if it's 1.23 then store it as a single, and if it's 1.2324241511343 store it as Extended. The problem is the 33/1440 is being stored as a single and IS LOSING DATA, the division should have been detected and therefore the lowest precision that doesn't cause data loss is NOT a single. In all cases in our example, we should not be getting different values for the same constant. The implementation not the right way of doing it. It's not doing what is required by the statement: "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" The "New behaviour" has a DEFINATE bug in it, because we are experiencing data loss. The correct way to implement this is to have the compiler ALWAYS evaluate everything at highest precision, THEN after all computations are complete evaluate the final answer to store in the constant and reduce the precision of only the constant if it's justified. If it was done this way then it would always give the expected result. James -Original Message- From: fpc-pascal On Behalf Of Florian Klämpfl via fpc-pascal Sent: Sunday, February 4, 2024 8:20 AM To: FPC-Pascal users discussions Cc: Florian Klämpfl Subject: Re: [fpc-pascal] Floating point question > Am 04.02.2024 um 13:50 schrieb Adriaan van Os via fpc-pascal > : > > Jonas Maebe via fpc-pascal wrote: >> On 03/02/2024 18:42, James Richters via fpc-pascal wrote: >>> Constants are also evaluated wrong,you don’t know what that constant is >>> going to be used for, so all steps of evaluating a constant MUST be done in >>> extended by the compiler, or the answer is just wrong. >> See >> https://wiki.freepascal.org/User_Changes_2.2.0#Floating_point_constan >> ts and https://www.freepascal.org/daily/doc/prog/progsu19.html > > I think this discussion shows that the 2.2 compiler change was a bad idea > (for modes other than Delphi). The result with the old code was that all floating point operations involving constants were carried out in full precision (normally double or extended) which is something unexpected and results in slow code. Example: const c2 = 2; var s1, s2 : single; … s1:=s2/c2; generated an expensive double division for no good reason. OTOH: const c2 : single = 2; var s1, s2 : single; … s1:=s2/c2; generated a single division. There is still the -CF option as a workaround to get the old behavior. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
How do I get -CF to work with the Text IDE? I put -CF and just CF in "Additional Compiler Args" either way I get: Error: Illegal parameter: -CF James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I agree with Aadrian 100% "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" We are getting data loss So it's doing it WRONG. So we are all living with a stupid way of doing things so some Delphi code won't have warnings? Who came up with this??? The old way was CORRECT, instead of changing it for everyone making it wrong for most users, a compiler directive should have been needed to get rid of the warnings, or ONLY applied in Mode Delphi. Not to make everything incorrect for everyone unless you add a directive. The problem with this that no one is expecting to need to add a directive to do things right. Consider this: Var MyVariable : Extended; MyVariable := 8427 + 33 / 1440.0; Since I am storing the result in an Extended, I DO NOT EXPECT the 33/1440 to be a SINGLE, that is NUTS!! I expect it to be all done in Extended. Why would anyone expect the contents of MyVariable to be butchered by storing the 33/1440 in single precision. In other words I expect the result of these both to be the same: program TESTDBL1 ; Var AA : Extended; BB : Extended; CC : Extended; DD : Extended; EE : Extended; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := 8427+33/1440.0; WRITELN ( 'DD =' , DD : 20 : 20 ) ; WRITELN ( 'EE =' , EE : 20 : 20 ) ; end. But they are NOT DD =8427.022916625000 EE =8427.022460937500 EE is WRONG and can never be considered right. Why would ANY user with the code above expect that the 33/1440 would be done as a single, thus causing a loss of precision. Again: "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" This was NOT done in the lowest precision which doesn't cause data loss.. we lost data We are no longer Extended precision, anything at all we use EE for is WRONG. This is CLEARLY WRONG! The default should be the old way and if you don't like the Delphi warnings, you can make a switch to do it this new stupider and WRONG way. I strongly feel this should be reverted, it's just wrong. This makes no sense to me at all. It's wrong to need to add a compiler directive to do things as they are expected by the vast majority to be, the directive should be needed for those few who even noticed the warnings in Delphi, and they were just warnings, not a substantial reduction in precision. James >But not at the price of loss in precision ! Unless an explicit compiler switch >like --fast-math is passed ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Hi Jonas, That’s Interesting, Thank you very much for the links!! Not only an explanation but a solution. The original is how I would expect it to work, If it's for Delphi compatibility why not only do that when in Mode Delphi? If not in mode Delphi who cares if it's compatible? Delphi is completely wrong to do it this way. I'm glad there is $EXCESSPRECISION I am Immediately putting that in every single program I have, because that is I always thought it would work, and I do have divisions where this can be a problem. James -Original Message- From: fpc-pascal On Behalf Of Jonas Maebe via fpc-pascal Sent: Sunday, February 4, 2024 7:21 AM To: fpc-pascal@lists.freepascal.org Cc: Jonas Maebe Subject: Re: [fpc-pascal] Floating point question On 03/02/2024 18:42, James Richters via fpc-pascal wrote: > Constants are also evaluated wrong,you don’t know what that constant > is going to be used for, so all steps of evaluating a constant MUST be > done in extended by the compiler, or the answer is just wrong. See https://wiki.freepascal.org/User_Changes_2.2.0#Floating_point_constants and https://www.freepascal.org/daily/doc/prog/progsu19.html Jonas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I don't understand it either, the result of the 33/1440 is being stored in a single precision apparently, but it shouldn't be,. If TT is Double or Extended, then all parts of the evaluation of TT should be carried out in the same way, whether evaluated By the compiler or the program. That is what I expect, but that is not what is happening. program TESTDBL1 ; Const TT_Const = 8427 + 33 / 1440.0 ; SS_Const = 8427 + Double(33 / 1440.0) ; Var AA_Double : Double; BB_Double : Double; CC_Double : Double; DD_Double : Double; EE_Double : Double; FF_Double : Double; GG_Double : Double; HH_Double : Double; II_Double : Double; JJ_Double : Double; KK_Double : Double; SS_Double : Double; TT_Double : Double; VV_Single : Single; WW_Single : Single; XX_Single : Single; YY_Single : Single; ZZ_Single : Single; begin AA_Double := 8427; BB_Double := 33/1440; CC_Double := AA_Double+BB_Double; DD_Double := 8427 + 33 / 1440.0 ; VV_Single := 8427; WW_Single := 33/1440; XX_Single := VV_Single+WW_Single; YY_Single := 8427 + 33 / 1440.0 ; ZZ_Single := DD_Double; EE_Double := Double(8427 + 33 / 1440.0) ; FF_Double := 8427 + Double(33 / 1440.0) ; GG_Double := Double(8427) + Double(33) / Double(1440.0) ; HH_Double := Double(8427 + Single(33 / 1440.0)) ; II_Double := 33; JJ_Double := 1440; KK_Double := AA_Double+II_Double/JJ_Double; SS_Double := SS_Const; TT_Double := TT_Const; WRITELN ( 'AA_Double := 8427;=' , AA_Double : 20 : 20 ) ; WRITELN ( 'BB_Double := 33/1440; =' , BB_Double : 20 : 20 ) ; WRITELN ( 'CC_Double := AA_Double+BB_Double; =' , CC_Double : 20 : 20 ) ; WRITELN ( 'DD_Double := 8427 + 33 / 1440.0 ; =' , DD_Double : 20 : 20 ) ; WRITELN ( 'VV_Single := 8427;=' , VV_Single : 20 : 20 ) ; WRITELN ( 'WW_Single := 33/1440; =' , WW_Single : 20 : 20 ) ; WRITELN ( 'XX_Single := VV_Single+WW_Single; =' , XX_Single : 20 : 20 ) ; WRITELN ( 'YY_Single := 8427 + 33 / 1440.0 ; =' , YY_Single : 20 : 20 ) ; WRITELN ( 'ZZ_Single := DD_Double; =' , ZZ_Single : 20 : 20 ) ; WRITELN ( 'EE_Double := Double(8427 + 33 / 1440.0) ; =' , EE_Double : 20 : 20 ) ; WRITELN ( 'FF_Double := 8427 + Double(33 / 1440.0) ; =' , FF_Double : 20 : 20 ) ; WRITELN ( 'GG_Double := Double(8427) + Double(33) / Double(1440.0) ; =' , GG_Double : 20 : 20 ) ; WRITELN ( 'HH_Double := Double(8427 + Single(33 / 1440.0)) ; =' , HH_Double : 20 : 20 ) ; WRITELN ( 'KK_Double := AA_Double+II_Double/JJ_Double; =' , KK_Double : 20 : 20 ) ; WRITELN ( 'TT_Const = 8427 + 33 / 1440.0 ; =' , TT_Const : 20 : 20 ) ; WRITELN ( 'SS_Const = Double(8427 + 33 / 1440.0);=' , SS_Const : 20 : 20 ) ; WRITELN ( 'TT_Double := TT_Const;=' , TT_Double : 20 : 20 ) ; WRITELN ( 'SS_Double := SS_Const;=' , SS_Double : 20 : 20 ) ; end. AA_Double := 8427; =8427. BB_Double := 33/1440; =0.02291500 CC_Double := AA_Double+BB_Double; =8427.022916668000 DD_Double := 8427 + 33 / 1440.0 ; =8427.022460937500 VV_Single := 8427; =8427. WW_Single := 33/1440; =0.022916667160 XX_Single := VV_Single+WW_Single; =8427.02246100 YY_Single := 8427 + 33 / 1440.0 ; =8427.02246100 ZZ_Single := DD_Double; =8427.02246100 EE_Double := Double(8427 + 33 / 1440.0) ; =8427.022460937500 FF_Double := 8427 + Double(33 / 1440.0) ; =8427.0229166671634000 GG_Double := Double(8427) + Double(33) / Double(1440.0) ; =8427.022916668000 HH_Double := Double(8427 + Single(33 / 1440.0)) ; =8427.022460937500 KK_Double := AA_Double+II_Double/JJ_Double; =8427.022916668000 TT_Const = 8427 + 33 / 1440.0 ; =8427.02246100 SS_Const = Double(8427 + 33 / 1440.0); =8427.0229166671634000 TT_Double := TT_Const; =8427.022460937500 SS_Double := SS_Const; =8427.0229166671634000 I would actually expect values that were calculated by the compiler to ALWAYS be done in
Re: [fpc-pascal] What's in Hello World
>Try building with smartlinking, -XX I never knew there was an option for smartlinking. I'm using the FPC text IDE, I see various options like Generate Smaller Code, and level 1, 2, and 3 optimizations, but I don't see anything specifically called smartlinking. Is it the same as Generate Smaller Code? or if not, is there another way to turn it on in the textmode IDE? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Profiling in windows
I have a freepascal project for Windows that works really well, but as soon as I start it, I have high CPU usage, and it stays high, it constantly uses 10% CPU while my program is running, even when it's idle waiting for me to make a selection from its menu. The main program loop does a few minor things like update the time on the screen, checks some timers, checks for a keypress, then sleeps until it's time to do the loop again. I'm wondering if its getting stuck in some inefficient routine that's causing all this processor activity. This program only runs under Windows so I'm trying to get a profiler to work with a windows program. I came across FPProfiler: https://wiki.freepascal.org/FPProfiler I'm trying to figure out how it's supposed to work but I haven't made it very far. The instructions say to use Lazarus to build the following: .\fpp\fpp.lpi .\fpp\fppinsert.lpi .\fpp\fppremove.lpi .\fppview\fppview.lpi But only .\fpp\fpp.lpi and .\fppview\fppview.lpi exist, so I compiled those with Lazarus. I am using the repository at: http://github.com/graemeg/fpprofiler The svn link doesn't work for me: http://svn.freepascal.org/cgi-bin/viewvc.cgi/fpprofiler/?root=fpcprojects Also, the instructions say," to compile your project, you pass the same parameters to FPP as you would to FPC." I don't use FPC from the command line, I use the FPC textmode IDE. Which I have set up the way I like it years ago. Is there some way to know what parameters the text mode IDE is using? Or What would the command line be to compile the same way as the IDE? Any advice on how to get this to work, or recommendations on another way I can profile my program under Windows is greatly appreciated. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
>Writeln() is special. You cannot duplicate it. That's good to know, I can stop trying. >What you can do is use WriteStr(), it has the same action as Writeln() but writes to a string instead of a file. I was hoping to just replace all existing Writeln()s with my procedure with a global search and replace. I think it's probably easiest to make my procedure: Procedure WriteLog(Filename:String, WriteString:String); Begin Writeln(Filename,WriteString); Writeln(WriteString); End; Then just fix the call to concatenate everything into a single string: So if I end up with this: WriteLog(Myfile,'some text ',MyInteger); I'll have to change it to this: WriteLog(Myfile,'some text '+InttoStr(MyInteger)); And if the arguments are really complicated I can just use WriteStr() to store it into a string and call my procedure with the resulting string. It will be a little more effort than doing a global search and replace but at least I know that it's the only way. Thanks for the help James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Procedures that work like WRITELN()
I wanted to write what I thought should be a simple procedure, just instead of calling WRITELN() with some arguments, call WRITELOG() with the same arguments that you would use to write to a file, but my WRITELOG() procedure would write to the screen and the file.. but I can't figure out how to pass all the arguments to the two WRTIELNs. So.. Procedure WriteLog(Filename:String, AllOtherAurguments:); Begin Writeln(Filename,AllOtherAurguments); Writeln(AllOtherAurguments); End; How can I make this work? Since WRITELN can take any number of many kinds of arguments, how can I get them all and pass them along without knowing how many or what types they are? How does WRITELN even work when you don't know this information? I'm guessing there should be some way to do this, because WRITELN itself works, but how it could possibly work is not within my experience. The only way I could think of would be if there were versions of WRITELN with every combination of possible arguments, but that seems completely unmanageable and ridiculous, so there must be something more advanced going on, but maybe WRTELN is special and not something I can duplicate? Any Ideas? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Strings greater than 255 characters
>3) There are some other smaller differences impacting compatibility with code designed to work with type shortstring (e.g. related to used character sets etc.). Here's a difference I discovered... I see that if I try to do something like: If MyString[1]='~' Then ... If MyString is an AnsiString that is empty then you get a rangecheck error, which is understandable as there is nothing in character 1, but If MyString is just a String and is empty then it runs just fine so I have a lot of those kinds of things. So some of these I just changed them back to a string for now, but If I want to change them anyway then I just do If (Length(MyString)>0) and (MyString[1]='~') Then ... And that fixes the issue as well, and it's probably better code as I shouldn't be testing a particular character if there isn't a character there. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Strings greater than 255 characters
I keep getting bit by using STRING variables then trying to store more than 255 characters. My typical way to fix this is to just change it to an ANSISTRING. I'm wondering if there is any reason not to do this the other way around and just go through My entire program and replace all the STRING variables with ANSISTRNG? It's likely that I would solve a lot of future problems that I don't even know I have yet if I did this. Is there any reason not to change all the Strings to Ansistrings? I did notice that I cannot have a file of Ansistrings. Myfile : File of Ansistring; Causes a compiler error: Error: Typed files cannot contain reference-counted types. So maybe this could be a problem. Is there a way to make a file of strings that are not limited to 255 characters? Also I can make records that contain Ansistrings, but I can't make files of those records, for the same reason as above. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] case statement
I have occasionally had ambiguity with ELSE, for example when you have IF statements nested inside other IF statements, sometimes the ELSE is seen as part of the inner, not the outer, or vice versa, depending on where the one-liners are but I just resolve it with some BEGIN - END Blocks, even if they are not actually needed because there is only one line, ambiguity resolved. For years I have just been in the habit of always putting BEGIN and END on all IF and ELSE statements, as well as all entries of CASE statements, whether needed or not, just because it's so much easier to stick in some temporary diagnostic code if needed, it's easier to just always have them and not have to add them later if you want to do a second thing, which always seems to be happening. I guess that's why I never noticed there could be an issue with CASE statements. It is handy to know about OTHERWISE though, I'll probably throw it in just to help remind me that this belongs to the CASE Statement, and not part of some IF, maybe it will be more readable that way. James -Original Message- From: fpc-pascal On Behalf Of Martin Wynne via fpc-pascal Sent: Thursday, December 14, 2023 3:16 PM To: fpc-pascal@lists.freepascal.org Cc: Martin Wynne Subject: Re: [fpc-pascal] case statement I've been using ELSE in IF statements and in CASE statements for 25 years without realising there was a problem. What a dim-wit I have been. Martin. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] case statement
I didn’t know there was such a thing as OTHERWISE. Is there any functional difference between OTHERWISE and ELSE? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
I changed to Compiler Version 3.3.1-12875-gadf843196a which is what FPCUPDeluxe installed when I installed Trunk and now it runs just fine. So I guess there was a bug in 3.3.1-10077-gc8403ad49e that was fixed already. I was so convinced that I was doing something wrong I didn't even think to try another version. >Because I use a screen reader, I have multiple sapi voices installed, (though I rarely use them), but I haven't played with the code enough just yet to see why it fails when it tries to select one, when not selecting one works just fine Here's a sample program that now works on the updated 3.3.1, I guess it should work on 3.2 as well. It lists all available voices and lets you choose one. Maybe that would let you select another voice? {$Mode OBJFPC} program VoiceSelection; uses ComObj; var v: OleVariant; selectedVoiceIndex: Integer; voiceName: string; speechText: string; begin v := CreateOleObject('SAPI.SpVoice'); Writeln('Available Voices:'); for selectedVoiceIndex := 0 to v.GetVoices.Count - 1 do begin voiceName := v.GetVoices.Item(selectedVoiceIndex).GetDescription; Writeln('Voice ', selectedVoiceIndex + 1, ': ', voiceName); end; Writeln; Writeln('Enter the index of the voice you want to use:'); Readln(selectedVoiceIndex); if (selectedVoiceIndex < 1) or (selectedVoiceIndex > v.GetVoices.Count) then begin Writeln('Invalid voice index.'); Exit; end; voiceName := v.GetVoices.Item(selectedVoiceIndex - 1).GetDescription; v.Voice := v.GetVoices.Item(selectedVoiceIndex - 1); Writeln('Selected Voice: ', voiceName); speechText := 'Hello World, this is ' + voiceName; Writeln('Speech Text: ', speechText); v.Speak(speechText); end. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
Well that's worth a lot, it may be indicating a bug in 3.3.1? I guess I need to get on the current trunk to see if it's still misbehaving. James >Also, for what it's worth, your code works fine on fpc 3.20. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
I was using OleVarient and Varient. How can I check to see if CreateOleObject was successful? James >It sounds like " SpVoice := CreateOleObject('SAPI.SpVoice');" is failing and >then SpVoice is nil ? >May be try with an OleVariant instead of a simple Variant ? (i.e declare var >SpVoice: OleVariant; ) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
When I run the code below I get: An unhandled exception occurred at $004143C0: ■ Free Pascal IDE Version 1.0.12 [2022/02/07] ■ Compiler Version 3.3.1-10077-gc8403ad49e ■ GDB Version GNU gdb (GDB) 7.2 Running "i:\programming\sapi.exe " EOleError: Variant does not reference an automation object $004143C0 $004194DD $0040B991 $0040193B SPEAK, line 13 of i:/programmingl/sapi.pas $00401962 main, line 17 of i:/programming/sapi.pas program voice; uses comobj; procedure speak(s : string); var v : olevariant; begin v:=CreateOleObject('SAPI.SpVoice'); v.Speak(s); end; begin speak('Hello.'); end. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
I appreciate the help with this. I'm still confused. In my original post, I already had CoInitialize, CoUninitialize; and Unit ComOBJ, Unit Windows and Unit ActiveX I was still getting EOleError: Variant does not reference an automation object. Do I need to do all this Change FPU stuff? I'm sure I'm doing something wrong but I still can't get it to work. Here's my original program. I wasn't even trying to change the voice yet. What do I need to do to this to make it work? James {$mode objfpc} uses CRT, Windows, SysUtils, ComObj, Variants, OLEServer, Classes, ActiveX, ShellApi; var SavedCW: Word; SpVoice: Variant; MyWideString: WideString; begin CoInitialize(nil); SpVoice := CreateOleObject('SAPI.SpVoice'); MyWideString := WideString('Hello, the time is ' + TimeToStr(Now)); Writeln(MyWideString); // Change FPU interrupt mask to avoid SIGFPE exceptions SavedCW := Get8087CW; try Set8087CW(SavedCW or $4); SpVoice.Speak(MyWideString, 0); finally // Restore FPU mask Set8087CW(SavedCW); end; Writeln('Press Any Key'); ReadKey; CoUninitialize; end. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
I was trying to figure this out on my own.. I went to: https://wiki.freepascal.org/SAPI that is where I got my advice. I took the top example code from the link and made it into the following program: {$Mode OBJFPC} uses comobj; var SavedCW: Word; SpVoice: Variant; begin SpVoice := CreateOleObject('SAPI.SpVoice'); // Change FPU interrupt mask to avoid SIGFPE exceptions SavedCW := Get8087CW; try Set8087CW(SavedCW or $4); SpVoice.Speak('hi', 0); finally // Restore FPU mask Set8087CW(SavedCW); end; end. It fails with Running "i:\programming\gcode\mill\sapi.exe " An unhandled exception occurred at $004143F0: EOleError: Variant does not reference an automation object $004143F0 $0041950D $0040B9A1 $00401931 main, line 13 of I:/Programming/Gcode/Mill/SAPI.pas I don't have Lazarus, just FPC. I have been going nuts trying to track down this unhandled exception. I tried to make your example into a FPC program without Lazarus: {$mode objfpc}{$H+} uses comobj; var SavedCW: Word; v: OleVariant; begin v:=CreateOleObject('SAPI.SpVoice'); v.Speak('Hello'); End. I get: Running "i:\programming\gcode\mill\sapi.exe " An unhandled exception occurred at $00414370: EOleError: Variant does not reference an automation object $00414370 $0041948D $0040B941 $004018DF main, line 9 of i:/programming/gcode/mill/sapi.pas I have tried to trace through with F7 I get a message that "Program generated a signal 291... " and then the IDE terminates I still do not have an example I can compile and run from the FPC IDE (without Lazarus) >I don't know what people advised you, but what you want to do needs 3 lines of >code only: ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
I gave up on doing it directly, it seems SO convoluted to do with FPC with the COM unit and all this stuff I just don’t understand, and it’s SO simple to do with a VBS script in just 3 lines and it just works! (it would only be 2 lines if I didn’t want Microsoft Zira) So I decided to do this in the most ridiculous way possible.. but after 3 days of trying to get send something directly to SAPI with FPC , I’m done with it, and getting this to work was super easy. Computers are fast enough that I don’t need to waste my time tying to figure this out, just have FPC write out a VBS script, and run it with Process.Execute problem solved! Here it is, maybe it will help someone else struggling to get something so simple to work: {$mode objfpc} Program Zira; Uses SysUtils, Classes, Process; Procedure Zira(ZiraZtring: AnsiString); Var ScriptText: TStringList; Process: TProcess; Begin ScriptText := TStringList.Create; ScriptText.Add('Set objVoice = CreateObject("SAPI.SpVoice")'); ScriptText.Add('Set objVoice.Voice = objVoice.GetVoices().Item(1)'); ScriptText.Add('objVoice.Speak "' + ZiraZtring + '"'); ScriptText.SaveToFile('ZiraScript.vbs'); Process := TProcess.Create(nil); Process.Executable := 'WScript.exe'; Process.Parameters.Add('ZiraScript.vbs'); Process.Execute; Process.WaitOnExit; ScriptText.Free; DeleteFile('ZiraScript.vbs'); End; Begin Zira('Hello World'); End. From: fpc-pascal On Behalf Of Rafael Picanço via fpc-pascal Sent: Sunday, June 25, 2023 2:17 PM To: fpc-pascal@lists.freepascal.org Cc: Rafael Picanço Subject: Re: [fpc-pascal] Microsoft SAPI on Freepascal Hi James, I am not familiar with variants and Ole objects, sorry about that. I found some people using code with Ole objects and it that seems to work, can you chack if it applies to your case? https://stackoverflow.com/questions/17970573/using-word-ole-in-lazarus-freepascal Best, R ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
So it’s broken? It seems like the link you provided is trying to show a workaround, but I don’t know how I could apply that. >"Remark Dispatch interface support for variants is currently broken in the >compiler." (https://www.freepascal.org/docs-html/ref/refsu20.html) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Microsoft SAPI on Freepascal
Ooops forgot the link: https://wiki.lazarus.freepascal.org/SAPI From: fpc-pascal On Behalf Of James Richters via fpc-pascal Sent: Sunday, June 25, 2023 8:52 AM To: 'FPC-Pascal users discussions' Cc: James Richters Subject: [fpc-pascal] Microsoft SAPI on Freepascal I am trying to get Microsoft speech synthesis to work with Freepascal. I am trying to follow the guide here: I don't know what I am doing wrong. SAPI is working on my system, because the TTSApp Demo that comes with the Microsoft Speech SDK works fine. Here is my test program: {$mode objfpc} uses CRT, Windows, SysUtils, ComObj, Variants, OLEServer, Classes, ActiveX, ShellApi; var SavedCW: Word; SpVoice: Variant; MyWideString: WideString; begin CoInitialize(nil); SpVoice := CreateOleObject('SAPI.SpVoice'); // Change FPU interrupt mask to avoid SIGFPE exceptions MyWideString := WideString('Hello, the time is ' + TimeToStr(Now)); Writeln(MyWideString); SavedCW := Get8087CW; try Set8087CW(SavedCW or $4); SpVoice.Speak(MyWideString, 0); finally // Restore FPU mask Set8087CW(SavedCW); end; Writeln('Press Any Key'); ReadKey; CoUninitialize; end. Whenever my program gets to: SpVoice.Speak(MyWideString, 0); Even if I hardcode something like: SpVoice.Speak('Hello', 0); I always get: Running "i:\programming\TTS.exe " Hello, the time is 8:41:27 An unhandled exception occurred at $0041FC90: EOleError: Variant does not reference an automation object $0041FC90 $00424DAD $0040BB31 $00401A8A main, line 21 of i:\programming\TTS.pas I don't really understand what this means, and I can't find a complete sample program that I can just compile and run. I feel I must be missing something but I don't know what it is. Any help is greatly appreciated! James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Microsoft SAPI on Freepascal
I am trying to get Microsoft speech synthesis to work with Freepascal. I am trying to follow the guide here: I don't know what I am doing wrong. SAPI is working on my system, because the TTSApp Demo that comes with the Microsoft Speech SDK works fine. Here is my test program: {$mode objfpc} uses CRT, Windows, SysUtils, ComObj, Variants, OLEServer, Classes, ActiveX, ShellApi; var SavedCW: Word; SpVoice: Variant; MyWideString: WideString; begin CoInitialize(nil); SpVoice := CreateOleObject('SAPI.SpVoice'); // Change FPU interrupt mask to avoid SIGFPE exceptions MyWideString := WideString('Hello, the time is ' + TimeToStr(Now)); Writeln(MyWideString); SavedCW := Get8087CW; try Set8087CW(SavedCW or $4); SpVoice.Speak(MyWideString, 0); finally // Restore FPU mask Set8087CW(SavedCW); end; Writeln('Press Any Key'); ReadKey; CoUninitialize; end. Whenever my program gets to: SpVoice.Speak(MyWideString, 0); Even if I hardcode something like: SpVoice.Speak('Hello', 0); I always get: Running "i:\programming\TTS.exe " Hello, the time is 8:41:27 An unhandled exception occurred at $0041FC90: EOleError: Variant does not reference an automation object $0041FC90 $00424DAD $0040BB31 $00401A8A main, line 21 of i:\programming\TTS.pas I don't really understand what this means, and I can't find a complete sample program that I can just compile and run. I feel I must be missing something but I don't know what it is. Any help is greatly appreciated! James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Size of set.
>You can transverse a set with > for ... in Interesting, I learned something new, I did now know I could do this with FreePascal. It says it works for Strings and Arrays as well, does it also work for StringLists? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Windows Display Settings
Is there some way with FreePascal that I can Get / Set the windows display settings for multiple monitors like their resolutions, portrait/landscape, scale factors, and if they are disconnected or not? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Pause Key
It occurs to me that since Pause is independent of keypressed, I could actually us it as an extra modifier key if I wanted to... "Pause-A" could be different than "A", and also different than "CRTL-A" or "ALT-A", in fact I could do "Pause-CTRL-ALT-A" and have that be different than "CTRL-ALT-A" I could have all kinds of secret command key combinations and no one would ever discover them because almost nobody ever pushes the pause key anymore, and even if they do, even fewer people would ever uses it as a modifier. Fun! ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Pause Key
>> ... I wouldn't be surprised that James's program is a console one, not using TForm nor any windows message loop to process WM_ messages, but I may be wrong. Indeed you are correct, it is a very extensive console application which uses PTCGraph. I do accept keyboard input on both the Console window and the PTCGraph window. I have a keytest function that I can run in my application that reports the returned keycodes every time a key is pressed in either window, but pushing the Pause key is the same as doing nothing, it does not trigger keypressed. However I was already doing: isShiftDown := GetAsyncKeyState(VK_Shift); because I want to know if shift was held down, I can't rely on just if I get a capital or lower case letter because caps lock might be on, and I want my key command to work the same regardless of caps lock. So I just added a new function that does: isPausePushed := GetAsyncKeyState(VK_PAUSE); and check the pause key every time I check for keypressed (instead of inside keypressed) and if it finds it, it executes my Pause routine. It's working GREAT! So Thank you for the help getting it to work in my console program! Pause is Back!! Now I can use F12 for something more useful. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Pause Key
Does anyone know what's up with the Pause key in Windows? Is there some way to tell if it was pushed? I have a need for the user to pause execution of my Freepascal program, I have a pause key.. seems like there should be some way to use it. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Save and Restore Windows 10 Display configuration?
Is there some way I can programmatically use FreePascal to save and Restore all the settings found in the Windows 10 Display settings such as the resolution and position of each monitor and if they are enabled or not? ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] For Loop with QWord
I'm wondering why I can't have the following: Var I: QWord; Begin For I := 1 To N Do . It generates an error: Error: Ordinal expression expected If I change it to LongInt, then it works, but the question is, why can't I use a Qword here if I know I will never need I to be a negative number? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Working on a new way to educate people about pascal
I don’t know how my previous message got so out of sequence. I am not intending to continue this discussion, it was a message I sent early Thursday morning that was somehow delayed and is out of sequence. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Working on a new way to educate people about pascal
>Assuming people in that sentence, you are referring to people who use write >programs or scripts which make use of databases, if you know very little about >the subject of databases on that subject, how can you justify this assertion? The ‘People’ I was referring to are any people who work with databases in any way… when you go to the store to return something without a receipt, the customer assistance representative looks up your order on some kind of database system that stores all the transactions and is somehow able to retrieve yours without knowing SQL.. they are using the database, but know nothing of how it work and would never know what SQL was. >I suggest you either brush up on these subjects or refrain from scolding >people on subjects with which you have no practical experience. I apologize if you feel I was scolding you, that was not my intention. I thought we were just having a discussion about it. You can’t understand why anyone would say this is a complicated subject and I was simply trying to somehow show you a point of view that you do not seem to understand. My lack of experience is what qualifies me to evaluate your material better than you, because if I was familiar with the subject, I would fall into the same trap… “well this is just obvious, everyone should follow this.” I was under the impression that you wanted honest feedback, and that’s what I have been trying to provide, and I am very sorry if I have offended you. As a software developer, I have learned from experience, that I am the absolute WORST person to test my own programs. Why is that? It’s because I wrote them, I know what they are supposed to do and what input to give them to get the desired result. I have no possible way to truly forget what I have put in there, and so I am not capable of trying to do it in a way someone else might try to do it. When I make a release to my beta testers, it’s normal that they will try to do things THEIR way and often they will not understand why the sequence they tried didn’t yield the expected result. At this point, I could do a few different things, I can just explain to my beta testers why it didn’t work the way they wanted it to, and show them what would have worked. That is not an ideal approach, because if my testers wanted to make it work that way, then maybe ALL of my customers also want it to work that way, or maybe 10% of them want it to work that way. A much better solution is to listen to my testers and learn from them, and create a program that works in the way that was intuitive to THEM, not me. The best solution would be to get it to work the way I originally wanted it to work and also the way they tried to test it at the same time, then all of my customers would get the expected results So when I get feedback from my beta testers, I do not get defensive and justify why I did it the way that I did. I don’t try to teach them the way they should have done it. I listen to their extremely valuable feedback and try to incorporate that feedback into the product. They are giving me a point of view that I cannot ever possibly have, because when it comes down to it, I can’t ever think the way they do. It’s only through communicating with my testers that I can ever see that other point of view. This other point of view is SO valuable, that I have trashed months of work on a project and re-wrote entire huge sections to make fundamental changes so that it would work the way someone other than myself might want to accomplish something. I was simply trying to offer you that other point of view. Again, I am very sorry if I offended you. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Working on a new way to educate people about pascal
>Well, this discussion has not gone well at all! I agree >I suggest that everyone relax and discontinue pursuing it. I apologize to Anthony and everyone on the list for getting too carried away. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Working on a new way to educate people about pascal
>It shouldn't be confusing to anyone who has been programming for decades. It is very confusing if you never had a need for any kind of database.. which I do not…. And neither do many other programmers. Databases are only a very small part of what people use computers for, and only a very small part of people who use Databases use SQL... it's a VERY Specific topic. I do motion control and industrial machinery automation. I get into very timing critical applications with heavy calculations and digital communications with various electronic devices, and graphical display of the processes involved in various manufacturing processes. Absolutely nothing I have done in my entire career has required any kind of database whatsoever. I think I did some database stuff in COBOL in high school… and it didn’t use SQL.Without having a need for a database, my high school exposure to databases is all the education I have ever had on them… they are simply not anything I actually use or care about… so when I look at your SQL Monitor screen shot, "Where not (exists (Select1 bla bla bla.. well that's not something I recognize or understand the usefulness of.. it's another language on it's own and has nothing to do with anything I would ever use a computer for. You are completely missing the point.. which is, if your target audience is: “anyone who either isn't familiar with writing computer software or perhaps is not acquainted with Free Pascal.” Then you are introducing Free Pascal using an advanced topic that none of your audience will understand or appreciate, because if they aren’t “familiar with writing computer software” then they defiantly will have no idea what you are talking about.. and they, like myself, can’t relate to it. If people can’t make a connection with the subject, they are don’t even going to finish reading your article, and are defiantly not going to be inspired to download Free Pascal and try to write some code. For a sample program, you really need a simple subject that is interesting to any random person, and easy to understand code that is easily duplicatable. So if the reader finds value in what you have presented, and they are inspired to give it a try, which is the goal of your introduction, then they need sample code they can literally cut and paste into the Free Pascal IDE and run it for themselves, then they can see how it works, follow along, and customize it, and from there… who knows. But in your example, they would already have to have some kind of SQL database up and running to have a need for such a thing or to understand anything at all about the sample application.. it just doesn’t apply at all to most of your target audience. If your intention was: "This short program guide is designed as an introduction to the Free Pascal programming language for any SQL users who are not acquainted with Free Pascal." Then the subject is more relevant to your now much smaller target audience, but it still lacks the ability of the reader to make their own SQL monitor with the information presented on your page.. because you have snippets of code.. they can copy and paste them.. but how? Where? How do you combine these snippets of code into a functional program? It’s not obvious based on the information provided where these code blocks go, and how do they combine to make a complete working application? If the reader can’t easily duplicate your sample program and follow along and run it on their own computer, how are they going to be inspired to go further? And if you really want to reach your target audience, of “anyone who either isn't familiar with writing computer software” then even if you gave them a download for all the source files and an executable with an installer… they still can’t run it and make it work on their own computer because they would have to also install SQL, and set it all up to have something to monitor.. so now they need to learn 2 new systems, SQL and Free Pascal.. or 3 if we want to count Lazarus, which is entirely different than just Free Pascal on its own. To be an effective writer, you need to forget everything you know, and consider who the typical reader is and put yourself in their place and then evaluate what you are trying to accomplish form the READER's point of view.If you showed this to 100 random people, how many of them would make any kind of a connection to it? How many would say, I can see the value in this, maybe I should give it a try? How many people that fall into the “anyone who either isn't familiar with writing computer software" category are going to have a clue what you are talking about?The point I was trying to make is that even with my background in programming, I don't know what you are talking about... at all, not even after your explanations... because I can't connect to the subject in even the slightest way, the only database I ever use is the one
Re: [fpc-pascal] Working on a new way to educate people about pascal
“James, when you raised these questions are you saying that you don't know, or that someone who doesn't know much if anything about programming doesn't know” The point I was trying to make is that most of this is gobbely gook to me. So I went looking for something I could recognize.. and I saw a reference to a timer, but the only thing we know about it from the article is that there is a timer and it needs to get closed, and that TSqlForm.CloseTimerTimer closes it, and that is IT. We don’t know how it got started, how much time it was for, why it needs to close, or why in fact there is a timer at all… the reason I brought up the timer is because it was the only thing I could really see that an average person would recognize as maybe being useful in their own lives. Anyone who could understand what SQL was from the link you provided or understand what the program is even supposed to do, really doesn’t need an introduction to Pascal. I’m not trying to say that the idea itself is bad, in fact I do like the way you have links that show specific lines to help with the explanation. I’m just saying, the sample program needs to be on a MUCH simpler subject.. something that an average person who is not a computer scientist can understand. A subject that a middle school student could understand and see the value of. I went way beyond what your potential readers would ever do, and went to Wikipedia to see what SQL was and I even tried to follow some of the code and unfortunately I just couldn’t follow any of it at all. It seems to be just pieces of programs but the reader can’t understand how they relate to each other or how it all works.. it’s too complicated. It really needs to be just a single program that starts with does something understandable, that the reader could easily copy and paste and play with and understand, not a bunch a pieces of code that the reader can’t figure out how these separate pieces relate to each other. That is why Michael mentioned having a Pas2js compiler on the page.. it would allow the user to play with the code right there.. but this is impossible with your SQL monitor because on a web page there would be no server to monitor, and even if they wanted to try this themselves, the would have to learn all about SQL to even get started, and that’s never going to happen. So the only interest you will get at all are people who already have some SQL thingie that want to monitor it… but even so, they don’t have enough information to duplicate your program.. if they cut every bit of code from your page, they would not know where or how to paste it to make a functional program. With such a complicated subject, even someone willing to try to figure it out what SQL is and why you need to monitor it, will click the link to ”Entity Framework” and go Woah what is all this?? They going to think “All this Free Pascal stuff is really super advanced and beyond anything I could have a use for” and while it is true that Free Pascal is VERY advanced and has a LOT of ways to accomplish very complicated tasks fairly easily, it also does not HAVE to be complicated at all. In fact you are missing one of the key fundamental philosophies of the Pascal programming language, which is that “Programs should be easily understandable by humans” The image of “The SQL Monitor Example Program” doesn’t mean anything to the average person, and it does not mean anything to me as an experienced programmer.. it’s just a bunch of gibberish that seems to accomplish nothing. I don’t know why I would ever want to monitor that stuff and I’m afraid you are going to lose your entire audience because the subject is just too complex, unless the reader can understand what the program specifically does and how it does it, they aren’t going to be interested. If instead you had an example of a program that everyone could relate to and maybe even use themselves you will capture a lot more interest, and if the example is relatively simple and easy to follow, with variables that have no abbreviations so it’s as readable as possible, and well commented to make sure that everything is clear, then you might get someone to actually download Free Pascal and start typing some code, and it seems to me that would be the goal of such an introduction. That’s why I mentioned the timer.. hey a cool program that you set an amount of time, then it counts down and maybe makes a sound when it’s done.. well everyone that has ever boiled and egg could see why you would want to do that. Then they could see.. this program has a timer, this is how I set the amount of time, this is how I start it, this is what happens when it’s done, this is what displays the time left, etc… it serves a purpose they can understand and they can follow exactly what is happening and understand the end result. James ___ fpc-pascal mail
Re: [fpc-pascal] Working on a new way to educate people about pascal
>i think he meant both... Yes I meant both, I myself as an experience programmer cannot follow really any of what is going on at all.. except the button that clears the message box. I can't figure out why there is a timer, I can't figure out how you would change the amount of time being timed, or how to start it or how to stop it or anything at all other than.. look, there's a timer in here.. wonder what that's for and how does that work? Maybe a nice simple countdown timer would be a better example. I looked up SQL on Wikipedia and yea.. that's over my head.. that is a VERY specific and VERY advanced topic. It's just not anything that the average person who isn't already a very technical person or in fact very technical people who just have no use for it would understand. I couldn't even understand the Wikipedia article on it.. it's just way outside my experience and I have no idea what it's for.. but I know I don't have a use for it. A nice simple countdown timer would be something everyone could understand the purpose of and be able to follow along. I have done a few Lazarus projects, and I do understand it, but in my opinion Lazarus is a terrible example of Pascal programming, for one simple reason... There is never a continuous program anywhere.. it's snippets of code here and snippets of code there.. it's all over the place. It makes it VERY difficult for anyone to follow what the heck is going on if you don't have the actual IDE right in front of you. The document itself is a perfect example of this.. there's a block of code here and a block of code there, but no way to figure out how anything works together. So that is why I said start with a console app that has a bunch of Writeln() commands in it.. it's easy to follow, and you don't need to go here and go there to figure out what's going on. Lazarus and GUI applications are ALL too advanced as an introduction to Pascal because the GUI interface requires that you have these snippets of code all over the place. -Original Message- From: fpc-pascal On Behalf Of wkitty42--- via fpc-pascal Sent: Wednesday, December 28, 2022 4:46 AM To: fpc-pascal@lists.freepascal.org Cc: wkitt...@windstream.net Subject: Re: [fpc-pascal] Working on a new way to educate people about pascal On 12/27/22 9:37 PM, Anthony Walter via fpc-pascal wrote: > "I see there's a timer there.. but what starts it? What happens when > it times out? How do I set the amount of time? Why is there even a > timer at all? I don't know any of this." > > James, when you raised these questions are you saying that you don't > know, or that someone who doesn't know much if anything about programming doesn't know? i think he meant both... there are times when i see "wall of words" code and can pick some things out of it but why they are there, what they are used for, and how they operate are still asked... digging deep in the code may answer those questions after some circuitous path tracing but it depends on the code... like james, i also have like 40-45 years programming experience... 99% of my stuff is still text mode tools and apps... GUI stuff has just never made sense to me... -- NOTE: No off-list assistance is given without prior approval. *Please keep mailing list traffic on the list where it belongs!* ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Working on a new way to educate people about pascal
>>If the target audience are people that are not yet into programming, I think the code samples might be a little too difficult ? I have been programming with Pascal since the days of Turbo Pascal, I have applications with hundreds of thousands of lines of code, and I also program C++ and Python, but I honestly don't have a clue what's going on at all with this introduction. About the only thing I understood was the explanation of clear.button.click The SQL monitor program example.. I have no idea what any of that means or what it might be used for. I don't know what SQL is, never seen it before, and don't know why you would want to monitor it. Threads... Sockets... etc.. those are more advanced topics. Introductions should be a Hello World Terminal program with maybe some colored text... something you can follow line by line and it makes sense even if you don't know what some unit is doing. After the Hello World program maybe introduce procedures, and show how repetitive things could be done with a procedure, Then show functions and show how a value could be returned from a function. The introduction should be basic syntax and logic, maybe some if then statements or for loops... something easy to follow and understand what's going on line by line Then another hello world program with a message box. Then maybe a simple form.but threads and sockets... ok.. well I know what threads and sockets are because I happened to use them... but to a newbie... YIKES what are those?? and SQL??? What the heck is that anyway? I'm not talking about a newbie.. I mean.. myself... with over 40 years of programming experience, mostly with Pascal, What the heck is it and why would I need to monitor it? So how can I type this program in on my own computer and run it, play with some things and see what happens? Where am I going to find an SQL thingie to monitor?? I don't even know what that is. It's way too advanced of a subject for an introduction to a programming language and honestly it doesn't make me want to try to lean it.. it's just Poof WAY over my head. With a hello world program, I can type in in my own computer, change the text, change the color.. etc.. I can understand it.. if there's a for loop or some variables, I can follow the logic of what's happening. In this example, well lets see.. I see there's a timer there.. but what starts it? What happens when it times out? How do I set the amount of time? Why is there even a timer at all? I don't know any of this. I also could not tell you the purpose of the entire program.. I don't know what an SQL is, what the things mean in the SQL monitor box or why SQLs whatever they are might need to be monitored. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Program efficiency
Sounds to me that if the compiler will probably insert temp variables anyway, then I might as well make my own and make it easier to understand later. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Program efficiency
I was wondering if breaking up large complicated formulas into smaller sections that use more variables is less efficient than just the large formula. In other words.. is A:=(B+C/D)-E^F; G:=H*(I+J); K:=L+M/N; O:= A+G-K; Less efficient than O:= ((B+C/D)-E^F)+ (H*(I+J))-(L+M/N); Or does it end up being the same when it's done? I have a tendency to avoid using variables even though the code would be infinitely more understandable if it was broken into sections and more variables were used, but I'm wondering if this is really any more efficient or if it just seems like it should be... after all storing things in a variable and reading them out should take some time... but then again the processor only works on one operation at a time anyway, so the final assembly code would probably have to store things somewhere and get them back... so.. is it really faster? So if I never need the value a second time, is it really better to avoid variables? I could break it up an use comments: O:= ((B+C/D)-E^F)+ //A (H*(I+J))- //G (L+M/N); //K This got me thinking, it would be cool if there was some king of utility that counted clock cycles for you while your program ran..and then I could just try a sample program both ways and see what the results are... James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] mciSendString with long file names
Sorry for the confusion. Let me clarify: The freepasal program is always run on a Windows system, mciSendString is a Windows function. I've seen solutions for this problem that use the NTFS 8.3 Short file name... Which I thought would work, but, for my application it won't work because the file is being loaded off a network drive, and the SERVER for the file is a Linux server.. but even though it's a Linux server, the path on my windows system is still uses backslashes not forward slashes... It's a FreeNAS server with Windows file sharing. Anyway the point was that only windows NTFS formatted drives have the short file name.. so that solution won't work at all. I want the program to be able to play the sound file no matter where the file is stored on the network or on a flash drive or a ramdrive.. etc, and not have a requirement that it is an NTFS drive. So it has to work with windows paths. Almost all windows applications just put it in quotes, but mciSendString does not play nice. I think it was invented during 8.3 limitations and it was only hacked to kind of work with long file names.. not really work properly. The Alias method does work, but it's not so convenient for Asynchronous mode because it leaves the file open.. if you close it before it finishes playing, it stops and if you wait for it to finish and then close it.. well, that's just not asynchronous. James -Original Message- From: fpc-pascal On Behalf Of Travis Siegel via fpc-pascal Sent: Thursday, September 22, 2022 3:27 PM To: ja...@productionautomation.net; FPC-Pascal users discussions Cc: Travis Siegel ; James Richters Subject: Re: [fpc-pascal] mciSendString with long file names That's on windows, you said the program was running on linux. In that case, backslashes will escape the spaces, allowing the path to be found properly. Windows paths are different, as mentioned before, they can be escaped too, but the character is different. On 9/22/2022 2:57 PM, James Richters via fpc-pascal wrote: > Won’t backslashes before each space be defining a subdirectory? > > If my path looks like: > C:\Program Files\My Program\Some File.MP3 I don't see how changing it > to: > C:\Program\ Files\My\ Progam\Some\ File.MP3 can possibly work.. it's just > butchering the path. > > James > > > From: fpc-pascal On Behalf > Of Travis Siegel via fpc-pascal > Sent: Wednesday, September 21, 2022 4:15 PM > To: FPC-Pascal users discussions > Cc: Travis Siegel ; Jean SUZINEAU > > Subject: Re: [fpc-pascal] mciSendString with long file names > > Adding a backslash (\) before each space should do the job nicely. I have > had similar issues on linux and windows with some commands, and adding the > escape characters to the filename almost always fixes the problem. The only > time it didn't, was when the filename started with a dash "-" character. > Otherwise, the backslash always works for me. > > On 9/20/2022 4:16 PM, Jean SUZINEAU via fpc-pascal wrote: > May be by escaping the spaces with ^ ? > Something like: MyFileName:= StringReplace(MyFileName, ' ', '^ ', > [rfReplaceAll]); ^ is the escape char for cmd.exe but may be it is active in > this context too ? > Le 20/09/2022 à 18:31, James Richters via fpc-pascal a écrit : > I just tried it that way: > Var > pcmd: String; > MyFileName: String; > > pcmd:='play "'+MyFileName+'"'+#0; > mciSendString(@pcmd[1],Nil,0,0); > > > > > ___ > fpc-pascal maillist - mailto:fpc-pascal@lists.freepascal.org > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal > > ___ > fpc-pascal maillist - fpc-pascal@lists.freepascal.org > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] mciSendString with long file names
Won’t backslashes before each space be defining a subdirectory? If my path looks like: C:\Program Files\My Program\Some File.MP3 I don't see how changing it to: C:\Program\ Files\My\ Progam\Some\ File.MP3 can possibly work.. it's just butchering the path. James From: fpc-pascal On Behalf Of Travis Siegel via fpc-pascal Sent: Wednesday, September 21, 2022 4:15 PM To: FPC-Pascal users discussions Cc: Travis Siegel ; Jean SUZINEAU Subject: Re: [fpc-pascal] mciSendString with long file names Adding a backslash (\) before each space should do the job nicely. I have had similar issues on linux and windows with some commands, and adding the escape characters to the filename almost always fixes the problem. The only time it didn't, was when the filename started with a dash "-" character. Otherwise, the backslash always works for me. On 9/20/2022 4:16 PM, Jean SUZINEAU via fpc-pascal wrote: May be by escaping the spaces with ^ ? Something like: MyFileName:= StringReplace(MyFileName, ' ', '^ ', [rfReplaceAll]); ^ is the escape char for cmd.exe but may be it is active in this context too ? Le 20/09/2022 à 18:31, James Richters via fpc-pascal a écrit : I just tried it that way: Var pcmd: String; MyFileName: String; pcmd:='play "'+MyFileName+'"'+#0; mciSendString(@pcmd[1],Nil,0,0); ___ fpc-pascal maillist - mailto:fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] mciSendString with long file names
I ran into a problem just removing spaces for the alias name, I guess the slashes and colon from the path are not valid for the alias, so now I have a new function that removes everything that is not a letter, and that seems to have solved the problem: mciSendString(PChar(Ansistring('Close '+LettersOnly(MyLongFileName))), Nil, 0, 0); mciSendString(Pchar(Ansistring('Open ' + #34+MyLongFileName+#34 + ' alias '+ LettersOnly (MyLongFileName))), Nil, 0, 0); mciSendString(PChar(Ansistring('Play '+ LettersOnly (MyLongFileName)+' wait')), Nil, 0, 0); I'm still trying to see if there is a way to close everything even if I don't know the alias anymore. James -----Original Message- From: fpc-pascal On Behalf Of James Richters via fpc-pascal Sent: Tuesday, September 20, 2022 5:21 PM To: 'FPC-Pascal users discussions' Cc: James Richters ; 'Alexander Hofmann' Subject: Re: [fpc-pascal] mciSendString with long file names That Alias method does seem to work.. thank you for the suggestion, although it makes it more complicated for asynchronous operation, which is of course what I wanted. So here is what I came up with.. for synchronous operation, this works fine: mciSendString(Pchar(Ansistring('Open ' + #34+MyLongFileName+#34 + ' alias myalias wait')), Nil, 0, 0); mciSendString(PChar(Ansistring('Play myalias wait')), Nil, 0, 0); mciSendString(PChar(Ansistring('Close myalias)), Nil, 0, 0); but without the wait, it closes before it plays.. and I don't want my application to wait for the sound to finish before moving on, so for asynchronous operation, I just put the close before the open and it seems to work, to make sure the alias is available, and it seems to work. I also need unique alias names, in case 2 sounds are trying to be played back to back, otherwise the second one will not be able to use the alias but that's easy to generate by just removing the spaces from the file name. This seems to work: mciSendString(PChar(Ansistring('Close '+Nospaces(MyLongFileName))), Nil, 0, 0); mciSendString(Pchar(Ansistring('Open ' + #34+MyLongFileName+#34 + ' alias '+Nospaces(MyLongFileName))), Nil, 0, 0); mciSendString(PChar(Ansistring('Play '+Nospaces(MyLongFileName)+' wait')), Nil, 0, 0); I suppose I really need to close it at some point after it's done, but by then my process is long past the procedure that fired it off... at least for repeat playing, it will have closed the old one before it made a new one. I wonder if there is a way to do a 'CLOSE ALL' that I could run when before my program exits just to clean up the system. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] mciSendString with long file names
That Alias method does seem to work.. thank you for the suggestion, although it makes it more complicated for asynchronous operation, which is of course what I wanted. So here is what I came up with.. for synchronous operation, this works fine: mciSendString(Pchar(Ansistring('Open ' + #34+MyLongFileName+#34 + ' alias myalias wait')), Nil, 0, 0); mciSendString(PChar(Ansistring('Play myalias wait')), Nil, 0, 0); mciSendString(PChar(Ansistring('Close myalias)), Nil, 0, 0); but without the wait, it closes before it plays.. and I don't want my application to wait for the sound to finish before moving on, so for asynchronous operation, I just put the close before the open and it seems to work, to make sure the alias is available, and it seems to work. I also need unique alias names, in case 2 sounds are trying to be played back to back, otherwise the second one will not be able to use the alias but that's easy to generate by just removing the spaces from the file name. This seems to work: mciSendString(PChar(Ansistring('Close '+Nospaces(MyLongFileName))), Nil, 0, 0); mciSendString(Pchar(Ansistring('Open ' + #34+MyLongFileName+#34 + ' alias '+Nospaces(MyLongFileName))), Nil, 0, 0); mciSendString(PChar(Ansistring('Play '+Nospaces(MyLongFileName)+' wait')), Nil, 0, 0); I suppose I really need to close it at some point after it's done, but by then my process is long past the procedure that fired it off... at least for repeat playing, it will have closed the old one before it made a new one. I wonder if there is a way to do a 'CLOSE ALL' that I could run when before my program exits just to clean up the system. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] mciSendString with long file names
I just figured out that short filenames won't work, my files are on a linux server... not NTFS drives.. so I'm back to getting it to work with spaces the normal file names James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] mciSendString with long file names
I just tried it that way: Var pcmd: String; MyFileName: String; pcmd:='play "'+MyFileName+'"'+#0; mciSendString(@pcmd[1],Nil,0,0); I get the same results, files with no spaces in the name even long file names play fine, if there's spaces, they won't play. I had the idea to just get the windows short file name and pass it on to play the sound instead of bothering to figure out why spaces won't work. I found getshortpathname: https://www.freepascal.org/daily/packages/winunits-jedi/jwawinbase/getshortp athname.html function GetShortPathName( lpszLongPath: LPCTSTR; lpszShortPath: LPTSTR; cchBuffer: Windows.DWORD ):Windows.DWORD; does anyone know how to convert a pascal string to the LPCTSTR needed for the long path and then how to convert the LPTSTR short path to LPCTSTR for mciSendString? Are the LPCTSTR and LPTSTR just PChar strings or something else? James >I've only ever done this like: > >pcmd: string; > >pcmd:='open "'+filename+'" ... '+#0; > >mciSendString(@pcmd[1], ...); ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] mciSendString with long file names
I'm trying to get mciSendString() to work with long file names with spaces in them and I'm not having any success. I know with winnows you need quotes around long file names, so I'm trying things like this: Var MySoundFile:String; mciSendString(PChar('play '+Ansistring(#34+MySoundFile+#34)),Nil,0,0); But still it works if my file name has no spaces, but does not work if there are spaces. I think maybe it's my conversion to a PChar, but it works as long as there are no spaces, so I don't know. The name of my file is in a string because it comes from a record with a string variable in it.. part of another whole system that I don't want to change just to get this to work. Any one have any ideas how to get long file names with spaces to work? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] SerReadTimeout question
I can't seem to find any documentation or SerRead or SerReadTimeout.. searching for either along with Freepascal doesn't get me any results. If it exists somewhere and I am just missing it, can someone tell me where it is? Anyway, what I'm trying to figure out is when the timeout timer starts... does the timeout timer start when I call the funciton, or does it start when there is no data to read... waiting for a certain amount of time to see if there is more data? Of course it will also stop when the requested number of bytes is satisfied. I'm trying to read as fast as reliable, but I don't always know how many bytes I'm expecting. So it would be handy it the timer started when there was nothing to read.. then I could have a very small timeout and as long as data was coming in, I would get it, until the requested number of bytes is reached... but if the timer stated when I call the function, I will have to caclculate how long it should take and add a little in case the data isn't ready when I ask for it. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Getting Shift key with PTCCRT
I came up with a solution for this. Since I am on windows, I found I can just check GetAsyncKeyState between keypressed and readkey like this: If PTCCRT.KeyPressed then Begin isShiftDown := GetAsyncKeyState(VK_Shift); MyKey:=PTCCRT.ReadKey; End; James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
So I could just do this? Index:= MyStringlist.IndexOfName(SearchName); If Index >=0 then MyValue := MyStringlist[Index].ValueFromIndex; That sure is nice to know, Thank you! I guess for my dynamic arrays of records, I still need to search with a loop... or is there a cool thing I don't know about for that as well? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
The problem with the for in loop is that I need the index. I'm sometimes searching through the stringlist looking for a match, and when I find a match, I want to read the value And then do a break, because there is no point is searching once I found what I am looking for: For I:= 0 to MyStringlist.high Do Begin If MyStringlist[I].Names = SearchName Then Begin MyValue := MyStringlist[I].ValueFromIndex; Break; End; End; I agree that the for - in loop is a great way if you are always processing the entire list and don't need the index for anything. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
The loops is just an example because in my original post of why I wanted to get the highest element of a stringlist was because I wanted a for loop that wasn't as clumsy as For I:=0 to myStringlist.count-1 Do This came up because thanks to this discussion list, I learned I could use High() and Low() for my dynamic arrays, so I went through replacing all instances of Length(MyDynamicArray)-1 with High(MyDynamicArray) So my for loops went from: For I:=0 to Length(MyDynamicArray)-1 Do To For I:=0 to High(MyDynamicArray) Do Which I find much more clear and less prone to problems.. I have forgot the -1 before and it gives range check errors of course.. so I'm switching everything to use High() instead and will just automatically use High() in the future, thus preventing the issue all together. I'm really happy with the helper function and using MyStringList.High. I think .High should just be added to all things that have a .Count because everyone always needs it ALL THE TIME. But I am happy it's possible to add a helper function to add it myself. James >Why the loop? ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
Thank you for the example! I also needed {$Mode OBJFPC} to get it working. I am normally in {$Mode FPC} Or {$Mode TP} But I found that if I just put this in a unit that is {$Mode OBJFPC} and include that unit in my {$Mode TP} Unit it works just great! I have a useless unit that is just a whole list of constants, types, and variables used by my other units, just so I don't have to scroll past over 1000 lines of code just to get to the functions and procedures. It was {$Mode FPC} For some reason {$Mode FPC} {$modeswitch typehelpers} Still had Error: Identifier not found "class" So I changed it to {$Mode OBJFPC} {$modeswitch typehelpers} And put the function in it, and it's working great! My main reason for wanting something like this is because I occasionally will forget the -1 and... well... that's no good... Since I recently learned of High() and Low() for arrays, I've been changing all my for loops with arrays to use High() and sometimes Low() if they don't start at 0. It's also helpful to do something like: MyArray[High(MyArray)] := something; To write to a newly added array element where I used to have MyArray[Length(MyArray)-1] := something; While it does work.. it's less readable and prone to errors. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
This Helper sounds like a nice way to do it. I need the numerical index of the loop so this would be more straight forward. Would I then do something like : For I:= 0 to MyStringList.High Do ? When I try to add the Type statement: type TStringListHelper = class helper for TStringList function High: NativeInt; end; I getError: Identifier not found "class" I have the Classes unit. Is there something else I am missing? James >Another alternative would be declaring a helper: >type TStringListHelper = class helper for TStringList function High: NativeInt; end; >function TStringListHelper.High: NativeInt; begin > Exit (Self.Count-1); >end; ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Get highest element of a StringList
I thought I would try: For Loop := 0 to High(MyStringList) do But I get "Error: Type mismatch" Is there a way to get the highest element of a stringlist other than: For Loop := 0 to MyStringList.Count-1 do It would be nice to not have the -1 Could High() be made to work if the argument was a stringlist? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Getting Shift key with PTCCRT
Thanks for the suggestion I think the syntax should be: type myKeyEvent = IPTCKeyEvent; Var myShiftStatus : boolean; myShiftStatus := myKeyEvent.Shift; but I get IPTCKeyEvent not found. I wonder if it's only designated as internal.. or if I need to use something other than PTCGraph and PTCCRT James >looking at the list of constants in ptcpas, i find PTCKEY_SHIFT... i also find, in Classes, the IPTCKeyEvent which has a GetShift function as well as a Shift >property... seems like you should be able to the shift status with something like >type myKeyEvent : IPTCKeyEvent; >type myShiftStatus : boolean; >myShiftStatus := myKeyEvent.Shift; ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Access Violation When SetLength(DynArray, Value)
>With FPC 3.2.0 and newer you can do "Concat(MyArray, [TheNewElement])" or (if >modeswitch ArrayOperators is active) "MyArray := MyArray + [TheNewElement]". I have a lot of arrays of records, but I just build the record into the array elements, like this: SetLength(MathArray,Length(MathArray)+1); MathArray[High(MathArray)].Variable:=NewVariable; MathArray[High(MathArray)].Formula:=NewEquation; Could either of the methods mentioned work directly with something like this or would I have to build the record first and do: MyRecord.Variable:=NewVariable; MyRecord.Formula:=NewEquation; MathArray:= MathArray+ MyRecord; I thought I would make my own IncArray() function: Procedure IncArray(Var TheArray); Begin SetLength(TheArray,Length(TheArray)+1); End; But I get a 'Type Mismatch' Any ideas how this could be done? Is this even possible without specifying the exact type of array? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Getting Shift key with PTCCRT
I have some key sequences with PTCCRT.READKEY where I use a lower case letter to do one thing and an uppercase to do another, but if the Capslock is on, they do the wrong things. Is there a way I can check the condition of the shift key to see if shift was actually pressed instead of just going by whether I got a capital letter or not? The key input is not something that is ever displayed on the screen, it's just making selections and doing them. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Access Violation When SetLength(DynArray, Value)
I only recently learned about using Low() and High() and it is so much nicer than For I:= 0 to Length(MyArray)-1 Do That I actually went though all my code replacing the Length() - 1's with High() I still end up with a lot of SetLength(MyArray,Length(MyArray)+1); Every time I want to add one more thing to the array. Almost all of my dynamic arrays do this, because I can only add one thing at a time to the array... and the reason I wanted it to be dynamic in the first place. Is there some nifty way to increase a dynamic array by 1 that is more elegant? Inc(MyArray); would sure be nice James >To avoid this kind of error you can use > > for i:= 0 to High(Rails) do > >or even > >for i:= Low(Rails) to High(Rails) do ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] BoolToStr
Thanks for the discussion everyone, it does shed some light on what's going on. I agree it would be impossible to change it now, It was actually a GREAT idea to make it customizable, and that serves my needs just fine. I guess all that's left is to update the documentation to show what it really does and show how it is customizable. I wouldn't mind doing that... if I knew how. What is the proper method to submit documentation change requests? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] BoolToStr
I don't see how it makes anything compatible at all.. because it's NOT a 0 or a -1 integer value, it's a STRING of '0' or '-1' so you can't even evaluate the negative bit.. because there isn't one, it's a string of - and 1. You would have to do StrToInt(BoolToStr(MyVariable)) to be able to evaluate the negative bit... which again is useless because there is only one bit to check.. indeed you would need to do StrToInt(BoolToStr(MyVariable)) just to evaluate the 0 as a numeric value, but then this is a really round about way to do it when you could make a simple BoolToInt function to just give you the numeric result. Even if it is convenient to set the - flag for "All Bits Set" it doesn't apply to BoolToStr, because we aren't evaluating a Nibble, or a Byte, or a Word, etc, we are only evaluating a single bit Boolean variable.. so there are no, ALL Bits, there is only THE Bit. I guess technically ALL one of it was set... but making it a -1 makes it more difficult to stack a bunch of these bits together into a word or something, and the - really serves no purpose if there is only one bit.. in fact you can't even put it into a byte because -1 isn't a valid Byte. You would have to do MyByte:=Abs(StrToInt(BoolToStr(True))); I think it would be best to make BoolToStr always produce 'TRUE' or 'FALSE' as the default because that is what is documented, and that is also what makes the most sense.. after all you are asking for a STRING, so you are outputting to something that wants a String, probably to be readable at some point, if you do Writeln of a Boolean you get 'TRUE' or 'FALSE', and BoolToStr should do that same thing... just like the documentation indicates. An additional BoolToInt could be added that returned an integer, which I think should return a 0 or a 1, but maybe retain the ability to customize the integer output the same way BoolToStr does, then if you want to check the - flag instead of checking the 1 bit, you could do that.. as silly as it is for a 1 bit test. Anyway, I suppose such a change would break a whole pile of stuff at this point, so it's probably not going to happen... but it would be nice if it made more logical sense, and BoolToInt is what you need if you want to get a 0 and 1 (or 0 and -1 as the case may be) numerical value, but there doesn't appear to be one in FPC. I'm curious if there is a way to search the FPC version history of changes for BoolToStr to see why it was changed, and see if there is a valid reason not to change it back. it was obviously changed from the way the documentations is at some point. It really seems to me that if it was that important that someone had a function that output a 0 or a -1, the only way it makes sense is if it's an integer, not a string. If a special function is needed for some COM thing or weird Winapi thing, then that function should be part of the unit that needs it, not modifying the generic function intended to be used for general purpose applications output something that does not conform to other Pascal Boolean datatypes and just confuses everyone. James Op 8/28/2022 om 8:45 PM schreef Ralf Quint via fpc-pascal: On 8/28/2022 8:23 AM, James Richters via fpc-pascal wrote: Running "i:\booltostr.exe " -1 0 Why true is -1 instead of 1 is beyond me, but anyway, I would consider this BoolToInt, not BoolToStr, I want the Strings ‘TRUE’ or ‘FALSE’ as indicated in the documentation Very logical in fact. 0 is NO bit set in any given size of boolean data type, -1 means ALL bits set on that same size boolean data type. Pascal boolean datatypes only have 0 or 1 as defined values. But probably it is for some COM or Winapi compatible purpose. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] BoolToStr
> You can use BoolToStr(b,'TRUE','FALSE') That works great! Shouldn't that be the default and you can put in something else if you want it? It's Boolean To String... not Bool to some number. If I just do Writeln(True); I get the string 'TRUE' The text 'TRUE' is what you get if you convert a Boolean value of 1 to a string, not anything else. I guess the default must have been 'TRUE' or 'FALSE' at one time as that is how the documentation is written, it must have been changed to be compatible with Delphi code at some point I guess. Thanks for the suggestion, it works for my needs. James. -Original Message- From: fpc-pascal On Behalf Of Michael Van Canneyt via fpc-pascal Sent: Sunday, August 28, 2022 11:39 AM To: ja...@productionautomation.net; FPC-Pascal users discussions Cc: Michael Van Canneyt ; James Richters Subject: Re: [fpc-pascal] BoolToStr On Sun, 28 Aug 2022, James Richters via fpc-pascal wrote: > I'm generating a report where I wish to display some Boolean values. > I thought I would try BoolToStr, as according to: > https://www.freepascal.org/docs-html/rtl/sysutils/booltostr.html it states: > > Description > BoolToStr converts the boolean B to one of the strings 'TRUE' or 'FALSE' > > So it should do exactly what I want. output the text string 'TRUE' or > 'FALSE' depending on the Boolean state, but that is not what happens: > > Uses Sysutils; > Begin > Writeln(BooltoStr(True)); > Writeln(BooltoStr(False)); > End. > > Running "i:\booltostr.exe " > -1 > 0 > > Why true is -1 instead of 1 is beyond me, but anyway, I would consider > this BoolToInt, not BoolToStr, I want the Strings 'TRUE' or 'FALSE' > as indicated in the documentation I will adapt the documentation to be more precies. You can use BoolToStr(b,'TRUE','FALSE') or BoolToStr(b,True) in which case it will use the BoolStrs arrays to determine the strings. -1 and 0 are the Delphi values, which, I agree, are not very intuitive. > > And BoolToInt should always output 0 or 1, not matter what operating > system you are on.. I don't understand the -1. I guess some Windows > API's use -1 for true.. I still don't understand. > Maybe there should be a BoolToBit that could always be 0 or 1 > regardless of the operating system. As said, the 0 and -1 are for Delphi compatibility. Use Ord(Boolean) It will give you 0 and 1. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] BoolToStr
I'm generating a report where I wish to display some Boolean values. I thought I would try BoolToStr, as according to: https://www.freepascal.org/docs-html/rtl/sysutils/booltostr.html it states: Description BoolToStr converts the boolean B to one of the strings 'TRUE' or 'FALSE' So it should do exactly what I want. output the text string 'TRUE' or 'FALSE' depending on the Boolean state, but that is not what happens: Uses Sysutils; Begin Writeln(BooltoStr(True)); Writeln(BooltoStr(False)); End. Running "i:\booltostr.exe " -1 0 Why true is -1 instead of 1 is beyond me, but anyway, I would consider this BoolToInt, not BoolToStr, I want the Strings 'TRUE' or 'FALSE' as indicated in the documentation And BoolToInt should always output 0 or 1, not matter what operating system you are on.. I don't understand the -1. I guess some Windows API's use -1 for true.. I still don't understand. Maybe there should be a BoolToBit that could always be 0 or 1 regardless of the operating system. I know I can write my own simple function to do it the way I want, but why does this behavior not match the documentation? The whole point of having lots of little functions like FloatToStr, is so everyone doesn't have to keep writing the same functions over and over. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] FPConnect Timeout
I'm not quite following how I could implement that. Here is what I am trying to do: Uses Serial,Sysutils,Sockets,CRT; var Socket_Address: TSockAddr; opt: LongWord; Connect_Result : Integer; TCP_Connect_Socket : Tsocket; begin Modbus.Device[Device_Number].TCP_Socket := fpsocket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if Modbus.Device[Device_Number].TCP_Socket = TSocket(INVALID_SOCKET) then Writeln('Error Creating Socket: ',SocketError); Socket_Address.sin_family := AF_INET; Socket_Address.sin_addr := StrToNetAddr(Modbus.Device[Device_Number].Connection); Socket_Address.sin_port := htons(Modbus.Device[Device_Number].TCP_Port); Connect_Result := fpconnect(Modbus.Device[Device_Number].TCP_Socket, @Socket_Address, sizeof(Socket_Address)); if Connect_Result = SOCKET_ERROR then Writeln('Error Connecting Socket: ',SocketError); // I want to get this error in 2 seconds ... Are you saying to use TInetSocket instead of the Sockets unit? Or do I just figure out how to use set ConnectTimeout and then that's the timeout that will be used, and still use everything else the same? James -Original Message- From: fpc-pascal On Behalf Of Dimitrios Chr. Ioannidis via fpc-pascal Sent: Wednesday, June 8, 2022 1:11 PM To: fpc-pascal@lists.freepascal.org Cc: Dimitrios Chr. Ioannidis Subject: Re: [fpc-pascal] FPConnect Timeout Hi, Στις 8/6/2022 7:27 μ.μ., ο/η James Richters via fpc-pascal έγραψε: > Is there any way to specify a shorter timeout for FPConnect? AFAIK, socket connect timeout is implemented in ssockets ( in TSocketStream ) not in sockets unit. You can use the TInetSocket's class from ssockets unit ( this is what fphttpclient uses ) overloaded constructor with the aConnectTimeout parameter or if you want you can use the ConnectTimeout property before connect and you're ready to go ... regards, -- Dimitrios Chr. Ioannidis ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] FPConnect Timeout
Is there any way to specify a shorter timeout for FPConnect? ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] PTCGraph window location
For my application, I want to put the window where it goes and not allow it to be moved. I am doing: SetWindowLongPTR(graphicwindow, GWL_STYLE, GetWindowLong(graphicwindow, GWL_STYLE) AND not(WS_SIZEBOX) And not(WS_Caption)); WS_Caption is the title bar And WS_Seizebox is a border around the window that I don’t want either. I could do all this stuff myself easy enough and get the desired result if there was just an option to create the PTCGraph window with WS_VISIBLE turned off. I could move it, remove the title, and whatever then make it visible when I’m done, and the screen won’t be flickering with all kinds of window movements. I change the title of the existing window without reopening the window with: SetWindowTextA(graphicwindow,wintitletouse); James From: fpc-pascal On Behalf Of Nikolay Nikolov via fpc-pascal Sent: Saturday, March 12, 2022 10:51 AM To: fpc-pascal@lists.freepascal.org Cc: Nikolay Nikolov Subject: Re: [fpc-pascal] PTCGraph window location On 3/12/22 15:54, James Richters via fpc-pascal wrote: Is there some way I can set the location of the pctgraph window before it is created so it just pops up where I want it to be? I’m using Windows 10. I’ve been re-locating it with SetWindowPos() which is ok if the window is going to be open for a while, but now I am trying to make a little program to display things and relocating the window is quite distracting. It would also be nice to create the window without the title bar. Currently, there's no way to do that. I'm planning to make it possible to change the title, without reopening the window, but I haven't thought about creating a window without a title, or moving it to a specific location. Btw, if the windows doesn't have a title, how can the user move it? Or do you want to move it manually, or just make it stay at a fixed location. These things are possible, but may be hard to do in a multi-platform way, e.g. in Linux, different window managers and desktop environments might ignore the location and place the window somewhere else. There are some crazy non-windows-like WMs there, like i3wm :) Nikolay James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org <mailto:fpc-pascal@lists.freepascal.org> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] PTCGraph window location
Is there some way I can set the location of the pctgraph window before it is created so it just pops up where I want it to be? I'm using Windows 10. I've been re-locating it with SetWindowPos() which is ok if the window is going to be open for a while, but now I am trying to make a little program to display things and relocating the window is quite distracting. It would also be nice to create the window without the title bar. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Sorting a Stringlist on ValueFromIndex
Thanks for the elegant solution Michael, but I'm having some issues implementing it. I'm getting: pastep.pas(28651,10) Warning: Function result does not seem to be set 28650 // Custom compare function 28651 function CompareValues(List: TStringList; Index1, Index2: Integer): Integer; 28652 28653 begin 28654 Result:=CompareText(List.ValueFromIndex[Index1],List.ValueFromIndex[Index2]) 28655 end; pastep.pas(28797,65) Error: Incompatible type for arg no. 1: Got "Pointer", expected "" 28797 AllLogLastRunStringList.CustomSort(@CompareValues); The unit I'm putting this in has: Unit PAStep; {$Mode TP}{$I-} {$modeswitch exceptions} {$R+} I can fix the first error with: 28654 CompareValues:=CompareText(List.ValueFromIndex[Index1],List.ValueFromIndex[Index2]) {$Mode TP} doesn't like using 'result' But I have no idea how I could fix the second error. Any ideas? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Sorting a Stringlist on ValueFromIndex
Is there a quick way to sort a stringlist on it's .ValueFromIndex field instead of it's .Names field? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Text Only printing on Windows.
Thanks for the information. It's not a Dymo printer, it's a Zebra printer. But maybe it will work in a similar way.. James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Text Only printing on Windows.
Way back in the old Turbo Pascal days, it was super simple to send text to a printer. I had written a program that printed text on labels in the order the labels were needed.. the whole thing took me less than an hour to write and labels were spewing out of the printer. I haven't had a need to print anything since then, but now, I want to do the exact same thing.. print sequential text only labels from my FPC console program. I can display the labels to the console window, or write them to a file. but I'm just staring at my code at a total loss on how to send these simple labels to my USB label printer connected to a windows 10 64bit PC. Is there no way to just send text to printers anymore? I don't want to go through the windows print dialog for every label, and I don't want to create one huge document of all the labels and print them all at once.. I want my FPC console application to spit out the next in sequence single label each time I push the space bar, without dealing with any the print dialog or doing anything else. This used to be so easy to do, but now it seems either very complicated or impossible. Does anyone know of a way to just send pain text to a USB printer with FPC ,preferably without Lazarus? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal