Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

NaN-related questions

217 views
Skip to first unread message

spectrum

unread,
Jul 27, 2020, 12:37:09 PM7/27/20
to
Hello,

I believe NaN-related questions are a recurrent topic (and also afraid that my
internet search is far from sufficient), but I would really appreciate any comments/
opinions/pointers!

[Q1] I would like to generate NaN programmatically using the IEEE_VALUE() function.
I've tried this code first, which works as expected (i.e., it prints "NaN").

program main
use ieee_arithmetic, only: ieee_value, ieee_quiet_nan
implicit none
real(8) :: x

x = ieee_value( 1.0d0, ieee_quiet_nan ) !! assignment at run time

print *, x !! => NaN (gfort-8/10)
end

However, it seems that I cannot use it for initialization of variables
at compile time, e.g.,

program main
use ieee_arithmetic, only: ieee_value, ieee_quiet_nan
implicit none
real(8), save :: x = ieee_value( 1.0d0, ieee_quiet_nan )

print *, x
end

$ gfortran-10 test.f90
test.f90:10:24:

10 | real(8), save :: x = ieee_value( 1.0d0, ieee_quiet_nan )
| 1
Error: Function 'ieee_value' in initialization expression at (1) must be
an intrinsic function

My local note says that IEEE_VALUE() becomes an intrinsic function from
F2018 (?), so the above result is probably because the feature is too new.

If so, is there any alternative way to initialize variables with NaN
at compile time, hopefully in a portable manner?
(I am sorry that this is probably a recurrent question,
but I would like to know "best practice" as of 2020-7).

# My motivation is to set the default value of type components to NaN, or
set a parameter to NaN, but both fail for the same reason (i.e., not an intrinsic
function).

----- test2.f90 -----
program main
use ieee_arithmetic, only: ieee_value, ieee_quiet_nan
implicit none
real(8), parameter :: x = ieee_value( 1.0d0, ieee_quiet_nan )
print *, x
end

----- test3.f90 -----
program main
use ieee_arithmetic, only: ieee_value, ieee_quiet_nan
implicit none
type Mytype
real(8) :: x = ieee_value( 1.0d0, ieee_quiet_nan )
endtype
type(Mytype) :: obj

print *, obj% x
end

[Q2] Apart from IEEE_VALUE(), is there possibly some compiler option
to fill the default value of type components with NaN?
I tried -finit-real=snan in gfortran-10, but it seems to not affect
the type components...

----- test4.f90 -----
program main
implicit none
type Mytype
real(8) :: x
real(8) :: y = 100
endtype
type(Mytype) :: obj
real(8) :: z

print *, obj% x
print *, obj% y
print *, z
end

$ gfortran-10 test4.f90 && ./a.out
0.0000000000000000
100.00000000000000
4.2439915819305446E-314

$ gfortran-10 -finit-real=snan test4.f90 && ./a.out
0.0000000000000000
100.00000000000000
NaN

As always, thanks very much for various info!

steve kargl

unread,
Jul 27, 2020, 1:05:50 PM7/27/20
to
program main
implicit none
real(8), parameter :: x = real(z'FFF8000000000000', kind(1.d0))
print '(Z16.16,F12.4)', x,x !! => NaN (gfort-8/10)
end



pkla...@nvidia.com

unread,
Jul 27, 2020, 1:27:14 PM7/27/20
to
Be advised, IEEE-754 doesn't fully define the binary formats for NaNs, and
whether that hex value is signaling or quiet will depend on the target architecture.

I don't think that Fortran has a means for doing what OP wants in a
conforming and portable manner.

Themos Tsikas

unread,
Jul 27, 2020, 2:05:20 PM7/27/20
to
Hello,

IEEE_VALUE is an elemental function in an intrinsic module (IEEE_ARITHMETIC). It is not an elemental intrinsic function. The transformational functions from IEEE_ARITHMETIC are allowed in constant expressions (suitable for initialisation) but IEEE_VALUE is elemental.

There's also the restriction (in F2018)
"IEEE_VALUE (X, CLASS) shall not be invoked if IEEE_SUPPORT_DATATYPE (X) has the value false."

real(8) is not portable as KIND value 8 can mean different things. real(kind(1.0d0)) is portable and selects DOUBLE PRECISION.

What you want is not portable but compilers offer their own ways of doing things. What Steve Kargl displayed will not work with the NAG Fortran Compiler but that compiler has a -nan flag that will

-nan Initialise REAL and COMPLEX variables to IEEE Signalling NaN, causing a runtime crash if the values are used before being set. This affects local variables, module variables, and INTENT(OUT) dummy arguments
only; it does not affect variables in COMMON or EQUIVALENCE.

I don't see any indication in the F202X worklist (https://j3-fortran.org/doc/year/20/20-010r1.pdf) that affects IEEE_VALUE.

Themos Tsikas, NAG Ltd.

