FabDev 8 Posted June 6, 2023 (edited) Hello, This : procedure TForm2.Button3Click(Sender: TObject); var V1, V2: Variant; I1, I2: Integer; begin V1 := 0; V2 := 0; ShowMessage(V1 / V2); I1 := 0; I2 := 0; ShowMessage(FloatToStr(I1 / I2)); end; Tested on 4 differents Delphi version (XE, 10.3, 10.4 or 11.3 pro or enterprise) both showmessage raise an EInvalidOp exception. Like described here : https://docwiki.embarcadero.com/RADStudio/Sydney/en/Floating-Point_Exceptions Tested on Windows 10 or 11 in VM or Physical. From a ten year old pentium to a two year old Core I7. Same for Win32 or Win64 compiled debug or release. In debug mode or not. And same with or without GExpert, madexcept etc. But for other Delphi user's using exactly the same project NaN is displayed ! Why ? Does any Windows language settings can do it ? TestDivisionByZero.zip Edited June 6, 2023 by FabDev Share this post Link to post
Lajos Juhász 293 Posted June 6, 2023 var x: real; begin SetExceptionMask(exAllArithmeticExceptions); x:=0/0 ; showmessage(FloatToStr(x)); Most probably some dll changes the exception mask. Share this post Link to post
FabDev 8 Posted June 6, 2023 Using project in attachment so there is no SetExceptionMask . But what dll can do this ? Share this post Link to post
Brian Evans 105 Posted June 7, 2023 With DLL injection it could be anything. Can use something like Sysinternals Process Explorer to see what DLLs are loaded in a process and compare between the two systems. Process Explorer - Sysinternals | Microsoft Learn Share this post Link to post
David Heffernan 2345 Posted June 7, 2023 Check what the floating point exception mask is. I'm sure you'll find that invalid op is unmasked. Some code in your process is doing this. Share this post Link to post
FabDev 8 Posted June 7, 2023 (edited) Problem all my Delphi (XE, 10.3, 10.4 and 11.3) do exception on VM and Physical Windows 10/11 : The project in attachment : procedure TForm23.Button1Click(Sender: TObject); var v1,v2,v3:variant; begin v1:=0; v2:=0; v3:=v1/v2; end; procedure TForm23.Button2Click(Sender: TObject); var v1,v2:integer; begin v1:=0; v2:=0; showmessage(Floattostr(v1/v2)); end; procedure TForm23.Button3Click(Sender: TObject); var v1,v2,v3:variant; begin v1:=1; v2:=0; v3:=v1/v2; end; procedure TForm23.Button4Click(Sender: TObject); var v1,v2:integer; begin v1:=1; v2:=0; showmessage(Floattostr(v1/v2)); end; Each 0/0 : Raise exception 'Floating point invalid operation' (EInvalidOP) Each 1/0 : Raise exception 'Floating point divide by 0' And I have : GetExceptionMask=[exInvalidOp,exDenormalized,exUnderflow] Does somebody get different result ? My problem it is that I can't reproduce the Nan result like some Delphi user's can have in the same project !!! ExceptonDivisionBy0.zip Edited June 7, 2023 by FabDev Share this post Link to post
Der schöne Günther 316 Posted June 7, 2023 (edited) Sorry to be so persistent, but is it really that exact same project that you posted, which reports differently at some of your clients machines? Or just your "real" project? I've had the FPU mask getting changed behind my back by 3rd party dependencies like printer drivers or ActiveX plugins running in the TWebBrowser. But in your example, there should be no third party code at all. Edited June 7, 2023 by Der schöne Günther Share this post Link to post
FabDev 8 Posted June 7, 2023 (edited) 22 minutes ago, Der schöne Günther said: Sorry to be so persistent, but is it really that exact same project that you posted, which reports differently at some of your clients machines? The project in my first post in this thread was coded by another Delphi user's (someone in the Support of a component library) and he said showmessage display Nan (= no exception) !!! Edited June 7, 2023 by FabDev Share this post Link to post
Der schöne Günther 316 Posted June 7, 2023 (edited) But that is not a full project. Maybe the full project had something like a fancy graphic/charting library? Some other kind of 3rd party dependency? That is what I'm trying to say. If you are working on a stand-alone project, you will need to find out what is changing this inside your application. If you are working on a library, you will either have to make sure that your code is always operating with the FPU mask it was designed for. Or, if that is not an option (FPU mask modification is a costly operation), then make it very clear in the documentation that the caller is responsible. I have never heard that Windows sets the FPU mask differently for processes. However, I haven't been able to find much about it. I'd expect the Delphi RTL to set it at startup, but I haven't checked if it does. Edited June 7, 2023 by Der schöne Günther Share this post Link to post
Minox 7 Posted June 8, 2023 I had a similar problem with android, I solved it by trying to convert the result to string and then to number, so I modified your code a bit, but I can't test it with "NAN": procedure TForm2.Button1Click(Sender: TObject); var V1, V2, V3: Variant; I1, I2: Integer; S1 : String; begin V1 := 0; V2 := 0; Try V3 := V1 / V2; Except V3 := -1; End; Try S1 := FloatToStr(V3); StrToFloat(S1); Except V3 := -1; End; If V3=-1 Then ShowMessage('Division by zero') Else ShowMessage(V3); I1 := 0; I2 := 0; ShowMessage(FloatToStr(I1 / I2)); end; Share this post Link to post
David Heffernan 2345 Posted June 8, 2023 27 minutes ago, Minox said: I had a similar problem with android, I solved it by trying to convert the result to string and then to number, so I modified your code a bit, but I can't test it with "NAN": Whatever problem this is attempting to solve, this isn't the solution Share this post Link to post
David Heffernan 2345 Posted June 8, 2023 I'm honestly not sure why this topic is still open. It's the exception mask. Something is changing it. You don't have complete control over it. Other modules that are loaded into your process can change it. It's quite messy. It's been covered ad nauseum here, Borland forums, SO, etc. Run this program to demonstrate how the different exception masks influence behaviour: {$APPTYPE CONSOLE} uses System.SysUtils, System.Math; procedure Main; var x, y: Double; Mask: TArithmeticExceptionMask; begin x := 0; y := 0; Mask := GetExceptionMask; SetExceptionMask(Mask + [exInvalidOp]); Writeln(x / y); SetExceptionMask(Mask - [exInvalidOp]); Writeln(x / y); end; begin try Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. For your scenario, when NaN is produced, clearly invalidop is masked. When the exception is raised it is unmasked. Share this post Link to post
Minox 7 Posted June 8, 2023 41 minutes ago, David Heffernan said: Whatever problem this is attempting to solve, this isn't the solution Have you tested it? because it works for me, it won't be the best of programming, but if it works... Share this post Link to post
Minox 7 Posted June 8, 2023 38 minutes ago, David Heffernan said: I'm honestly not sure why this topic is still open. It's the exception mask. Something is changing it. You don't have complete control over it. Other modules that are loaded into your process can change it. It's quite messy. It's been covered ad nauseum here, Borland forums, SO, etc. Run this program to demonstrate how the different exception masks influence behaviour: {$APPTYPE CONSOLE} uses System.SysUtils, System.Math; procedure Main; var x, y: Double; Mask: TArithmeticExceptionMask; begin x := 0; y := 0; Mask := GetExceptionMask; SetExceptionMask(Mask + [exInvalidOp]); Writeln(x / y); SetExceptionMask(Mask - [exInvalidOp]); Writeln(x / y); end; begin try Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. For your scenario, when NaN is produced, clearly invalidop is masked. When the exception is raised it is unmasked. The problem is that if the division results in "NAN", no exception is raised, so at runtime the error cannot be detected. Share this post Link to post
David Heffernan 2345 Posted June 8, 2023 (edited) 1 hour ago, Minox said: Have you tested it? because it works for me, it won't be the best of programming, but if it works... The solution is to set the exception mask to unmask fp exceptions that you want converted into runtime exceptions. That said, I don't know how exception masks work on non x86 platforms. Your code has the problem that if the division returns -1 then it will treat that as an error, but what do you think happens when you do -1 / 1? If you are going to hack it the way you are doing then at least use a boolean. Although see below. If your platform doesn't handle exception masks as windows does then use IsNaN. Edited June 8, 2023 by David Heffernan Share this post Link to post
David Heffernan 2345 Posted June 8, 2023 2 minutes ago, Minox said: The problem is that if the division results in "NAN", no exception is raised, so at runtime the error cannot be detected. Do you understand how fp exceptions masks work? Share this post Link to post
Wagner Landgraf 43 Posted June 8, 2023 57 minutes ago, David Heffernan said: Run this program to demonstrate how the different exception masks influence behaviour: It doesn't work in Windows ARM. In both cases, the output is Nan. Share this post Link to post
David Heffernan 2345 Posted June 8, 2023 43 minutes ago, Wagner Landgraf said: It doesn't work in Windows ARM. In both cases, the output is Nan. So for the original question that's not an issue because that is for Windows. For @Minox on Android then IsNaN is what is needed. Share this post Link to post
Wagner Landgraf 43 Posted June 8, 2023 1 hour ago, David Heffernan said: So for the original question that's not an issue because that is for Windows. I didn't understand your statement. Isn't that the exact original question? This is what I see in original post: " But for other Delphi user's using exactly the same project NaN is displayed ! Why ? Does any Windows language settings can do it ? " Share this post Link to post
David Heffernan 2345 Posted June 8, 2023 (edited) 3 hours ago, Wagner Landgraf said: I didn't understand your statement. Isn't that the exact original question? This is what I see in original post: " But for other Delphi user's using exactly the same project NaN is displayed ! Why ? Does any Windows language settings can do it ? " The original question is for Windows. And the program I posted demonstrates behaviour with and without invalid op masked. As stated repeatedly above the original question concerns behaviour that is determined by fp exception masks. @Minox was talking about Android. Edited June 8, 2023 by David Heffernan Share this post Link to post
FabDev 8 Posted June 9, 2023 (edited) Yes the original question was for win32 : On 6/6/2023 at 6:02 PM, FabDev said: Same for Win32 or Win64 compiled debug or release. In debug mode or not. And same with or without GExpert, madexcept etc. And after reading this : I need to have a "logical" answer in which case exception is not raised. For the moment it's seems to be because of using of : SetExceptionMask([exInvalidOp, exZeroDivide]); Edited June 9, 2023 by FabDev Share this post Link to post
David Heffernan 2345 Posted June 9, 2023 @FabDev yes that's exactly the same issue Share this post Link to post
Sherlock 663 Posted June 9, 2023 22 hours ago, Wagner Landgraf said: It doesn't work in Windows ARM. In both cases, the output is Nan. Windows ARM <> Windows x86 Windows ARM in this case is much closer to Android. Share this post Link to post