Recent

Author Topic: Invalid Math Operations  (Read 4296 times)

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Invalid Math Operations
« on: June 23, 2018, 02:00:15 am »
Hi, seems that there are operations and or conversions that are not supported by the CPU.

I need a bit of theory here, because with this code:
https://github.com/bgrabitmap/demo/tree/master/superformula_ui

Or here:
https://github.com/bgrabitmap/demo/tree/master/superformula

Feeding it random values in each field, causes the SIGFPE.

If I use all 'Double', then an error converting to single is thrown. (For example the drawing of the line needs a 'Single' value).

If I go all 'Single', then there are errors in other parts of the code. (In the actual super formula 'r' function).

Sorry if this is supposed to know, I've not taken all subjects yet in University.

Edit: Ok, I found that's a floating point overflow, and that can be caused by the actual values, not all is possible to compute.
« Last Edit: June 23, 2018, 02:27:28 am by lainz »

Josh

  • Hero Member
  • *****
  • Posts: 1271
Re: Invalid Math Operations
« Reply #1 on: June 23, 2018, 08:30:15 am »
HI Lainz,

Could the issue be setting variables to mindouble; then calculating (sin/cos) based on such a small number could result in a zero result.. Setting your own MyMinDouble may help, that is not so small.

Code: [Select]
const mymindouble=mindouble;// you could try 0.000000000001;
var a:double=0;
    m:double=mymindouble;
    b:double=mymindouble;
    theta:double=mymindouble;
begin
  a:=sin(m * theta / 4) / b ;
  if a=0 then
  begin
    showmessage('equal to zero');
  end;
end;       
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: Invalid Math Operations
« Reply #2 on: June 23, 2018, 09:05:07 am »
Code: [Select]
const mymindouble=mindouble;// you could try 0.000000000001;
var a:double=0;
    m:double=mymindouble;
    b:double=mymindouble;
    theta:double=mymindouble;
begin
  a:=sin(m * theta / 4) / b ;
  //...
What do you expect?

You have m=theta=5e-324! So the argument of sin is m*theta/4 = 6.25E-648, which obviously underflows to zero and sin(0)=0!

And where is the invalid math operation?

And finally: the cos of very small arguments can never result in zero.
« Last Edit: June 23, 2018, 09:07:29 am by Gammatester »

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Invalid Math Operations
« Reply #3 on: June 23, 2018, 10:51:32 am »
HI Lainz,

Could the issue be setting variables to mindouble; then calculating (sin/cos) based on such a small number could result in a zero result.. Setting your own MyMinDouble may help, that is not so small.

Code: [Select]
var a:double=0;
begin
  a:=sin(m * theta / 4) / b ;
  if a=0 then
Due to round-off error in floating point calculations never make comparisons based on '=' but on SameValue and an appropriate tolerance value:
Code: Pascal  [Select][+][-]
  1. uses
  2.   Math;  // for "SameValue"
  3. const
  4.   EPS = 1E-9;
  5. ...
  6.   a := sin (a * theta/t) / 4;
  7.   if SameValue(a, 0.0, EPS) then
  8.  

Gammatester

  • Jr. Member
  • **
  • Posts: 69
Re: Invalid Math Operations
« Reply #4 on: June 23, 2018, 11:15:11 am »
Due to round-off error in floating point calculations never make comparisons based on '=' but on SameValue and an appropriate tolerance value:
Code: Pascal  [Select][+][-]
  1. uses
  2.   Math;  // for "SameValue"
  3. const
  4.   EPS = 1E-9;
  5. ...
  6.   a := sin (a * theta/t) / 4;
  7.   if SameValue(a, 0.0, EPS) then
  8.  
Comparisons against zero is almost never a problem. Especially in this case, where you know that a is zero because 1. the argument is zero, 2. sin(0)=0.

The problem in the OP is, that the superformula is coded far too complicated (power(power(cos(..),n2) + power(sin(..),n3), n1) with unrelated variables). A start would be to breakup the formula and check, whether for small values it can be solved asymptotically. Otherwise the value is even mathematically undefined for the independent limits-to-zero of the variables.

One critical part is

power(abs(sin(m * theta / 4) / b), n3), -1 / n1)

with m=theta=n1=mindouble this tries to compute power(0, -2e323) which obviously overflows. Even if n1 is not that small, power(0, -1/n1) will crash because the power of zero with a negative real exponent is invalid!
« Last Edit: June 23, 2018, 11:41:05 am by Gammatester »

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Invalid Math Operations
« Reply #5 on: June 23, 2018, 11:49:56 am »
Comparisons against zero is almost never a problem. Especially in this case, where you know that a is zero because 1. the argument is zero, 2. sin(0)=0.
It certainly is a problem. Not in this case which is a constructed example (if you know that a is 0 from the beginning why should you calculate sin(a) after all?). But if a is the result of some calculation you never can be sure, even if mathematics tells you that it should be zero. Look at this example: The square of the square root of some number should be equal to that number - well, in numerics only: almost...
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. var
  3.   a, b: Double;
  4. begin
  5.   a := 3.0;
  6.   b := sqr(sqrt(a)) - a;
  7.   Write(b, ' is ');
  8.   if (b = 0) then
  9.     WriteLn('zero')
  10.   else
  11.     WriteLn('not zero');
  12.  
  13.   ReadLn;
  14. end.
Therefore it is good practice to never use the '=' operator in floating point calculations (in '>=' and '<=', too, BTW: instead of "if a >= b then"  write "if SameValue(a, b, EPS) or ( a > b) then...")

But you are right, it is not problem of the original question. Writing such a complex equation in a single instruction is a sin.
« Last Edit: June 23, 2018, 12:10:00 pm by wp »