Themos Tsikas

unread,
Jul 27, 2020, 2:08:40 PM7/27/20
to
Hello,

On your Q2, the -nan option of nagfor will cause the desired output

NaN
1.0000000000000000E+02
NaN

Themos Tsikas, NAG Ltd.

FortranFan

unread,
Jul 27, 2020, 2:10:23 PM7/27/20
to
On Monday, July 27, 2020 at 12:37:09 PM UTC-4, spectrum wrote:

> ..
> If so, is there any alternative way to initialize variables with NaN
> at compile time, hopefully in a portable manner? ..

There doesn't seem to be a "portable" alternative, not at compile time at least as far as I know.

"Initialization" of objects at compile time in Fortran is generally rather limiting for any *type* besides the simple intrinsic ones that go back to FORTRAN I or FORTRAN 77.

If you plan to continue working with Fortran (why, you should ask yourself given your inclination to be polyglot and can thus easily find alternatives for scientific coding with D, Julia, Python, C++, etc. for your computing needs), you may be better off instituting your own "best practice" where objects of derived types are all explicitly initialized using "initializer" subroutine(s) for each such derived type. You will then be able to "make do" with such option until year 2053 when possibly the Fortran standard will really offer something better for *compile-time computing*, something Stroutsrup and others realized the value of decades ago and led the efforts to include better and efficient facilities in C++.

By the way, "real(8)" is neither a "best practice" nor portable e.g., to NAg compiler.

Ron Shepard

unread,
Jul 27, 2020, 2:11:46 PM7/27/20
to
On 7/27/20 11:37 AM, spectrum wrote:
> My local note says that IEEE_VALUE() becomes an intrinsic function from
> F2018 (?), so the above result is probably because the feature is too new.
>
> If so, is there any alternative way to initialize variables with NaN
> at compile time, hopefully in a portable manner?
> (I am sorry that this is probably a recurrent question,
> but I would like to know "best practice" as of 2020-7).

You might try something like this:

program ieeeNaN
use ieee_arithmetic
implicit none
integer, parameter :: wp = ieee_selected_real_kind(14)
real(wp) :: x
real(wp), parameter :: xNaN = real(Z'FFF8000000000000',kind=wp)

write(*,*) 'support=', ieee_support_nan(x)
x = ieee_value( 1.0_wp, ieee_quiet_nan ) !! assignment at run time

write(*,*) x !! => NaN (gfort-8/10)

write(*,'(z16)') x
write(*,*) xNaN, ieee_is_nan(xNaN)
end

As for "best practices," I think you will just get a lot of opinions
about what is the best compromise.

First, if you are concerned with portability, then maybe you should not
use IEEE specific operations because that limits you right off the bat
to ieee hardware and to compilers that support the ieee_arithmetic module.

If that pair of limitations is acceptable (they are to me), then notice
how I removed your hard-coded "8" types. I also removed your "1.0d0"
literal constant. I replaced them with the integer kind parameter "wp".
You should never hard coded types, either in declarations or in
literals, that's just ugly. And mixing double precision constants with
the "d" exponent with ieee types is just confusing and weird. It is all
like turning a silk purse into a sow's ear.

Just do the straightforward thing and define a parameter of the correct
type and use it. You don't need to depend on all of those other
assumptions (that wp==8 and that double precision is the same as wp).

Ok, so next, you can see that I printed out the Nan value with a Z
format. That's not standard. Most compilers support it, but it's not
really portable. It works for gfortran, which I know you are using, so I
did it for this posting. There are other ways to print out those hex
values, all ugly, so do one of those if you must.

Once you see the hex representation of Nan, then you can define a real
parameter to have that bit pattern. There was a recent thread about the
funky syntax needed to do that, but I think the above is now standard.
It was not standard in f90, but it is now, so there may be portability
issues related to just using the REAL() intrinsic.

Even if the ieee_arithmetic module is supported, and the bit pattern is
defined by the ieee standard itself, that does not mean that hex
constant is necessarily portable. There may be other issues related to
bit ordering or to byte ordering within the REAL data value. That
constant above should be fairly portable, but it is not required to be
so by either the fortran standard or the ieee standard.

Note that I added a ieee_support_nan(x) reference. Even if ieee
arithmetic is supported, that does not mean that NaN is supported. If
your code requires that, then you should check to make sure and stop if
necessary. I also added a ieee_is_nan() reference just to double check
that the hex value is interpreted as a NaN. For portability reasons, you
probably should do that test too, and stop if things don't match up.

If you want to initialize values at compile time with the xNaN
parameter, and if you are concerned with portability, then you should
define the parameter xNaN in a module by itself and isolate all of those
potential nonportable trip wires in one place. Every place in your code
that you want to use a Nan constant, it should USE that module and refer
to the xNAN parameter. That way, if something goes haywire, all of your
code will get fixed once that one module works correctly.

