Recent

Author Topic: Is this a bug? External: SIGFPE  (Read 7214 times)

Isenbeck

  • Newbie
  • Posts: 5
Is this a bug? External: SIGFPE
« on: November 29, 2021, 07:34:08 pm »

I am having this error message: Project Project3D raised exception class 'External: SIGFPE'

Code: Pascal  [Select][+][-]
  1.   if w <> 0 then
  2.   begin
  3.     outVector.x := outVector.x / w;              <- Error is here
  4.     outVector.y := outVector.y / w;
  5.     outVector.z := outVector.z / w;
  6.   end;

It cannot be "division by zero" error because code verifies if w is zero.

The value of outVector record is following:
outVector = record VECTOR3D {
  X = 0.68582887700534767,
  Y = 2.1648889418968406e-316,
  Z = -0.10001000100010002}
var outVector: Vector3D = record

and value of w is:
w = 1.0359149494331584e-316
var w: real = type Double

I don't see why there would be an error? Is this a bug?
I have tried to replace outVector.x with a simple real variable (aValue: real) and still have the fault. So, it is also not because of outVector being a record.
 
Any ideas?

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Is this a bug? External: SIGFPE
« Reply #1 on: November 29, 2021, 07:55:55 pm »
It's not "division by zero", it's "quotient out of range". You've not shown us a compilable example: what's the /exact/ definition of those types and what platform are you on?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Isenbeck

  • Newbie
  • Posts: 5
Re: Is this a bug? External: SIGFPE
« Reply #2 on: November 29, 2021, 08:19:21 pm »
It's not "division by zero", it's "quotient out of range". You've not shown us a compilable example: what's the /exact/ definition of those types and what platform are you on?

MarkMLl

The operating system is Windows 10, 64 bit.
Here is the definition of the record:
Code: Pascal  [Select][+][-]
  1.   Vector3D = record
  2.     x, y, z: real;
  3.   end;
So... every field in the record is of type REAL. Also is the variable 'w'.
And like I said... To eliminate the possibility that the problem is with the field of a record, I have created a variable of type real, gave it some value (other than zero), and tried with that. It made the same error when divided with 'w'.
Values are given in my first post.

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Is this a bug? External: SIGFPE
« Reply #3 on: November 29, 2021, 08:24:49 pm »
Hi!

Even if the range was not real but double:

You are out of range.

The Value of minDouble is

2.2250738585072014e-308 

Your value for y is

 Y = 2.1648889418968406e-316


which is smaller than minDouble.

You are beyond the range of any 64-bit float.

Winni


MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Is this a bug? External: SIGFPE
« Reply #4 on: November 29, 2021, 08:32:02 pm »
You DID NOT show us a sensible definition of your types.

Code: [Select]
var w: real = type Double

Check what real is on that platform... https://www.freepascal.org/docs-html/current/prog/progsu158.html#x202-2070008.2.5 suggests that it's double but in general you're better off using single/double/extended explicitly.

Check whether using an explicit double fixes the problem. I don't think you've got 80-bit extended available which is a pity.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Is this a bug? External: SIGFPE
« Reply #5 on: November 29, 2021, 08:34:34 pm »
Even if the range was not real but double:

You are out of range.

The Value of minDouble is

2.2250738585072014e-308 

Your value for y is

 Y = 2.1648889418968406e-316


which is smaller than minDouble.

You are beyond the range of any 64-bit float.

https://www.freepascal.org/docs-html/current/ref/refsu5.html#x27-310003.1.2 says 5.0E-324 .. 1.7E308, but this wouldn't be the first time documentation has been found wrong.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Isenbeck

  • Newbie
  • Posts: 5
Re: Is this a bug? External: SIGFPE
« Reply #6 on: November 29, 2021, 08:37:46 pm »
Thank you for your advice.
I have tried to use the DOUBLE type explicitly, on all variables... but it did not work.

But, SINGLE works fine.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Is this a bug? External: SIGFPE
« Reply #7 on: November 29, 2021, 08:52:18 pm »
Thank you for your advice.
I have tried to use the DOUBLE type explicitly, on all variables... but it did not work.

But, SINGLE works fine.

If I were you I'd not trust that.

The reason I emphasise "quotient out of range" is that you'll get it if e.g. your dividend is garbage, which is effectively the point Jamie's making.

The other thing you've not told us is what compiler mode you're using plus your compilation options etc., but your observation that SINGLE works suggests that there's something badly screwy going on.

We'll not get any further with this unless you post a test program.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Is this a bug? External: SIGFPE
« Reply #8 on: November 29, 2021, 09:05:58 pm »
Hi!