BeanzMaster

  • Sr. Member
  • ****
  • Posts: 268
Re: Invalid Math Operations
« Reply #6 on: June 23, 2018, 12:04:20 pm »
HI Lainz,

Could the issue be setting variables to mindouble; then calculating (sin/cos) based on such a small number could result in a zero result.. Setting your own MyMinDouble may help, that is not so small.

Code: [Select]
const mymindouble=mindouble;// you could try 0.000000000001;
var a:double=0;
    m:double=mymindouble;
    b:double=mymindouble;
    theta:double=mymindouble;
begin
  a:=sin(m * theta / 4) / b ;
  if a=0 then
  begin
    showmessage('equal to zero');
  end;
end;       

Hi
it should be

Code: Pascal  [Select][+][-]
  1. const mymindouble=mindouble;// you could try 0.000000000001;
  2. var a:double=0;
  3.     m:double=mymindouble;
  4.     b:double=mymindouble;
  5.     theta:double=mymindouble;
  6. begin
  7.   a:=sin(m * theta / 4) / b ;
  8.   if a<=0 then
  9.   begin
  10.     showmessage('equal to zero');
  11.   end;
  12. end;

I suggest you change mindouble by one of this (depend of the resolution you want
Code: Pascal  [Select][+][-]
  1. Const
  2.   cEpsilon: Single = 1e-10;
  3.   cEpsilon40 : Single = 1E-40;
  4.   cEpsilon30 : Single = 1E-30;

To avoid SIGFPE in superformula demo at exit

Add :

Code: Pascal  [Select][+][-]
  1. Procedure TfrmSuperFormula.FormClose(Sender: TObject; Var CloseAction: TCloseAction);
  2. Begin
  3.   timer1.Enabled := false;
  4.   Application.OnIdle := nil;
  5. end;

You need stop timer  8)

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Invalid Math Operations
« Reply #7 on: June 23, 2018, 04:32:42 pm »
Thanks  :)

I will try to implement all your good suggestions.

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Invalid Math Operations
« Reply #8 on: June 24, 2018, 12:16:03 am »
I added a threshold to 0.1 in the numeric edits in the UI version, less graphics can be generated by the user, but it still was working... and then I try with combinations of big numbers and it can break as well.

I think as it's coded is not as safe to include into a paint application.. only to get the user losing his work.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Invalid Math Operations
« Reply #9 on: June 25, 2018, 12:03:59 pm »
The following replacement of your function r(...) does not crash your SuperFormula project any more up to t = 2000 when I gave up:

Code: Pascal  [Select][+][-]
  1. var
  2.   MAX_LOG: Double = 0.0;
  3.   MIN_LOG: Double = 0.0;
  4.   MAX_R: Double = 100.0;
  5.  
  6. function SafePower(a, b: Double; out c: Double): Boolean;
  7. var
  8.   tmp: Double;
  9. begin
  10.   Result := true;
  11.   if (a < 0) then
  12.     raise Exception.Create('1st argument of Power() must not be negative');
  13.   if (a = 0) then begin
  14.     if (b = 0) then
  15.       raise Exception.Create('Both arguments of Power() must not be zero.');
  16.     c := 0;
  17.     exit;
  18.   end;
  19.  
  20.   if MAX_LOG = 0.0 then
  21.     MAX_LOG := ln(MaxDouble);
  22.   if MIN_LOG = 0.0 then
  23.     MIN_LOG := ln(MinDouble);
  24.  
  25.   // ln(a^b) = b ln(a)
  26.   tmp := b * ln(a);
  27.   if tmp > MAX_LOG then
  28.     Result := false
  29.   else
  30.   if tmp < MIN_LOG then
  31.     c := 0.0
  32.   else
  33.     c := exp(tmp);
  34. end;
  35.  
  36. function r(theta, a, b, m, n1, n2, n3: double): double;
  37. const
  38.   EPS = 1E-9;
  39. var
  40.   c, pc, s, ps: Double;
  41. begin
  42.   if (a = 0) then
  43.     raise Exception.Create('a must not be zero.');
  44.   if (b = 0) then
  45.     raise Exception.Create('b must not be zero');
  46.   if (m = 0) then
  47.     raise Exception.Create('m must not be zero');
  48.   if (n1 = 0) then
  49.     raise Exception.Create('n1 must not be zero');
  50.   if (n2 = 0) then
  51.     raise Exception.Create('n2 must not be zero');
  52.   if (n3 = 0) then
  53.     raise Exception.Create('n3 must not be zero');
  54.  
  55.   c := abs(cos(m * theta / 4) / a);
  56.   if c < EPS then
  57.     pc := 0
  58.   else
  59.   if not SafePower(c, n2, pc) then begin
  60.     Result := MAX_R;
  61.     exit;
  62.   end;
  63.  
  64.   s := abs(sin(m * theta / 4) / b);
  65.   if s < EPS then
  66.     ps := 0
  67.   else
  68.   if not SafePower(s, n3, ps) then begin
  69.     Result := MAX_R;
  70.     exit;
  71.   end;
  72.  
  73.   if pc + ps < EPS then
  74.     Result := 0
  75.   else
  76.   if not SafePower(pc + ps, -1/n1, Result) then
  77.     Result := MAX_R;
  78.  
  79.   if Result > MAX_R then Result := MAX_R;
  80. end;

lainz

  • Hero Member
  • *****
  • Posts: 4460
    • https://lainz.github.io/
Re: Invalid Math Operations
« Reply #10 on: June 25, 2018, 02:06:14 pm »
Thanks @wp  :) I will try again.

 

TinyPortal © 2005-2018