When f2018 is supported, then this all gets easier. But for now, those
are my "best practices" suggestions. They are not perfect, they are
compromises, and others may have their own opinions.

$.02 -Ron Shepard

Beliavsky

unread,
Jul 27, 2020, 2:40:56 PM7/27/20
to
On Monday, July 27, 2020 at 2:10:23 PM UTC-4, FortranFan wrote:

> If you plan to continue working with Fortran (why, you should ask yourself given your inclination to be polyglot and can thus easily find alternatives for scientific coding with D, Julia, Python, C++, etc. for your computing needs),

If someone asks a technical question about Fortran in comp.lang.fortran, I think it's odd to suggest they reconsider using Fortran. It's not as if people are unaware of alternatives.

Themos Tsikas

unread,
Jul 27, 2020, 2:51:24 PM7/27/20
to
On Monday, 27 July 2020 19:10:23 UTC+1, FortranFan wrote:
> You will then be able to "make do" with such option until year 2053 when possibly the Fortran standard will really offer something better for *compile-time computing*, something Stroutsrup and others realized the value of decades ago and led the efforts to include better and efficient facilities in C++.

Hello, I don't think that's entirely fair. Compilers have always been allowed to provide extensions so that non-conforming programs are given a valid interpretation and run as long as a) behaviour of conforming programs is not affected and b) the compiler marks the source as using an extension. If/when such extensions become sufficiently widely used (presumably due to their coherence and usability), the committee will probably incorporate them into revisions of the Standard.

Themos Tsikas, NAG Ltd.

steve kargl

unread,
Jul 27, 2020, 3:30:36 PM7/27/20
to
Given that gfortran is ported to more architectures and operating systems on
this planet than any other compiler that I am aware of, and being the person
that wrote gfortran's BOZ support, I would be interested to learn on which
architecture/OS the above will fail.

As to what IEEE-754 guarantees, Section 3.4 and 6.2.1 do a fairly decent
job of defining the bit patterns for its binary interchange formats.
--
steve

steve kargl

unread,
Jul 27, 2020, 3:35:25 PM7/27/20
to
What makes FortranFan's statement exceptionally odd is that he is/was
a (disenfranchised) member/participant of J3.

--
steve

steve kargl

unread,
Jul 27, 2020, 3:44:56 PM7/27/20
to
Themos Tsikas wrote:

>
> What you want is not portable but compilers offer their own ways of doing things. What Steve
> Kargl displayed will not work with the NAG Fortran Compiler

Out of curiosity, does NAG support REAL(boz-literal-constant)? If so, does the BOZ
string need to be consistent with Fortran's model number in 16.4?

--
steve

pkla...@nvidia.com

unread,
Jul 27, 2020, 3:50:59 PM7/27/20
to
x86 and PA-RISC have opposite conventions for interpreting the MSB of the significand when decoding signaling vs quiet NaNs.

steve kargl

unread,
Jul 27, 2020, 4:23:55 PM7/27/20
to
What does the endianness of the processor have to do with IEEE-754 binary
interchange format (BIF)? IEEE-754 defines bit patterns for qNaN and sNaN under
its BIF (which is depicted in figure 3.1). IEEE-754 says nothing about endianness.

REAL(BOZ) is a compile time constant, which allows the BOZ to be handled with
the BIF. Yes, Fortran declares the interpretation of BOZ as an actual argument
to REAL() to be processor dependent. This is just another example of J3 getting
the details of BOZ wrong from the get-go.

--
steve

pkla...@nvidia.com

unread,
Jul 27, 2020, 4:29:02 PM7/27/20
to
Endianness has nothing to do with it. The difference between x86 and PA-RISC lies in their interpretation of the MSB of the significand in a NaN -- if it's set, one of them treats it as a signaling NaN, and the other treats it as a quiet NaN.

steve kargl

unread,
Jul 27, 2020, 4:46:17 PM7/27/20
to
OK. So, PA-RISC does not conform to IEEE-754 (with respect to the BIF).

If I were working on a Fortran compiler that can be used on x86 and PA-RISC,
I would likely enforce BIF in the Fortran frontend when converting a BOZ to
an internal numerical representation. This then allows users of the compiler
to avoid the C pre-processor:

#ifdef X86
x = real(z'FFF8000000000000', kind(1.d0))
#else
x = real(PA-RISC-BOZ, kind(1.d0))
#endif

--
steve


Themos Tsikas

unread,
Jul 27, 2020, 5:00:50 PM7/27/20
to
On Monday, 27 July 2020 20:44:56 UTC+1, steve kargl wrote:
> Out of curiosity, does NAG support REAL(boz-literal-constant)? If so, does the BOZ
> string need to be consistent with Fortran's model number in 16.4?
>
> --
> steve

Hello Steve,