Never trust any documentation.
Trust the source.

Have a look at unit math:
     
Code: Pascal  [Select][+][-]
  1.      const
  2.  
  3.       MinSingle    =  1.1754943508e-38;
  4.       MaxSingle    =  3.4028234664e+38;
  5.       MinDouble    =  2.2250738585072014e-308;
  6.       MaxDouble    =  1.7976931348623157e+308;    


Whatever you do:  anythingE-316 is out of range

Winni


PS.: This is exact the definition of IEEE 754

« Last Edit: November 29, 2021, 09:12:17 pm by winni »

avk

  • Hero Member
  • *****
  • Posts: 752
Re: Is this a bug? External: SIGFPE
« Reply #9 on: November 29, 2021, 09:13:07 pm »
I wonder what happens if add the Math unit to the Uses clause, and somewhere at the very beginning of the your unit execute
Code: Pascal  [Select][+][-]
  1.   ...
  2.   SetExceptionMask(GetExceptionMask + [exDenormalized]);
  3.   ...
  4.  

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Is this a bug? External: SIGFPE
« Reply #10 on: November 29, 2021, 09:15:23 pm »
Never trust any documentation.
Trust the source.

Well /you/ report it as a bug then :-) :-) :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Is this a bug? External: SIGFPE
« Reply #11 on: November 29, 2021, 09:27:34 pm »
I wonder what happens if add the Math unit to the Uses clause, and somewhere at the very beginning of the your unit execute
Code: Pascal  [Select][+][-]
  1.   ...
  2.   SetExceptionMask(GetExceptionMask + [exDenormalized]);
  3.   ...
  4.  

Ouch. That reminds me of a problem way back (Delphi 3 era), where an HP printer driver changed the global FPU settings.

Double ouch: an OS 35 years ago that didn't save any FPU state at all, and I somehow managed to patch it...

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Isenbeck

  • Newbie
  • Posts: 5
Re: Is this a bug? External: SIGFPE
« Reply #12 on: November 29, 2021, 09:37:22 pm »
I'm using Lazarus 2.0.12
FPC version 3.2.0
Revision 64642
win64

It is the default Lazarus installation with all default settings. Including compiler options.

Here is the part of the code that generates the fault.
As for the form, there is one simple form frmMain that contains two controls: TPaintBox that has a name pbDisplay and one TTimer that has a name tmRefresh.

This program is my "playground" where I test methods and it does not do much.
But while testing, it throws me that error.

