Conversion from real to integer

I recently posted, then deleted, a question asking how Fortran goes about converting a real(8) into an integer. I realised as I was writing it that the most likely approach is the same as applying INT to the equation.

So, I did some checking and, yes, that seemed to be correct.

I went through my code, looking for all relevant warnings, and added INT at the correct locations.

Now the code breaks earlier.

However, could this be because the real value it is using exceeds the maximum/minimum value representable by the integer?

This is, again, where I am getting an error, suddenly, about a variable being out of bounds:

Fortran runtime error: Index '-2147483230' of dimension 1 of array 'iptr' below lower bound of 1

This particular subroutine is where I have used INT to resolve a warning of a Possible change of value from REAL(8) to INTEGER(4).

If I ignore the warning, the system continues on to another error (one I am still seeking to resolve). However, if I use INT then it fails with the above index error.

I am wondering if the conversion through INT is causing the value to exceed the value limit of INTEGER?

For real kind REAL64, the value REAL(HUGE(1),KIND=REAL64) can be represented exactly. So just compare this value to whatever real value is being converted to see if it is too large.

I am sorry, @RonShepard, but I haven’t gotten my head completely around this KIND thing. I have used the KIND aspect that you defined for me previously to define all of my REAL values. So, I have this definition in my one module, that I access throughout my programs…

integer, parameter :: DP = kind(0.d0)

And then, I define all of my variables in context with this, for example…

real(DP) :: rtau(mtau), rtau23, zmtau(mtau)

I then use this, again, for all floating point values throughout my code. For example…

taux = -1._DP

However, I have then exhausted my understanding, and what you have defined above doesn’t make sense to me.

I did try reading this up but I found the write-ups confusing; with little relevance to what I was doing.

So, might I ask you to humour me a little; what do you mean by the above in context with the REAL and INTEGER issue?

Sure, Fortran integers can go far lower than 64 bits reals, so before conversion you should test the real value. Using integer(int64) (int64 is a KIND defined in the iso_fortran_env module) you could go higher, but still far lower than 64 bits reals.

That aside, I often use NINT() (nearest integer) instead of INT().

In your original post, you were using integer literal kind values of 8 for real and 4 for integer. As you use fortran more, you will find that literal kind values are inconvenient, and sometimes even nonportable. In your later post, you are defining DP as the kind value, and it almost certainly has the value of 8. In my reply, I used REAL64, which is a parameter in the iso_fortran_env module. It almost certainly has the value of 8 too. So the expression I gave before REAL(HUGE(1),KIND=REAL64) first takes the largest possible integer value of default kind (kind=4 in your case), and converts it to a real 64-bit floating point value (kind=8 in your case). That value, which may be stored in a parameter if you want, can then be used to compare floating point values in your code. If your floating point value X is larger in magnitude than that limit, then it cannot be converted back to INT(X) without losing information. If you try, then you might get an exception (which I think is what you are seeing in your code), or you might get silently an incorrect integer.

The fortran KIND system is one of the nicest things about the language. It is powerful, flexible, concise, and open ended. No other popular language has anything comparable.

Where? I don’t see it.

It’s likely OP is running into integer overflow with the use of INT intrinsic, effectively along the following lines:

   integer, parameter :: DP = kind(0.d0)
   real(DP) :: x
   integer :: idx, incr
   x = 3E9_dp !<-- some large value greater than 2**31
   idx = int( x )  !<-- likely source of trouble
   incr = 418
   print *, "array index with iptr: ", idx + incr
end
C:\temp>gfortran -ffree-form p.f -o p.exe

C:\temp>p.exe
 array index with iptr:  -2147483230

Thus the action is to check, preferably in a debugger GDB or perhaps more easily using Visual Studio IDE with Intel Fortran, the conversion being done with INT.

Whatever the (too big) value of x, gfortran and ifort always print -2147483230
but ifx prints 0

I have reliably used INT, NINT or DBLE when converting between REAL(8) and INTEGER(4), but now going to 64-bit and INTEGER(8), you now have to include all the KIND labelling for these intrinsic functions, which may not surprise, I find this a failure in the standard.
What a mess for what was once anticipated to be the solution that generic intrinsics offered.

1 Like

There is an intrinsic function named ANINT returns the nearest whole REAL number to a given value (ie AINIT(3.123) will return 3.0, AINIT(3.7) will return 4.0). Not sure what the OPs application is but if he only needs the nearest whole number (ie truncated or rounded) then he might could just use ANINT.

Why not just NINT ?

NINT is of type INTEGER. ANINT is of type REAL. If the conversion is being applied to a term in an expression, the types of the expression and the type of the variable being assigned a value should be considered in choosing between NINT, ANINT, etc.

Thank you, everyone, for your comments, etc.

I did further reading (again) around the KIND aspect and think I do need to introduce this in terms of all my variable declarations. I primarily only have REAL and INTEGER, so this would not be difficult (all REAL values are defined in terms of KIND, anyway).

It was really nice to see @FortranFan comment again. As usual, you have helped identify what I think is going on, and given a good example of the issue. I was particularly excited to see the same value come out but then @vmagnin brought in reality. :slight_smile:

I need to identify WHAT the REAL value is, and what it becomes when Fortran is left to do its own thing. Then I should be able to identify the best approach. I had been using INT but, as @JohnCampbell pointed out, NINT might be a better option.

@rwmsu, I am trying to update a stellar evolution model system. I had gotten to a very good point, thinking I had finished, about a month and a half ago, but kept encountering an issue when using the Windows compiler. Knowing that this was showing there was still an issue in the code, likely to cause an issue later, I explored further and found that the system crashed under specific conditions on all platforms.