Yes, NAG supports boz-literal-constant in any context where an integer literal would be accepted. The only checks that I can see are that it is an appropriate length (warning) and that is not Inf or NaN (error). We treat it as a TRANSFER.

Themos Tsikas, NAG Ltd.

spectrum

unread,
Jul 27, 2020, 6:42:28 PM7/27/20
to
Thanks very much for so many comments in this short time, I really appreciate it!
I have tried some suggestions on my machine, but have some follow-up questions
so will ask them soon. Anyway, thanks much!

RE real(8) and 1.0d0, I'm again sorry for that, it is nothing but my laziness;
my local note has DOUBLE PRECISION (which I remember I copied from some
Intel site), but I instead used real(8) for brevity... In my working codes, I usually
try to be more careful about kinds and precision, so no worry about this,
hopefully... :)

On Monday, July 27, 2020 at 2:10:23 PM UTC-4, FortranFan wrote:

> If you plan to continue working with Fortran (why, you should ask yourself given your inclination to be polyglot and can thus easily find alternatives for scientific coding with D, Julia, Python, C++, etc. for your computing needs),

I think this is actually an interesting topic, so I will reply in my previous post below
(so as to not mix the topics in this present thread).
https://groups.google.com/d/msg/comp.lang.fortran/rnQC27Vl1kg/b9_ePA3ZBgAJ

jfh

unread,
Jul 27, 2020, 7:04:38 PM7/27/20
to
Some years ago I wanted a real(wp) constant that was NaN if the compiler supported that, but
-huge(1.0_wp) if not. It couldn't be a parameter but it could be a function with no arguments, like nanwp() below. (Reading 'NaN' with a compiler that does support it may give a result different from both that compiler's quiet NaN and its signalling NaN of kind wp, but that was OK for my purposes.)

pure real(wp) function nanwp() result(wrong)
character(3):: nan
integer ios
nan = 'NaN' ! can't be initialized on declaration in a pure procedure
read(nan,*,iostat=ios) wrong
if(ios/=0) wrong = -huge(wrong)
end function nanwp

steve kargl

unread,
Jul 27, 2020, 9:54:51 PM7/27/20
to
Themos,

Thanks for the info. I haven't had access to a NAG compiler since NAG
dropped support for FreeBSD.

Until 10.1, gfortran also allowed a boz-literal-constant to appear anywhere
an integer-literal-constant can appear. This has/had permitted some
rather questionable extensions such as

1) an array index could be a boz, e.g., array(z'ff')
2) a boz could appear in an expression: x = 3.1415 + z'ff'. As a BOZ is a typeless
and kindless thing, whatever are the conversion rules.
3) start, stop, and step in a do-loop could be a boz.
4) a boz could appear in an array constructor as an integer.
5) a boz could be used as SOURCE in a TRANSFER() reference.

I fixed all of those for gfortran. Surely, breaking people's code.

--
steve

FortranFan

unread,
Jul 28, 2020, 12:02:23 AM7/28/20
to
On Monday, July 27, 2020 at 5:00:50 PM UTC-4, Themos Tsikas wrote:

> On Monday, 27 July 2020 20:44:56 UTC+1, steve kargl wrote:
> > Out of curiosity, does NAG support REAL(boz-literal-constant)? If so, does the BOZ
> > string need to be consistent with Fortran's model number in 16.4?
> >
> ..
> Yes, NAG supports boz-literal-constant in any context where an integer literal would be accepted. The only checks that I can see are that it is an appropriate length (warning) and that is not Inf or NaN (error). We treat it as a TRANSFER.
> ..


@Themos Tsikas,

To the question, "does NAG support REAL(boz-literal-constant)?," you answered, "Yes, NAG supports boz-literal-constant in any context where an integer literal would be accepted .."

Your first part is hardly surprising. The Fortran standard itself states in section 16.9.160 REAL (A [, KIND]), "A shall be of type integer, real, or complex, or a boz-literal-constant." Thus any standard-conforming compiler, and one would think NAG would want its Fortran compiler to known as one given its marketing, would support the conversion to real type with a boz-literal constant.