Code: Pascal  [Select][+][-]
  1. unit Main_u;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Math;
  9.  
  10. type
  11.  
  12.   { Project types }
  13.  
  14.   Vector3D = record
  15.     x, y, z: double;
  16.   end;
  17.   Triangle = array[0..2] of Vector3D;
  18.   Matrix4x4 = array[0..3, 0..3] of double;
  19.   Mesh = array of Triangle;
  20.  
  21.   { TfrmMain }
  22.  
  23.   TfrmMain = class(TForm)
  24.     pbDisplay: TPaintBox;
  25.     tmRefresh: TTimer;
  26.     procedure FormCreate(Sender: TObject);
  27.     procedure pbDisplayPaint(Sender: TObject);
  28.     procedure tmRefreshTimer(Sender: TObject);
  29.   private
  30.     procedure SetTriangle(n: integer; v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z: real);
  31.     procedure MultiplyMatrixVector(inVector: Vector3D; var outVector: Vector3D; inMatrix: Matrix4x4);
  32.     procedure DrawTriangles(var bmp: TBitmap);
  33.     function MultiplyMatrixVector(inVector: Vector3D; inMatrix: Matrix4x4): Vector3D;
  34.   public
  35.  
  36.   end;
  37.  
  38.  
  39. var
  40.   frmMain: TfrmMain;
  41.   meshCube: Mesh;                              // Create a cube mesh
  42.  
  43. implementation
  44.  
  45. {$R *.lfm}
  46.  
  47. { TfrmMain }
  48.  
  49. procedure TfrmMain.FormCreate(Sender: TObject);
  50. begin
  51.   setlength(meshCube, 12);
  52.  
  53.   // SOUTH
  54.   SetTriangle(0, 1, 0, 0, 0, 1, 0, 1, 1, 0);
  55.   SetTriangle(1, 0, 0, 0, 1, 1, 0, 1, 0, 0);
  56.  
  57.   // EAST
  58.   SetTriangle(2, 1, 0, 0, 1, 1, 0, 1, 1, 1);
  59.   SetTriangle(3, 1, 0, 0, 1, 1, 1, 1, 0, 1);
  60.  
  61.   // NORTH
  62.   SetTriangle(4, 1, 0, 1, 1, 1, 1, 0, 1, 1);
  63.   SetTriangle(5, 1, 0, 1, 0, 1, 1, 0, 0, 1);
  64.  
  65.   // WEST
  66.   SetTriangle(6, 0, 0, 1, 0, 1, 1, 0, 1, 0);
  67.   SetTriangle(7, 0, 0, 1, 0, 1, 0, 0, 0, 0);
  68.  
  69.   // TOP
  70.   SetTriangle(8, 0, 1, 0, 0, 1, 1, 1, 1, 1);
  71.   SetTriangle(9, 0, 1, 0, 1, 1, 1, 1, 1, 0);
  72.  
  73.   // BOTTOM
  74.   SetTriangle(10, 1, 0, 1, 0, 0, 1, 0, 0, 0);
  75.   SetTriangle(11, 1, 0, 1, 0, 0, 0, 1, 0, 0);
  76.  
  77. end;
  78.  
  79. procedure TfrmMain.pbDisplayPaint(Sender: TObject);
  80. var
  81.   bmp: TBitmap;
  82. begin
  83.   // Bitmap manipulation
  84.   bmp := TBitmap.Create;
  85.   bmp.Width := pbDisplay.Width;
  86.   bmp.Height := pbDisplay.Height;
  87.  
  88.   bmp.Canvas.Brush.Color := clBlack;
  89.   bmp.Canvas.Pen.Color := clWhite;
  90.   bmp.Canvas.Pen.Width := 1;
  91.  
  92.   // Drawing routine
  93.   DrawTriangles(bmp);
  94.  
  95.   // Draw test line
  96.   bmp.Canvas.Line(20,20, 300, 300);
  97.  
  98.   // Bitmap manipulation
  99.   pbDisplay.Canvas.Draw(0, 0, bmp);
  100.   bmp.Free;
  101.  
  102. end;
  103.  
  104. procedure TfrmMain.tmRefreshTimer(Sender: TObject);
  105. begin
  106.   pbDisplay.Refresh;
  107. end;
  108.  
  109. procedure TfrmMain.SetTriangle(n: integer; v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z: real);
  110. var
  111.   vec: Vector3D;
  112.   tri: Triangle;
  113. begin
  114.   vec.x := v1x;
  115.   vec.y := v1y;
  116.   vec.Z := v1z;
  117.   tri[0] := vec;
  118.   vec.x := v2x;
  119.   vec.y := v2y;
  120.   vec.Z := v2z;
  121.   tri[1] := vec;
  122.   vec.x := v3x;
  123.   vec.y := v3y;
  124.   vec.Z := v3z;
  125.   tri[2] := vec;
  126.   meshCube[n] := tri;                            // Pascal will copy the variable to the matrix
  127. end;
  128.  
  129. procedure TfrmMain.MultiplyMatrixVector(inVector: Vector3D; var outVector: Vector3D; inMatrix: Matrix4x4);
  130. var
  131.   w: double;
  132. begin
  133.   outVector.x := inVector.x * inMatrix[0, 0] + inVector.y * inMatrix[1, 0] + inVector.z * inMatrix[2, 0] + inMatrix[3, 0];
  134.   outVector.y := inVector.x * inMatrix[0, 1] + inVector.y * inMatrix[1, 1] + inVector.z * inMatrix[2, 1] + inMatrix[3, 1];
  135.   outVector.z := inVector.x * inMatrix[0, 2] + inVector.y * inMatrix[1, 2] + inVector.z * inMatrix[2, 2] + inMatrix[3, 2];
  136.   w := inVector.x * inMatrix[0, 3] + inVector.y * inMatrix[1, 3] + inVector.z * inMatrix[2, 3] + inMatrix[3, 3];
  137.  
  138.   if w <> 0 then
  139.   begin
  140.     outVector.x := outVector.x / w;
  141.     outVector.y := outVector.y / w;
  142.     outVector.z := outVector.z / w;
  143.   end;
  144. end;
  145.  
  146. function TfrmMain.MultiplyMatrixVector(inVector: Vector3D; inMatrix: Matrix4x4): Vector3D;
  147. var
  148.   x, y, z, w: double;
  149.   r: Vector3D;
  150. begin
  151.   x := inVector.x * inMatrix[0, 0] + inVector.y * inMatrix[1, 0] + inVector.z * inMatrix[2, 0] + inMatrix[3, 0];
  152.   y := inVector.x * inMatrix[0, 1] + inVector.y * inMatrix[1, 1] + inVector.z * inMatrix[2, 1] + inMatrix[3, 1];
  153.   z := inVector.x * inMatrix[0, 2] + inVector.y * inMatrix[1, 2] + inVector.z * inMatrix[2, 2] + inMatrix[3, 2];
  154.   w := inVector.x * inMatrix[0, 3] + inVector.y * inMatrix[1, 3] + inVector.z * inMatrix[2, 3] + inMatrix[3, 3];
  155.  
  156.   if w <> 0 then
  157.   begin
  158.     r.x := x / w;
  159.     r.y := y / w;
  160.     r.z := z / w;
  161.   end;
  162.  
  163.   Result := r;
  164. end;
  165.  
  166. procedure TfrmMain.DrawTriangles(var bmp: TBitmap);
  167. var
  168.   fNear: real;                                   // Near plane
  169.   fFar: real;                                    // Far plane
  170.   fFov: real;                                    // Field of view
  171.   fAspectRatio: real;                            // Aspect ratio
  172.   fFovRad: real;                                 // Tangent calculation
  173.   matProj: Matrix4x4;                            // Projection matrix
  174.   triProjected: Triangle;                        // Projected triangle
  175.   tri: Triangle;                                 // A triangle iterator
  176. begin
  177.   // Projection matrix
  178.   fNear := 0.1;
  179.   fFar := 1000.0;
  180.   fFov := 90.0;
  181.   fAspectRatio := pbDisplay.Height / pbDisplay.Width;
  182.   fFovRad := 1 / tan(fFov * 0.5 / 180 * pi);
  183.  
  184.   matProj[0, 0] := fAspectRatio * fFovRad;
  185.   matProj[1, 1] := fFovRad;
  186.   matProj[2, 2] := fFar / (fFar - fNear);
  187.   matProj[3, 2] := (-fFar * fNear) / (fFar - fNear);
  188.   matProj[2, 3] := 1.0;
  189.   matProj[3, 3] := 0.0;
  190.  
  191.   // Calculate projection
  192.   for tri in meshCube do
  193.   begin
  194.     triProjected[0] := MultiplyMatrixVector(tri[0], matProj);
  195.     triProjected[1] := MultiplyMatrixVector(tri[1], matProj);
  196.     triProjected[2] := MultiplyMatrixVector(tri[2], matProj);
  197.     //MultiplyMatrixVector(tri[0], triProjected[0], matProj);
  198.     //MultiplyMatrixVector(tri[1], triProjected[1], matProj);
  199.     //MultiplyMatrixVector(tri[2], triProjected[2], matProj);
  200.   end;
  201.  
  202.   bmp.Canvas.Line(trunc(triProjected[0].x), trunc(triProjected[0].y), trunc(triProjected[1].x), trunc(triProjected[1].y));
  203.   bmp.Canvas.Line(trunc(triProjected[1].x), trunc(triProjected[1].y), trunc(triProjected[2].x), trunc(triProjected[2].y));
  204.   bmp.Canvas.Line(trunc(triProjected[2].x), trunc(triProjected[2].y), trunc(triProjected[0].x), trunc(triProjected[0].y));
  205. end;
  206.  
  207. end.

