Trouble with reading floats from ascii file

Hi,

When reading data from an ascii file, I have this error :
Program received signal SIGFPE: Floating-point exception - erroneous arithmetic operation

This error occurs when reading the value 6.969d-39 from the text file. When I change that value to 6.969d-09, the error disappears. This error happens with a variable being of type REAL64 or REAL128. I am quite surprised because I assumed that 1e-39 is well within the limits of REAL64. I am reading that value with free format : fmt=*.

When writing the minimal example below quite the same way as in my project, the error does not occur for an ascii file with the value 6.969d-39 !

program read
        use iso_fortran_env, only:REAL128
        INTEGER, PARAMETER :: DBL = KIND(REAL128)
        integer :: fUnit
        real(DBL) :: val1,val2,val3
        integer :: i

        open(newunit=fUnit, file = 'temp.txt',action='read')
        read(fUnit,*) i,val1,val2,val3
        write(*,*) i,val1,val2,val3
        close(fUnit)

end program read

the text file contains one line which is the same as in my project where the error occurs:
2 6.969d-39 0.5 0

Could someone help me ? It’s driving me mad

It runs without problem in my Ubuntu 23.10 (GFortran 13.2.0 & ifx 2024.1.0):

$ gfortran f.f90 && ./a.out
           2   6.96900058E-39  0.500000000       0.00000000    
$ ifx f.f90 && ./a.out
           2  6.9690006E-39  0.5000000      0.0000000E+00
$ file temp.txt
temp.txt: ASCII text

What OS, processor and compiler do you have? Or could it be a problem of coding in your text file?

@Vmagnin,

The sample runs fine either with my ubuntu 22.04 with gfortran-10 (with -g option). I simply do not succeed in having a minimal example producing the same error. For that minimal code, I just put the same read line, the exact same kind of variable on the same line of file, so the reading context is more or less the same as in my real-life project.
In my real project (to big to show there), what is weird is that by changing the exponential part of the floating point number from d-39 to d-09, my projects switches from not running to running fine.
Thanx

1 Like

I suspect the issue is in the way you define the kind of the real variables.
What you mean is different from what you coded.
real32/64/128 from iso_fortran_env intrinsic module are already real kinds parameters.
If you take their kind, you are actually querying the kind of the underlying integer used to define them.

program test
   use iso_fortran_env
   implicit none
   integer, parameter :: DBL = kind(real128)
   real(DBL)     :: not_a_r128
   real(real128) :: r_128

   print *, kind(not_a_r128)
   print *, kind(r_128)

end program test

outputs

           4
          16

with both GFortran 10 and 13.

2 Likes

@mEM,

you are right. How stupid I am ! It is a pity that the compiler get it through … The blame is also on me because I did not pay enough attention to a few warnings in visualstudio code indicating the use of real(4) :frowning:
Thank you but I am sorry for the time you spent for that. I will use the -Wall option and make all the fix required from now on!

No worries, we all learn from our coding mistakes.

Just you to know (if you didn’t do it already), in case there are lots of usages of real(DBL) as you show,
just change the line to

integer, parameter :: DBL = real128

Otherwise, I think it is more expressive (and avoids definition of a parameter copy basically) to use real(real128) throughout the code base.

yep, that’s exacly what I did

integer, parameter :: DBL = real128

Regarding using real(real128), I took the DBL idea from “chapman’s fortran for scientists and engineers”. It has the advantage that if I want to switch from real128 to real64, I just have to change it at a single file at a single location without introducing possible mistakes. Anyway, you are right, it is less expressive.

Then, I would have used a different kind parameter name, something like RK (real kind), to express the fact that reals declared as real(RK) might be of any desired kind.
By itself, DBL closely recalls the intrinsic double precision, which is directly linked to the default kind of simple real variables.
But yeah, finally choose a name that you are comfortable with.

2 Likes

I will follow your good advice DBL to RK :slight_smile:

Yes, or WP like working precision.

Finally, note that the bug could have been avoided by simply renaming the kind:

use iso_fortran_env, only: RK=>REAL128
1 Like

Well, @vmagnin, it is the demonstration that I am even more stupid than I thought, since I’m doing what you are suggesting, for stdout => output_unit … I should I think of your nice proposal by myself !

1 Like

One less line, one less bug!

2 Likes

A programmer would do this when he wants to hide REAL128 (and the other REAL* parameters too). If the programmer wants to have those parameters available, and also define a local RK, then a parameter definition is appropriate.

Here is a  run on mint linux. i saved the program s an f.08 file.

ian@ian-Latitude-E7440:~$ nano temp.txt
ian@ian-Latitude-E7440:~$ ./a.out
           2   6.96900058E-39  0.500000000       0.00000000    
ian@ian-Latitude-E7440:~$ cat temp.txt
2 6.969d-39 0.5 0
ian@ian-Latitude-E7440:~$ cat testx.f08
program read
        use iso_fortran_env, only:REAL128
        INTEGER, PARAMETER :: DBL = KIND(REAL128)
        integer :: fUnit
        real(DBL) :: val1,val2,val3
        integer :: i

        open(newunit=fUnit, file = 'temp.txt',action='read')
        read(fUnit,*) i,val1,val2,val3
        write(*,*) i,val1,val2,val3
        close(fUnit)

end program read
ian@ian-Latitude-E7440:~$

Your version of the test program is also deceptive. The variables val1, val2, val3 are single precision, despite being declared to have the kind DBL. To see that, add the following PRINT statement and run:

print *,epsilon(val1),huge(val2),tiny(val3)

I’m curious why you’re not using the correct input format?

read(fUnit,“(i,3f)”) i,val1,val2,val3

It’s strange to read it without… Am I missing something.

Knarfnarf

@Knarfnarf

My compiler (gfortran10) tells me when i try to compile read(fUnit,“(i,3f)”) i,val1,val2,val3 :
Nonnegative width required in format string at (1) (1) referring to i.
So I am using free format… May be I do something wrong once again !

Yes, that format is nonsense. Maybe it was corrupted by the display formatting. If you want to avoid using list-directed i/o, you can also experiment with the g format field. Here is a small example:

program g
   integer :: i = -99
   real :: val(3) = [1.0, -10., 1000.0]
   write(*,*) i, val
   write(*,'(*(g0,1x))') i, val
   write(*,'(*(g0.2,1x))') i, val
end program g

$ gfortran g.f90 && a.out
         -99   1.00000000      -10.0000000       1000.00000    
-99 1.00000000 -10.0000000 1000.00000
-99 1.0 -10. 0.10E+4

Silly me! I forgot you have to give it the number of characters on input. My fault! So given what you are reading, you might not be able to dictate those numbers!.. Ouch…

I also didn’t notice that 6.969d-39 doesn’t look right… Isn’t that supposed to be 6.969e-39?..

Knarfnarf