4

What would be a quick and accurate way of initializing a complex array? Are there any differences in the following:

complex(real64) :: x(2,2)
x = 0
x = 0d0
x = (0d0,0d0)

Are they the same and can I assume I get the same result on every compiler? Does the standard say anything about it? The question is specifically about initializing to zero, not any other number.

Raul Laasner
  • 1,475
  • 1
  • 17
  • 30
  • Because of your "quick" I read the question as asking about whether a compiler may do different things (being quicker at runtime), but given your comment to my answer this may actually be brevity/quickness in writing? – francescalus Jan 24 '16 at 00:26
  • Yes, quick meant brevity in writing. Any time saved by writing `(0d0,0d0)` and avoiding an implicit conversion may be considered negligible. Ideally, I would write `x=0`, which save me some seconds and is good for readability. However, this is scientific code and I need to be sure exactly what goes on at the low level. I have access to only gfortran and ifort currently and for them there is indeed no difference in the assignments. – Raul Laasner Jan 24 '16 at 00:33

1 Answers1

4

Before coming to the real answer, a note about terminology. In Fortran what you have here is not initialization but assignment. These are two distinct things. Yes, it's clear what is meant here but it's perhaps good to become aware of the distinction.

The lines like x=0 are intrinsic assignment statements. To the left of = is the variable and to the right the expression. For each of these in the question there are two considerations:

  • the variable and expression may differ in type or type parameter;
  • the variable is an array and the expression a scalar.

As stated in a related answer, when the variable and expression differ in type or type parameter (but are type conformable as in this case) the expression is converted to the type and type parameter of the variable.

The first two assignments certainly involve type conversion: 0 is an integer and 0d0 is a (double precision) real. Although (0d0, 0d0) is a complex - so there is no type conversion - this will be of different kind unless double precision is the same as real(real64).

So, for at least the first two we have conversion like the equivalent

x = CMPLX(0, KIND=real64)
x = CMPLX(0d0, KIND=real64)

and for the third perhaps

x = CMPLX((0d0, 0d0), KIND=real64)

With

x = (0._real64, 0._real64)

we can be sure the kinds of the variable and the expression are the same.

As long as CMPLX(0, KIND=real64) has the same value as (0._real64, 0._real64) you can be sure that the assignment x=0 (for now, for scalar x) has the same effect as x=(0._real64, 0._real64). This is mandated by the Fortran standard.

Zero is somewhat of a special case in that it appears in every model number set, but whenever a (mathematical) number is used which can be exactly represented in all three the effect will be the same. Equally,

x = 3.14_real64

and

x = (3.14_real64, 0._real64)

are equivalent.

Perhaps worth noting, though, is that some compilers with some options may offer warnings about implicit conversion. That is one difference to be observed even with the numeric values being equivalent.

Coming to the array/scalar aspect: the expression is treated as though it is an array of the same shape as the variable with every element equal to that scalar value.

To conclude: each of those three assignments has the same Fortran-effect. After the assignment x is an array of given shape with each element having complex value (0._real64, 0._real64).

Now, that isn't to say that there won't be a possibility of something exciting happening at a low level, and that zero-setting may be a special case. But that's something between you and your compiler (and system).

Community
  • 1
  • 1
francescalus
  • 30,576
  • 16
  • 61
  • 96
  • Thanks, indeed I meant assignment in Fortran terms. Can I infer from your last paragraph that the answer is no to my question or that you don't know for sure? My suspicion is that the conversion of zero is always without loss of accuracy. If it were something like 3.14 all three assignments would clearly be different. – Raul Laasner Jan 23 '16 at 23:40
  • Zero is partly a special case in that that value is exactly representable (I suppose really bizarre exceptions may exist) in each of the three representations `integer`, `double precision` and `real(real64)`. Other small magnitude integers also will be, so that's the limit of "special". `3.14` is perhaps a bad example as that's no integer, but `x=3.14` and `x=3.14d0` are likely to give different results but that's down to the literal constants themselves and the approximation by each type and not the subsequent conversion to complex/`real(real64)`. – francescalus Jan 24 '16 at 00:03
  • To correct my previous comment: zero explicitly exists in every model number set. Which other (mathematical) numbers can be represented exactly in each model will depend on the models, but at a practical level 1 will be but 3.14 won't be. – francescalus Jan 24 '16 at 00:26
  • Okay, I conclude then that such assignments with zero are safe. If it were any other number, including an integer, I would always write the assignment in full. – Raul Laasner Jan 24 '16 at 00:41
  • About compiler warnings. The compiler only issues a warning if the RHS is losing some digits, e.g., when assigning 1d0 to a 32-bit real, but not the other the other way around, e.g., assigning 1.0 to a 64-bit real. – Raul Laasner Jan 24 '16 at 00:58
  • Regarding gfortran if that's what you meant, I should [perhaps have remembered that](http://stackoverflow.com/q/32054301). But others may behave differently. Like you, I try to avoid writing too much more than I have to, so will rely on the defined behaviour of implicit conversion (making compiler warnings generally too noisy). – francescalus Jan 24 '16 at 01:03