Closed klausler closed 5 years ago
Are type conversions in calls to specific intrinsic functions standard compliant or is it an extension ?
Nag is also refusing the example code telling that the argument has the wrong type, all other compilers (gfortran, pgfortran, xlf, ifort) are silently accepting it. If the code is changed to have j
be a real
, then all compiler are raising an error but pgfortran that emits a warning about type conversions.
Simply removing the error would contradict with #661 .
What should f18 do:
float(0.4)
and float(1_2)
) (I would go for this one, easy to implement and easy to understand for the user)float(1_2)
) and emit error on type category conversion (e.g for float(0.4)
)I am fine with having a silent conversion for all cases that don't reduce precision. Compilers should emit warnings only when there's a potential problem that needs attention.
@sscalpone I add you to the discussion because you opened #661, so you may have an opinion. Problem:
I started a branch to convert argument as needed just to find out that it gave different result on edge cases compared with other compilers.... After investigating more, it turns out it is not only a warning/no warning issue. It seems there is at least two ways to handle the problem of specific intrinsic calls with "non-standard" argument types (bad kind), and different compilers make different choices:
float
(and maybe sngl
)). Note that this was also f18 behavior before I fixed #661.float
and maybe sngl
).Making a type conversion vs selecting the generic can give significantly different numerical results, even in cases where the inserted conversion would not be narrowing... Compilers may not even attribute the same kind to the intrinsic call expressions depending on the choice they make. Attached is a table with numerical discrepancies I could observe on a subset of the specific intrinsic. A few examples:
iabs(-17000_2)*iabs(2_2)
resolve to 34000
for pgfortran but -31536
for ifort and xlf. These three compilers remain silent when compiling....
(dprod(1.5, 1.0000000192_8)-1.5000001788)*10000000.+1.05
resolve to -0.14
with pgfortran (does not emit warning when expr is constant folded, else it warns about a conversion) but 0.14
with ifort (no warnings).
More in: NonStandardSpecificIntrinsicCalls.xlsx
Proposed solution:
For float
(resp. sngl
) transform the arguments to accept AnyInt
(resp. AnyReal
). This will be as if the specific was replaced by the generic and is most likely harmless because these two functions are restricted. These "ad-hoc" handling may be required to support some code out there (prroof being this bug was opened and gfortran allow these deviations). Also, all compilers agree on the behavior for these intrinsics. Note that float(real)
( resp sngl(integer)
) will remain forbidden which is in line with most compilers but pgfortran which silently accepts it.
For all other specific intrinsics, do not allow calls with wrong argument types. This is in line with nag and gfortran. I think it is better to forbid it because: 1. I do not know which side to follow. Sometimes I would say it is better to make the conversion (iabs
example), sometimes the generic seems like a better choice if a conversion step can be avoided and the result is more accurate. 2. I think it would make the switch to f18 a longer journey for people to chase numerical discrepancies rather than to face an hard error and fix it (selecting the ad-hoc way of solving it based on their needs).
Do you agree with the proposed solution ?
Where an "unrestricted specific intrinsic function" from Table 16.2 or 16.3 has the same name as the generic to which it maps, it would be confusing if it did not work like the generic does, so it should do so. (The generic DPROD
is defined (16.9.64) as requiring default real arguments.)
Where an "unrestricted specific intrinsic function" from Table 16.2 does not have same name as the generic, I am okay with requiring strict typing: ALOG, ALOG10, AMOD, CABS, CCOS, CEXP, CLOG, CSQRT
, DABS
through DEXP
, DINT
through DNINT
, DSIGN
through DTANH
, IABS, IDIM, IDNINT, & ISIGN
.
However, for the cases of intrinsic functions that represent type conversions (these are the numeric "restricted specific intrinsic functions" of Table 16.3, as well as the legacy extensions for double complex), the purpose of the intrinsic is to produce its fixed result type. I don't see a problem allowing other argument types. Specifically, the entire purpose of FLOAT
/SNGL
is to convert to default REAL; the purpose of IDINT
/IFIX
is to convert to default INTEGER. It would seem weird to require a program to convert an argument to a type conversion function, especially when modern codes should just be using INT
and REAL
generic intrinsic functions instead.
(The variants of MAX
and MIN
in 16.3 are defined as a generic MAX
or MIN
followed by a conversion and that seems fine to me.)
no longer works, and elicits
error: Actual argument for 'i=' has bad type or kind 'Integer(2)'
. I think it's because the intrinsic table probing code no longer allows for type conversions on calls to specific intrinsic functions.