The Routine where the error is thrown is MultiplyMatrixVector. And for the test I have actually made two routines: one is the procedure and the other is the function.
And in both, I get an error when dividing by 'w'. Unless I use SINGLE instead of DOUBLE in type and variable declaration.

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: Is this a bug? External: SIGFPE
« Reply #13 on: November 29, 2021, 10:16:52 pm »
Such numbers always look like uninitialized variables. And in fact, you do not initialize all elements of matProj. Call
Code: Pascal  [Select][+][-]
  1.   matProj := Default(Matrix4x4);
before you assign those 6 elements. This will certainly set the other elements to zero, and your code should work.
« Last Edit: November 29, 2021, 10:29:12 pm by wp »

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Is this a bug? External: SIGFPE
« Reply #14 on: November 29, 2021, 10:23:26 pm »
Hi!

You should protect this operations with a try  .. finaly bock:

Code: Pascal  [Select][+][-]
  1.  if w <> 0 then
  2.   begin
  3.     outVector.x := outVector.x / w;
  4.     outVector.y := outVector.y / w;
  5.     outVector.z := outVector.z / w;
  6.   end;

If an exception occurs then treat this exception.

Or do it like the C boys:

Set an exception mask for everything.
If the compiler does not complain everything is fine.
That's why you have to reboot windows often.
Because the errors are not detected anymore

Winni


 

TinyPortal © 2005-2018