So, all double precision values are defined as REAL(8), using the KIND parameter definition I have given above. I then have a series of INTEGERs, but these are the default integer definitions that rely upon the individual compiler definitions. Aside from that I have a small number of CHARACTERs and LOGICALs - that’s it.

The array being addressed (iptr) is a 1 dimension array with a magnitude of 1391; nothing near the integer limit. So, I find it peculiar that simply adding INT causes this out of bound error.

I have had to rest for a short while (rest would be the wrong term; I have other issues I need to sort out, beyond simply this code), but will test again under GDB. I did try to get VS working with Fortran, @FortranFan, but I will try again. I have been using GFortran but might swap to INTEL Fortran, if it works well with VS. Would that be your advice?

1 Like

But you are computing the index array by taking the INT() of a real number, isn’t it? In at least one of these computations, you are exceeding the Integer range, and with your compiler it results with a huge negative number. The compiler just complains that this index value is <1 (out of your array iptr).

Fortran runtime error: Index '-2147483230' of dimension 1 of array 'iptr' below lower bound of 1

The problem is in the computation of those real numbers.

Yes. The index value is calculated through a series of equations, all using REAL values, to index to use.
The system seems happy if I leave it as a conversion of REAL to INTEGER by the system but as soon as I use INT I get the error notice; a huge negative value.

OK, so an implicit conversion is working but not an explicit one. Can you post that line with the explicit conversion?

Re: “reality”, please note if you are primarily using gfortran, then the integer overflow scenario as hinted at in the actual program per the original post is the same as in the silly, little reproducer I posted. The intent with such reproducers, as always, is to give everyone an immediate and clear view and insight into the issue.

Yes, but do note the intent is not to imply migrating away from gfortran on to Intel Fortran or any such notion but rather to seek two general benefits:

  1. clearer and more performant code via graphical debugging. Being able to step through any and all sections of one’s code in a graphical debugger in an IDE brings insight into the code and computations like nothing else, and this has proven again and again to be of great help. This is where the Visual Studio, the world’s most used IDE, comes in handy in conjunction with Intel Fortran because it so happens Intel is now making their toolchain freely available.

  2. portable code. The legacy and the status of Fortran is such working with two or more different compilers help reveal issues and lead to more portable codebase that is closer to being conformant to the standard. This can also enable future researchers to pick up on the work and continue to advance the endeavor more readily than otherwise. Hence working with both gfortran and Intel Fortran toward the code development and cross-checking the computational results is sound research practice, a very, very basic element of the scientific method when it comes to the so-called third leg, computational, to complement theory and experiment.

1 Like

Page 381 of the Fortran 2018 Draft:

Case (ii):
If A is of type real, there are two cases: if |A| < 1, INT (A) has the value 0; if |A| ≥ 1, INT (A)
is the integer whose magnitude is the largest integer that does not exceed the magnitude of A and
whose sign is the same as the sign of A.

The standard does not say what happens if this integer is outside the range of the integer KIND. And indeed, ifort and ifx do not give the same result.

But page 345 there is IEEE_INT (A, ROUND [, KIND]):

Result Value. The result has the value specified by ISO/IEC/IEEE 60559:2011 for the convertToInteger{round} or the convertToIntegerExact{round} operation; the processor shall consistently choose which operation it provides. That is, the value of A is converted to an integer according to the rounding mode specified by ROUND;
if this value is representable in the representation method of the result, the result has this value, otherwise IEEE_-INVALID is signaled and the result is processor dependent. If the processor provides the convertToIntegerExact operation, IEEE_INVALID did not signal, and the value of the result differs from that of A, IEEE_INEXACT will be signaled.

   CALL IEEE_SET_HALTING_MODE (IEEE_INVALID, .TRUE.)
   x = 4E9_dp !<-- some large value greater than 2**31
   idx = IEEE_INT(x, IEEE_DOWN)
$ ifx int.f90 && ./a.out
forrtl: error (65): floating invalid
1 Like

Yes, thank you. The reason for looking to move is not to the individual compiler itself; GFortran has been an excellent compiler up to now. It is purely the integration with Visual Studio and what that gives me that helps considerably.

Sorry, did not quite understand your first point.

I must be careful in my terms, so not to confuse.
ALL variables are defined EXPLICTLY.
What I meant my implicit was simply that, where I left the compiler to resolve the REAL to INTEGER conversion and, explicitly where I stated it’s conversion by using the INT statement.

I think in all situations, with any possible real and integer kind values, the two statements

i = x
i = int(x,kind(i))

should be exactly equivalent. By “exactly equivalent” I mean that the compiled instructions should be the same.

However, if kind(i) is not the default integer kind, then these above statements would not be equivalent to

i=int(x)
i=int(x,kind(0))
i=int(int(x),kind(i))
i=int(int(x,kind(0)),kind(i))

which are all exactly equivalent to each other. I tried to write this sequence so that the implicit conversions are replaced with more and more explicit conversions. Note that in these expressions, two integer conversions are performed rather than just the one. That might not be obvious in the first two statements in this group. Information can be lost during either or both of those conversions, depending on the kind values involved.

I think your expressions involve only the default integer kind, so this last situation is not occurring, but it is something that can happen with mixed-kind and mixed-type arithmetic. The good thing is that the programmer does have complete control over which types are converted and which kind values are involved, but some extra typing is sometimes required to get exactly what the programmer intends.