What is unclear yet surprising is the latter part because Fortran standard places restrictions on where a boz-literal-constant can appear and it does *NOT* (unfortunately) support a boz-literal-constant in several of the contexts where an integer literal can appear. Heck, it even has a numbered constraint (C7109) that states, "A boz-literal-constant shall appear only as a data-stmt-constant in a DATA statement, or where explicitly allowed in 16.9 as an actual argument of an intrinsic procedure". I thought that was too limiting and even tried submitting a paper to get the standard to offer better support (https://j3-fortran.org/doc/year/19/19-132.txt) in Fortran 202X. So is it a conscious extension by NAG to support "boz-literal-constant in any context where an integer literal would be accepted" even as the standard doesn't do so yet?

Themos Tsikas

unread,
Jul 28, 2020, 5:55:38 AM7/28/20
to
On Tuesday, 28 July 2020 05:02:23 UTC+1, FortranFan wrote:
> On Monday, July 27, 2020 at 5:00:50 PM UTC-4, Themos Tsikas wrote:
>
> > On Monday, 27 July 2020 20:44:56 UTC+1, steve kargl wrote:
> > > Out of curiosity, does NAG support REAL(boz-literal-constant)? If so, does the BOZ
> > > string need to be consistent with Fortran's model number in 16.4?
> > >
> > ..
> > Yes, NAG supports boz-literal-constant in any context where an integer literal would be accepted. The only checks that I can see are that it is an appropriate length (warning) and that is not Inf or NaN (error). We treat it as a TRANSFER.
> > ..
>
>
> @Themos Tsikas,
>
> To the question, "does NAG support REAL(boz-literal-constant)?," you answered, "Yes, NAG supports boz-literal-constant in any context where an integer literal would be accepted .."
>
> Your first part is hardly surprising. The Fortran standard itself states in section 16.9.160 REAL (A [, KIND]), "A shall be of type integer, real, or complex, or a boz-literal-constant." Thus any standard-conforming compiler, and one would think NAG would want its Fortran compiler to known as one given its marketing, would support the conversion to real type with a boz-literal constant.

It is standard practice to make claims like "F2018 conforming, collectives excepted". Another example, we currently do not support EX editing (13.7.2.3.6). The choices made by all compilers are, in a sense, equally surprising.


>
> What is unclear yet surprising is the latter part because Fortran standard places restrictions on where a boz-literal-constant can appear and it does *NOT* (unfortunately) support a boz-literal-constant in several of the contexts where an integer literal can appear. Heck, it even has a numbered constraint (C7109) that states, "A boz-literal-constant shall appear only as a data-stmt-constant in a DATA statement, or where explicitly allowed in 16.9 as an actual argument of an intrinsic procedure". I thought that was too limiting and even tried submitting a paper to get the standard to offer better support (https://j3-fortran.org/doc/year/19/19-132.txt) in Fortran 202X. So is it a conscious extension by NAG to support "boz-literal-constant in any context where an integer literal would be accepted" even as the standard doesn't do so yet?

It is conscious, yes. That is how extensions work, by turning a non-conforming program into a running program. The constraint is that the conforming compiler must identify and report the extension. Other extensions in the NAG compiler are: Names of 199 characters, $ sign in names, CONVERT=specifier in OPEN, arrays of rank 31. All choices of which extensions to support are a matter of judging competing advantages.

Themos Tsikas, NAG Ltd

Themos Tsikas

unread,
Jul 28, 2020, 6:37:08 AM7/28/20
to
Steve,

The full documentation of the extension is

The NAG Fortran Compiler accepts hexadecimal, octal and binary literal constants in any context where an integer literal would be accepted. Such constants have a data type of default INTEGER, unless there are more digits in the BOZ constant than will fit in a default INTEGER; e.g., Z’12345678’ would be of type default INTEGER, and Z’123456789’ would be a 64-bit integer.

The actual implementation is more limited. I see that we reject your case 1, we accept case 2, we reject case 3, we accept case 4 when the BOZ is ac-value (and type of array is Integer) and we reject case 4 when BOZ is ac-implied-do limit expression, we accept case 5.

Apologies for the earlier misleading statement. I had only been looking into cases that make it past earlier checks to code generation.

Themos Tsikas, NAG Ltd.

Ron Shepard

unread,
Jul 28, 2020, 12:32:26 PM7/28/20
to
On 7/28/20 5:37 AM, Themos Tsikas wrote:
> Steve,
>
> The full documentation of the extension is
>
> The NAG Fortran Compiler accepts hexadecimal, octal and binary literal constants in any context where an integer literal would be accepted. Such constants have a data type of default INTEGER, unless there are more digits in the BOZ constant than will fit in a default INTEGER; e.g., Z’12345678’ would be of type default INTEGER, and Z’123456789’ would be a 64-bit integer.

We recently had a separate discussion about this in a different thread.
The issue is how the inconsistency with the latest standard comes into play.

According to the above convention, REAL(int,kind=k) would convert the
value of the integer to a real entity of kind=k with the same (or
approximately the same) numerical value. This would imply that
REAL(BOZ,kind=k) would first convert BOZ to an integer of some kind, and
then convert that resulting integer value in a consistent way.

But according to the latest (I think) standard, that is not the
semantics for REAL(BOZ,kind=k). According to the latest standard, the
bits within BOZ are transferred to form the real value. It is as if the
arguments were used in a TRANSFER() expression to copy bits.

But ironically, BOZ values are not allowed in a TRANSFER() expression.

As I said previously, all of this seems just backwards to me. I do not
understand why this unnecessary inconsistency was introduced into the
language. There were no backward compatibility concerns with previous
standards in this choice, and to the extent that vendors might have
previously supported REAL(BOZ,kind=k) as an extension, it seems like
most of them supported the integer conversion semantics rather than the
transfer semantics.

That is why I said previously in this thread that the use of REAL() was
funky when used in the parameter statement. Even though it is now
defined as part of the standard, it could well have portability issues
with previous compiler extensions. And, of course, it is just
inconsistent with what REAL() does with other argument types to begin with.

REAL(real,kind=k) converts the value of real to a real value of kind=k.
If KIND(real)==k, then this is a noop that likely can be compiled away.
Whether bits are copied or not depends on the various representations of
the supported real kinds: the exponent field widths, the mantissa field
widths, hidden bit conventions, exponent biases, and so on. But in any
case, it is the numerical value that is converted.

REAL(int,kind=k) converts the numerical value of int to a real value of
kind=k, with approximation if necessary. If there are any cases where
bits might be copied (e.g. for integer values of 0), they are
incidental, it is always values that are converted.

REAL(complex,kind=k) has the same semantics as REAL(real,kind=k) applied
to the real part of the complex entity. So although there may be some
cases where bits might be copied, those are incidental. It is the values
that are converted in all cases. Many uses for this conversion are now
obviated by the %RE and %IM syntax introduced in f2003, which is more
concise and more efficient (i.e. with assignments).

$.02 -Ron Shepard

Themos Tsikas

unread,
Jul 28, 2020, 12:55:14 PM7/28/20
to
On Tuesday, 28 July 2020 17:32:26 UTC+1, Ron Shepard wrote:
> On 7/28/20 5:37 AM, Themos Tsikas wrote:
> > Steve,
> >
> > The full documentation of the extension is
> >
> > The NAG Fortran Compiler accepts hexadecimal, octal and binary literal constants in any context where an integer literal would be accepted. Such constants have a data type of default INTEGER, unless there are more digits in the BOZ constant than will fit in a default INTEGER; e.g., Z’12345678’ would be of type default INTEGER, and Z’123456789’ would be a 64-bit integer.
>
> We recently had a separate discussion about this in a different thread.
> The issue is how the inconsistency with the latest standard comes into play.
>
> According to the above convention, REAL(int,kind=k) would convert the
> value of the integer to a real entity of kind=k with the same (or
> approximately the same) numerical value. This would imply that
> REAL(BOZ,kind=k) would first convert BOZ to an integer of some kind, and
> then convert that resulting integer value in a consistent way.

Accepting BOZ where integer literals were accepted is a syntactic decision. It does not determine the semantics, as far as I can see.

>
> But according to the latest (I think) standard, that is not the
> semantics for REAL(BOZ,kind=k). According to the latest standard, the
> bits within BOZ are transferred to form the real value. It is as if the
> arguments were used in a TRANSFER() expression to copy bits.

And why not? If you need to create a real whole-number value from an integer encoded as BOZ, you already have a solution REAL(INT(BOZ,kind=m),kind=k). I agree it's not elegant and possibly misleading but it is at least useful.

>
> But ironically, BOZ values are not allowed in a TRANSFER() expression.
>
> As I said previously, all of this seems just backwards to me. I do not
> understand why this unnecessary inconsistency was introduced into the
> language. There were no backward compatibility concerns with previous
> standards in this choice, and to the extent that vendors might have
> previously supported REAL(BOZ,kind=k) as an extension, it seems like
> most of them supported the integer conversion semantics rather than the
> transfer semantics.

Then those extensions were just syntactic sugar, not a very convincing argument for an extension, in my view.

>
> That is why I said previously in this thread that the use of REAL() was
> funky when used in the parameter statement. Even though it is now
> defined as part of the standard, it could well have portability issues
> with previous compiler extensions. And, of course, it is just
> inconsistent with what REAL() does with other argument types to begin with.
>
> REAL(real,kind=k) converts the value of real to a real value of kind=k.
> If KIND(real)==k, then this is a noop that likely can be compiled away.
> Whether bits are copied or not depends on the various representations of
> the supported real kinds: the exponent field widths, the mantissa field
> widths, hidden bit conventions, exponent biases, and so on. But in any
> case, it is the numerical value that is converted.
>
> REAL(int,kind=k) converts the numerical value of int to a real value of
> kind=k, with approximation if necessary. If there are any cases where
> bits might be copied (e.g. for integer values of 0), they are
> incidental, it is always values that are converted.
>
> REAL(complex,kind=k) has the same semantics as REAL(real,kind=k) applied
> to the real part of the complex entity. So although there may be some
> cases where bits might be copied, those are incidental. It is the values
> that are converted in all cases. Many uses for this conversion are now
> obviated by the %RE and %IM syntax introduced in f2003, which is more
> concise and more efficient (i.e. with assignments).
>
> $.02 -Ron Shepard

Themos Tsikas, NAG Ltd.

ga...@u.washington.edu

unread,
Jul 28, 2020, 9:55:05 PM7/28/20
to
On Tuesday, July 28, 2020 at 9:32:26 AM UTC-7, Ron Shepard wrote:

(snip)

> We recently had a separate discussion about this in a different thread.
> The issue is how the inconsistency with the latest standard comes into play.

> According to the above convention, REAL(int,kind=k) would convert the
> value of the integer to a real entity of kind=k with the same (or
> approximately the same) numerical value. This would imply that
> REAL(BOZ,kind=k) would first convert BOZ to an integer of some kind, and
> then convert that resulting integer value in a consistent way.

> But according to the latest (I think) standard, that is not the
> semantics for REAL(BOZ,kind=k). According to the latest standard, the
> bits within BOZ are transferred to form the real value. It is as if the
> arguments were used in a TRANSFER() expression to copy bits.

I first knew Z constants from the IBM OS/360 compilers, where they
are only allowed in DATA statements. The syntax makes them look like
variable names, so they can't be allowed just anywhere.

Restriction to DATA statements is slightly inconvenient, as sometimes
you need a variable for something that you otherwise wouldn't need one.

On the other hand, a common use is initializing arrays, so it isn't
all that inconvenient.

Traditionally REAL was only for the real part of a complex value.
Then it was extended as a generic conversion function, and later
as a BOZ type indicator.

I suppose I don't mind it so much.

spectrum

unread,
Jul 30, 2020, 11:03:26 AM7/30/20
to
On Tuesday, July 28, 2020 at 3:08:40 AM UTC+9, Themos Tsikas wrote:

> On your Q2, the -nan option of nagfor will cause the desired output

> NaN
> 1.0000000000000000E+02
> NaN

Dear Themos,
I have tried the -nan option with a bit older nag compiler, and confirmed that
it indeed gives the above result :)

Because I also wish NaN for uninitialized values of ALLOCATABLE arrays,
I've tried the following code also:

program main
implicit none
real, allocatable :: a(:)

allocate( a( 3 ) )
print *, a
end

Then, the above "-nan" option gives
NaN NaN NaN
I believe this option is very nice for debugging purpose :)

