drjrm3
drjrm3

Reputation: 4728

Turn off Warning: Extension: Conversion from LOGICAL(4) to INTEGER(4) at (1) for gfortran?

I am intentionally casting an array of boolean values to integers but I get this warning:

Warning: Extension: Conversion from LOGICAL(4) to INTEGER(4) at (1)

which I don't want. Can I either

(1) Turn off that warning in the Makefile?

or (more favorably)

(2) Explicitly make this cast in the code so that the compiler doesn't need to worry?

The code will looking something like this:

A = (B.eq.0)

where A and B are both size (n,1) integer arrays. B will be filled with integers ranging from 0 to 3. I need to use this type of command again later with something like A = (B.eq.1) and I need A to be an integer array where it is 1 if and only if B is the requested integer, otherwise it should be 0. These should act as boolean values (1 for .true., 0 for .false.), but I am going to be using them in matrix operations and summations where they will be converted to floating point values (when necessary) for division, so logical values are not optimal in this circumstance.

Specifically, I am looking for the fastest, most vectorized version of this command. It is easy to write a wrapper for testing elements, but I want this to be a vectorized operation for efficiency.

I am currently compiling with gfortran, but would like whatever methods are used to also work in ifort as I will be compiling with intel compilers down the road.

update:

Both merge and where work perfectly for the example in question. I will look into performance metrics on these and select the best for vectorization. I am also interested in how this will work with matrices, not just arrays, but that was not my original question so I will post a new one unless someone wants to expand their answer to how this might be adapted for matrices.

Upvotes: 2

Views: 1356

Answers (3)

agentp
agentp

Reputation: 6999

For this particular example you could avoid the logical all together:

 A=1-(3-B)/3

Of course not so good for readability, but it might be ok performance-wise.

Edit, running performance tests this is 2-3 x faster than the where construct, and of course absolutely standards conforming. In fact you can throw in an absolute value and generalize as:

 integer,parameter :: h=huge(1)
 A=1-(h-abs(B))/h

and still beat the where loop.

Upvotes: 1

Alexander Vogt
Alexander Vogt

Reputation: 18118

I have not found a compiler option to solve (1).

However, the type conversion is pretty simple. The documentation for gfortran specifies that .true. is mapped to 1, and false to 0.

Note that the conversion is not specified by the standard, and different values could be used by other compilers. Specifically, you should not depend on the exact values.

A simple merge will do the trick for scalars and arrays:

program test
  integer :: int_sca, int_vec(3)
  logical :: log_sca, log_vec(3)

  log_sca = .true.
  log_vec = [ .true., .false., .true. ]

  int_sca = merge( 1, 0, log_sca )
  int_vec = merge( 1, 0, log_vec )

  print *, int_sca
  print *, int_vec
end program

To address your updated question, this is trivial to do with merge:

A = merge(1, 0, B == 0)

This can be performed on scalars and arrays of arbitrary dimensions. For the latter, this can easily be vectorized be the compiler. You should consult the manual of your compiler for that, though.

The where statement in Casey's answer can be extended in the same way.


Since you convert them to floats later on, why not assign them as floats right away? Assuming that A is real, this could look like:

A = merge(1., 0., B == 0)

Upvotes: 2

casey
casey

Reputation: 6915

Another method to compliment @AlexanderVogt is to use the where construct.

program test
  implicit none
  integer :: int_vec(5)
  logical :: log_vec(5)

  log_vec = [ .true., .true., .false., .true., .false. ]

  where (log_vec)
     int_vec = 1
  elsewhere
     int_vec = 0
  end where

  print *, log_vec
  print *, int_vec
end program test

This will assign 1 to the elements of int_vec that correspond to true elements of log_vec and 0 to the others.

The where construct will work for any rank array.

Upvotes: 1

Related Questions