Search code examples
floating-pointruntime-errorpascalfpc

Why am I'm getting an Error 207 (invalid floating point operation)/ How to get around it?


program cosseno;
var fat1, fat2, n1, n2, cont1, cont2, s :real;
begin
  s := 0.5;
  fat1 := 24;
  fat2 := 720;
  n1 := 1/fat1;
  n2 := 1/fat2;
  cont1 := 8;
  cont2 := 10;

  while (n1 - n2) > 0.000001 do
  begin
    fat1 := (cont1) * (cont1-1) * (cont1-2) * (cont1-3) * fat1;
    fat2 := (cont2) * (cont2-1) * (cont2-2) * (cont2-3) * fat2;
    cont1 := cont1 + 4;
    cont2 := cont2 + 4;
    n1 := n1 + 1/fat1;
    n2 := n2 + 1/fat2;
  end;

  s := s + n1 - n2;
  writeln(s);
end.

This is a program to estimate e value of cos(1 rad), apparently, the error occurs within the while section.


Solution

  • The Problem

    The issue is that your variable fat1 is getting too big and overflowing. With free pascal, your code causes a 205 error (Floating point overflow). This is similar to a 207 Invalid floating point operation - free pascal run-time error codes. The real types that are relevant to your code have the following constraints (from the free pascal data types wiki page):

    Type       Range                   Significant digits   Bytes
    Real       platform dependent      ???                  4 or 8
    Single     1.5E-45 .. 3.4E38       7-8                  4
    Double     5.0E-324 .. 1.7E308     15-16                8
    Extended   1.9E-4932 .. 1.1E4932   19-20                10
    

    The Work Around

    You simply need to account for the possibility of overflow with your largest variable. It is not possible to simply check if the variable is above it's max value so you should do the reverse of the operation that could cause the overflow. I also used Extended to have a better estimate.

    var max_fat : Extended = 1.1 * power(10,4932);
    var should_step : Extended= max_fat / (cont1) / (cont1-1) / (cont1-2) / (cont1-3);
    

    then in your while loop include the check:

    fat1 < should_step
    

    The result of this reverse operation is the maximum that the variable fat1 can be before it overflows. I use the Math library to help calculate the maximum Extended. The following test code works for me:

    program cosseno;
    
    Uses Math;
    
    var fat1, fat2, n1, n2, cont1, cont2, s, max_fat, should_step : Extended;
       begin
          s := 0.5;
          fat1 := 24;
          fat2 := 720;
          n1 := 1/fat1;
          n2 := 1/fat2;
          cont1 := 8;
          cont2 := 10;
    
          max_fat := 1.1 * power(10,4932);
    
          should_step := max_fat;
    
          while ((n1 - n2) > 0.000001) AND (fat1 < should_step) do
           begin
              should_step := max_fat / (cont1) / (cont1-1) / (cont1-2) / (cont1-3);
    
              fat1 := (cont1) * (cont1-1) * (cont1-2) * (cont1-3) * fat1;
              fat2 := (cont2) * (cont2-1) * (cont2-2) * (cont2-3) * fat2;
              cont1 := cont1 + 4;
              cont2 := cont2 + 4;
              n1 := n1 + 1/fat1;
              n2 := n2 + 1/fat2;
              writeln('fat1  > ', fat1);
              writeln('fat2  > ', fat2);
              writeln('cont1 > ', cont1);
              writeln('cont2 > ', cont2);
              writeln('n1    > ', n1);
              writeln('n2    > ', n2);
           end;
    
          s := s + n1 - n2;
          writeln('<==================>');
          writeln(s);
       end.
    

    The code yields the following result:

    5.40302305868139717414E-0001
    

    which I checked to be correct for at least the first 10 digits.