# I had imagined that with -finit-real=snan (in gfortran) both the above two cases
results in NaN, but recently noticed that it was not the case for some reason.
So, I was trying to set NaN manually somehow (for type components in my first post).

spectrum

unread,
Jul 30, 2020, 11:35:09 AM7/30/20
to
On Tuesday, July 28, 2020 at 3:10:23 AM UTC+9, FortranFan wrote:

> "Initialization" of objects at compile time in Fortran is generally rather limiting for any *type* besides the simple intrinsic ones that go back to FORTRAN I or FORTRAN 77.

Yeah, I agree with this. I remember Ron also discussed related things some time ago
(e.g., character(:), allocatable :: str = "hello").

> (...snip...) you may be better off instituting your own "best practice" where objects of derived types are all explicitly initialized using "initializer" subroutine(s) for each such derived type.

Indeed, I almost always create an "init()" subroutine for each derived type and call it
manually like "call x % init(...)" (*1). My concern here is that init() cannot guarantee
that all the components are initialized at run time (*2). More specifically,

* when the type has many components,
* and if I add another new component (in the type definition),
* and if I forget assignment of that new component in my init()
or in other routines invoked during the run,

then that new variable remains unassigned (so resulting in bugs).
So I was looking for automatically preventing this kind of things somehow...

Another case that leads to bugs is when I forget to call "x % init()" XD

(*1) I tend to avoid the structure constructor (like x = Mytype(...)),
though it is commonly used in various books, because it induces copy and possible
reallocation of type components, plus pointer components can make things
more complicated (e.g., need of overloading assignment...)

(*2) Recently I came across a similar post on the net (though a different language):
How to ensure that all attributes of an object are explicitly set during creation?https://forum.nim-lang.org/t/6612

Ron Shepard

unread,
Jul 30, 2020, 1:48:49 PM7/30/20
to
On 7/30/20 10:35 AM, spectrum wrote:
> On Tuesday, July 28, 2020 at 3:10:23 AM UTC+9, FortranFan wrote:
>
>> "Initialization" of objects at compile time in Fortran is generally rather limiting for any *type* besides the simple intrinsic ones that go back to FORTRAN I or FORTRAN 77.
>
> Yeah, I agree with this. I remember Ron also discussed related things some time ago
> (e.g., character(:), allocatable :: str = "hello").

I would like this ability also even for the older intrinsic types

integer, allocatable, save :: j(:) = [], k(:)=[1,2,3]

and so on. This would simplify many programming tasks and make certain
types of library routines more robust.

$.02 -Ron Shepard

FortranFan

unread,
Jul 30, 2020, 5:16:25 PM7/30/20
to
On Thursday, July 30, 2020 at 11:35:09 AM UTC-4, spectrum wrote:

> .. My concern here is that init() cannot guarantee
> that all the components are initialized at run time (*2). More specifically,
>
> * when the type has many components,
> * and if I add another new component (in the type definition),
> * and if I forget assignment of that new component in my init()
> or in other routines invoked during the run,
>
> then that new variable remains unassigned (so resulting in bugs).
> So I was looking for automatically preventing this kind of things somehow...
>
> Another case that leads to bugs is when I forget to call "x % init()" XD
> ..


@spectrum,

Your concerns are very, very valid, you've expressed them here like a true Fortran practitioner, someone who really strives to code "in anger" (https://www.ldoceonline.com/dictionary/do-use-something-in-anger#:~:text=From%20Longman%20Dictionary%20of%20Contemporary,kick%20a%20ball%20in%20anger.)

But can you please reply here if you have yourself tried to read the current Fortran standard (2018 i.e., 18-007r1 document) thoroughly and if you have found anything in that language that provides the *comprehensiveness* and the "safety" you seek with initialization of objects generally, or even initialization of components of derived types specifically? It's a serious Yes/No question.

spectrum

unread,
Jul 31, 2020, 6:26:38 PM7/31/20
to
On Tuesday, July 28, 2020 at 1:37:09 AM UTC+9, spectrum wrote:
(...snip...)
> [Q2] Apart from IEEE_VALUE(), is there possibly some compiler option
> to fill the default value of type components with NaN?
> I tried -finit-real=snan in gfortran-10, but it seems to not affect
> the type components...

Today, I've checked the man page of gfortran-10 for the NaN-related parts, and
noticed that the "-finit-derived" option does the above job!! (i.e., sets NaN to
type components). The excerpt from the man page is like this:

-finit-derived
-finit-integer=n
-finit-real=<zero|inf|-inf|nan|snan>
-finit-logical=<true|false>
-finit-character=n

(...snip...)
-finit-real=<zero|inf|-inf|nan|snan> (which also initializes the
real and imaginary parts of local "COMPLEX" variables),
(...snip...)

With -finit-derived, components of derived type variables will be
initialized according to these flags. Components whose type is
not covered by an explicit -finit-* flag will be treated as
described above with -finit-local-zero.

For example, the following code gives the expected result:

----- test5.f90 -----
program main
implicit none
type Mytype
real :: x
real :: y = 100
endtype
type(Mytype) :: obj
real :: z

print *, obj% x
print *, obj% y
print *, z
end

$ gfortran-10 -finit-real=snan -finit-derived test5.f90 && ./a.out
NaN
100.000000
NaN

However, the man page also says:

These options do not initialize

* objects with the POINTER attribute
* allocatable arrays
* variables that appear in an "EQUIVALENCE" statement.

(These limitations may be removed in future releases).

So, ALLOCATABLE arrays seem not initialized with NaN (yet).
I think it would be great if an option like "-finit-alloc" will be introduced
in future for this purpose (in line with "-finit-derived") :)

spectrum

unread,
Jul 31, 2020, 7:58:12 PM7/31/20
to
On Friday, July 31, 2020 at 6:16:25 AM UTC+9, FortranFan wrote:
(...snip...)
> Your concerns are very, very valid, you've expressed them here like a true Fortran practitioner, someone who really strives to code "in anger" (https://www.ldoceonline.com/dictionary/do-use-something-in-anger#:~:text=From%20Longman%20Dictionary%20of%20Contemporary,kick%20a%20ball%20in%20anger.)

Ha ha... :) I'm not sure whether I am a "practitioner" (though using it for work),
I do wish as many robustness and safety features as possible to be available
in the standards as well as compilers (so that, even if I write risky codes at midnight,
the compiler can tell me problematic parts, ideally :)

> But can you please reply here if you have yourself tried to read the current Fortran standard (2018 i.e., 18-007r1 document) thoroughly and if you have found anything in that language that provides the *comprehensiveness* and the "safety" you seek with initialization of objects generally, or even initialization of components of derived types specifically? It's a serious Yes/No question.

I have never gone through the entire Fortran standard document
from the beginning to end (I only consult part of it as necessary),
so I cannot say anything definite (sorry...). But empirically, I feel modern Fortran
+ recent compilers are very strong for detecting bugs and possible issues
(as long as explicit declarations + interfaces are used), so it is pretty rare that
I get strong frustration from debugging experience.

Nevertheless, some useful features are actually still missing
(e.g., automatic init() for derived types), which makes the code less
robust by requiring manual handling of objects...

As for type components, I think it is useful to fill NaN as initial values (for
debug). Interestingly, D adopts this approach at the language level,
i.e., all fields of floating-point types are default-initialized to NaN.

https://dlang.org/spec/type.html (see the first table and "Default Initializer")

Though I think this is a drastic approach with pros & cons, one thing for sure
is that various languages have been exploring enhanced safety and
robustness features, which is very welcome for me :)
0 new messages