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

What is the maximum integer?

80 views
Skip to first unread message

Roland Rau

unread,
Nov 21, 2011, 7:38:44 AM11/21/11
to
Dear all,

I discovered via trial and (compile) error that the maximum value for
selected_int_kind on my platform is 38.
This is a small example code:[1]

program maxint
integer,parameter :: maxi = selected_int_kind(38)
integer(kind=maxi) :: maxinteger

print *, huge(maxinteger)
end program maxint

Is there a way to find the value of 38 without trial and error?
I assume this is OS dependent (Windows, Unix, Linux, ...), platform
dependent (32bit/64 bit) and compiler dependent (gfortran, g95,
intel....) -- so is there a way to determine this largest
representable integer without knowing the OS, platform or compiler?

Thank you,
Roland

[1] Modified from: http://gcc.gnu.org/onlinedocs/gfortran/SELECTED_005fINT_005fKIND.html

arjenmarkus

unread,
Nov 21, 2011, 7:51:20 AM11/21/11
to
Hi Roland,

that seems an incredibly large number: huge(1_38) should be in
the order of 10**38 then.

You can determine it in a preprocessing step:

program determine_range

integer :: i, kind

i = 0
do
kind = selected_int_kind(i)
if ( kind < 0 ) then
exit
else
write(*,'(a,i0,a,i0)') '10**',i,': kind =', kind
endif
i = i + 1
enddo
end program

But the kind attribute for a particular variable is a
compile time constant, so you can not use the resulting
kind for the largest integer on the system to declare
a variable in the same program.

Regards,

Arjen

Roland Rau

unread,
Nov 21, 2011, 8:06:28 AM11/21/11
to
Hi Arjen,

thank you very much for the incredibly quick reply.

On Nov 21, 1:51 pm, arjenmarkus <arjen.markus...@gmail.com> wrote:
> But the kind attribute for a particular variable is a
> compile time constant, so you can not use the resulting
> kind for the largest integer on the system to declare
> a variable in the same program.
>
I understand. Thank you.
So please let me follow up with another question:
Is there a minimum in the Fortran standard, i.e. a Fortran compiler
conforming to the 90, 95 or 2003 standard has to support at least
selected_int_kind(16)
or
selected_int_kind(32)
???
I can see from my compiler description at
http://gcc.gnu.org/onlinedocs/gfortran/KIND-Type-Parameters.html that
only 1, 2, and 4 are guaranteed to be supported but not 8 or 16.
However, it is not mentioned which systems support it and which
don't. :-/
I'd be happy for any pointers -- even a RTFM (hopefully with a link to
the respective section in the respective "M").

Thank you,
Roland

arjenmarkus

unread,
Nov 21, 2011, 8:30:01 AM11/21/11
to
Hi Roland,

I am pretty sure there is no such requirement.

But I see you making a small mistake wrt kind numbers:
they are _not_ the same as the number of bytes used for the
representation of the integer or real:
selected_int_kind(16) will return a negative number or the
kind to be used for integers that range up to and including 10**16.

You would need some 16*log_2(10) = roughly 43 bytes to store an
integer that large.

Regards,

Arjen

Roland Rau

unread,
Nov 21, 2011, 9:04:09 AM11/21/11
to
On Nov 21, 2:30 pm, arjenmarkus <arjen.markus...@gmail.com> wrote:
> Hi Roland,
>
> I am pretty sure there is no such requirement.
>
> But I see you making a small mistake wrt kind numbers:
> they are _not_ the same as the number of bytes used for the
> representation of the integer or real:
> selected_int_kind(16) will return a negative number or the
> kind to be used for integers that range up to and including 10**16.
>
> You would need some 16*log_2(10) = roughly 43 bytes to store an
> integer that large.
>
> Regards,
>
> Arjen
>
Thank you for taking your time,
Roland

Steve Lionel

unread,
Nov 21, 2011, 10:38:39 AM11/21/11
to
On 11/21/2011 8:06 AM, Roland Rau wrote:
> Is there a minimum in the Fortran standard, i.e. a Fortran compiler
> conforming to the 90, 95 or 2003 standard has to support at least
> selected_int_kind(16)
> or
> selected_int_kind(32)

Fortran 2008 specifies "The processor shall provide at least one
representation method with a decimal exponent range greater than or
equal to 18." [4.4.4.2 Integer type, paragraph 2] Fortran 2003 and
earlier does not have this requirement.

The standard says (F2008 Annex A):

This part of ISO/IEC 1539 does not specify the following:
...
- the number of representation methods and associated kind type
parameter values of the intrinsic types (4.4), except that there shall
be at least two representations methods for type real, and a
representation method of type complex that corresponds to each
representation method for type real.

So in F2003, there is no "minimum" requirement at all. In F2008, there
is, but it is satisfied by a 64-bit integer type. The specific kind
value corresponding top such a type is not dictated by the standard.

--
Steve Lionel
Developer Products Division
Intel Corporation
Merrimack, NH

For email address, replace "invalid" with "com"

User communities for Intel Software Development Products
http://software.intel.com/en-us/forums/
Intel Software Development Products Support
http://software.intel.com/sites/support/
My Fortran blog
http://www.intel.com/software/drfortran

Refer to http://software.intel.com/en-us/articles/optimization-notice
for more information regarding performance and optimization choices in
Intel software products.

James Van Buskirk

unread,
Nov 21, 2011, 10:43:20 AM11/21/11
to
"Roland Rau" <rolan...@gmail.com> wrote in message
news:4353c119-aa4d-4a1a...@p16g2000yqd.googlegroups.com...

> Is there a way to find the value of 38 without trial and error?
> I assume this is OS dependent (Windows, Unix, Linux, ...), platform
> dependent (32bit/64 bit) and compiler dependent (gfortran, g95,
> intel....) -- so is there a way to determine this largest
> representable integer without knowing the OS, platform or compiler?

C:\gfortran\clf\maxint>type maxint.f90
program maxint
use ISO_FORTRAN_ENV, only: integer_kinds
implicit none
integer i
integer, parameter :: ikm = integer_kinds(maxloc([( &
real(huge(int(0,integer_kinds(i))),kind(1.0d0)), &
i=1,size(integer_kinds))],1))
integer(ikm) j
write(*,*) huge(j)
end program maxint

C:\gfortran\clf\maxint>gfortran maxint.f90 -omaxint
maxint.f90:6.22:

real(huge(int(0,integer_kinds(i))),kind(1.0d0)), &
1
Error: 'kind' argument of 'int' intrinsic at (1) must be a constant
maxint.f90:8.14:

integer(ikm) j
1
Error: Symbol 'ikm' at (1) has no IMPLICIT type
maxint.f90:9.20:

write(*,*) huge(j)
1
Error: Symbol 'j' at (1) has no IMPLICIT type

A pity. N1830.pdf, section 7.1.12 (11) seems to allow this, but
not gfortran. Does a newer version of gfortran work here?

C:\gfortran\clf\maxint>gfortran -v
Built by Equation Solution <http://www.Equation.com>.
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=c:/gcc_equation/bin/../libexec/gcc/x86_64-w64-mingw32/4.6.0/
lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with:
../gcc-4.6-20110312-mingw/configure --host=x86_64-w64-mingw32 -
-build=x86_64-unknown-linux-gnu --target=x86_64-w64-mingw32 --prefix=/home/gfort
ran/gcc-home/binary/mingw32/native/x86_64/gcc/4.6-20110312 --with-sysroot=/home/
gfortran/gcc-home/binary/mingw32/cross/x86_64/gcc/4.6-20110312 --with-gcc --with
-gnu-ld --with-gnu-as --with-gmp=/home/gfortran/gcc-home/binary/mingw32/native/x
86_64/gmp --with-mpfr=/home/gfortran/gcc-home/binary/mingw32/native/x86_64/mpfr
--with-mpc=/home/gfortran/gcc-home/binary/mingw32/native/x86_64/mpc --with-ppl=/
home/gfortran/gcc-home/binary/mingw32/native/x86_64/ppl --with-cloog=/home/gfort
ran/gcc-home/binary/mingw32/native/x86_64/cloog --with-lto-plugin --with-host-li
bstdcxx='-lstdc++ -lsupc++ -lm' --enable-targets=i686-w64-mingw32,x86_64-w64-min
gw32 --enable-cloog-backend=ppl --enable-lto --enable-languages=c,c++,fortran
--
enable-libgomp --enable-threads=win32 --enable-static --enable-plugins --enable-
ld=yes --disable-shared --disable-nls --disable-tls --disable-win32-registry
Thread model: win32
gcc version 4.6.0 20110312 (experimental) (GCC)

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


Richard Maine

unread,
Nov 21, 2011, 11:25:18 AM11/21/11
to
arjenmarkus <arjen.m...@gmail.com> wrote:

> selected_int_kind(16) will return a negative number or the
> kind to be used for integers that range up to and including 10**16.
>
> You would need some 16*log_2(10) = roughly 43 bytes to store an
> integer that large.

Make that bits instead of bytes.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

Walt Brainerd

unread,
Nov 21, 2011, 2:19:23 PM11/21/11
to
program maxint

use iso_fortran_env
integer(kind=integer_kinds &
(size(integer_kinds))) :: n
print *, huge(n), log10(real(n)), kind(n)

end program maxint

In F08. This assumes that the largest one is last
in the array. 18+ digits. Same result on gfortran
and Intel.

It appears that maxval is not allowed in a constant
expression still. Thought all those restrictions
were removed ???

--
Walt Brainerd

Walt Brainerd

unread,
Nov 21, 2011, 2:27:52 PM11/21/11
to
Oops. Strange, I got 18+ with the first version. The
"junk" stored in n is close to huge(n)!

program maxint

use iso_fortran_env
integer(kind=integer_kinds&
(size(integer_kinds))) :: n
print *, huge(n), &
log10(real(huge(n))), &
kind(n)

end program maxint

--
Walt Brainerd

James Van Buskirk

unread,
Nov 21, 2011, 2:56:03 PM11/21/11
to
"Walt Brainerd" <wa...@swcp.com> wrote in message
news:rc2dnYyMwfCqO1fT...@swcp.com...

> On 11/21/2011 12:19 PM, Walt Brainerd wrote:

>> It appears that maxval is not allowed in a constant
>> expression still. Thought all those restrictions
>> were removed ???

Transformational standard intrinsics are certainly allowed
in constant expressions in F08 and I am pretty sure that they
were allowed in initialization expressions in F03 but not in
F95.

> program maxint

> use iso_fortran_env
> integer(kind=integer_kinds&
> (size(integer_kinds))) :: n
> print *, huge(n), &
> log10(real(huge(n))), &
> kind(n)

> end program maxint

F08 doesn't guarantee that the INTEGER_KINDS array stores data in
order of increasing size or any other order.

FX

unread,
Nov 21, 2011, 3:07:40 PM11/21/11
to
> Is there a way to find the value of 38 without trial and error?

Below is an F2003 way to have it as compile-time constant [1]:

integer, parameter :: limit = huge(0)
integer, parameter :: i(limit) = &
(/ ( selected_int_kind(k), k = 1, limit ) /)
integer, parameter :: s = size(pack(i, i > 0))
print *, s
end

If your compiler takes ages to compile that (as does gfortran on my shiny
laptop), then you can use a more reasonable value for limit, such as
1000. But then, one day, you'll have a laptop with 8192-bit integers, and
that old piece of code will break :)

--
FX


[1] You can bet on Richard Maine rightly chastising me because it's not
called a "compile-time constant", but rather a "named parameter", "named
constant", or what-not, but I can't remember it right now (and I've spent
most of my day teaching C to beginners, so it's not my best Fortran day).

glen herrmannsfeldt

unread,
Nov 21, 2011, 3:43:27 PM11/21/11
to
James Van Buskirk <not_...@comcast.net> wrote:

(snip)


> real(huge(int(0,integer_kinds(i))),kind(1.0d0)), &
> 1
> Error: 'kind' argument of 'int' intrinsic at (1) must be a constant
(snip)
> write(*,*) huge(j)

> A pity. N1830.pdf, section 7.1.12 (11) seems to allow this, but
> not gfortran. Does a newer version of gfortran work here?

I just found twi different ICEs with gfortran 4.1.2 testing out
some things for this. First:

integer, parameter:: is(1000000)=(/(i,i=1,1000000)/)
print *,is(1),is(size(is))
end

It seems that 10000000 is too big. It can compile 10000, but it
is very slow.

I also learned that SELECTED_INT_KIND isn't elemental, though
I don't know why it couldn't be, and that MAXVAL isn't allowed
in initialization expressions.

And the second ICE comes from:

integer, parameter:: kinds=100
integer, parameter:: is(:)=(/(i,i=1,kinds)/)
integer, parameter:: ik(kinds)=
& [(selected_int_kind(is(i)),i=1,size(is))]
print *,ik(1),ik(size(ik))
end

I was trying to find out how to dimension an array based on its
initialization. In C you can do:

int x[]={1,2,3,4,5,6,7,8,9,10,};

and it will dimension x to 10 and initialize it. Can you do that
in Fortran?

-- glen

FX

unread,
Nov 21, 2011, 3:52:35 PM11/21/11
to
> I was trying to find out how to dimension an array based on its
> initialization.

I was also trying out this an hour ago, and didn't find a way to do it. I
had tried:

integer, parameter :: a(:) = (/ 1, 2, 3 /)

which didn't work out. Turns out that assumed-size is the way to go:

integer, parameter :: a(*) = (/ 1, 2, 3 /)
print *, size(a)
end

but gfortran says it's F2008 only:

$ gfortran b.f90 && ./a.out
3
$ vim b.f90
$ gfortran -std=f95 b.f90 && ./a.out
b.f90:1.25:

integer, parameter :: a(*) = (/ 1, 2, 3 /)
1
Error: Fortran 2008: Implied-shape array at (1)

--
FX

FX

unread,
Nov 21, 2011, 3:55:09 PM11/21/11
to
> assumed-size is the way to go

Even the error message quoted below corrected me, so I'd rather come
clean. This is in fact an "implied-shape array", about which "The new
features of Fortran 2008" says:

> 5.4 Implied-shape array
>
> An implied-shape array is a named constant that is declared with each
> upper bound given as an asterisk. It takes its shape from its constant
> expression, for example,
> integer, parameter :: order(0:*) = [0, 1, 2, 3]

--
FX

Walt Brainerd

unread,
Nov 21, 2011, 4:28:08 PM11/21/11
to
On 11/21/2011 12:56 PM, James Van Buskirk wrote:
> "Walt Brainerd"<wa...@swcp.com> wrote in message
> news:rc2dnYyMwfCqO1fT...@swcp.com...
>
>> On 11/21/2011 12:19 PM, Walt Brainerd wrote:
>
>>> It appears that maxval is not allowed in a constant
>>> expression still. Thought all those restrictions
>>> were removed ???
>
> Transformational standard intrinsics are certainly allowed
> in constant expressions in F08 and I am pretty sure that they
> were allowed in initialization expressions in F03 but not in
> F95.
>
I was pretty sure too since I was the person that wrote the
proposal for F03 to remove those kinds of restrictions, but
the error message from gfortran makes you wonder:

integer(kind=maxval(integer_kinds)) :: n
1
Error: transformational intrinsic 'maxval' at (1) is not permitted in an
initialization expression

The standard (as I read it) seems to disagree with gfortran (4.7),
as you indicate.

BTW, they now seem to be called "constant expressions" :-).

>> program maxint
>
>> use iso_fortran_env
>> integer(kind=integer_kinds&
>> (size(integer_kinds))) :: n
>> print *, huge(n),&
>> log10(real(huge(n))),&
>> kind(n)
>
>> end program maxint
>
> F08 doesn't guarantee that the INTEGER_KINDS array stores data in
> order of increasing size or any other order.
>
That is why I said in the post that the assumption was being made.

--
Walt Brainerd

Steven G. Kargl

unread,
Nov 21, 2011, 4:35:32 PM11/21/11
to
On Mon, 21 Nov 2011 20:43:27 +0000, glen herrmannsfeldt wrote:

> James Van Buskirk <not_...@comcast.net> wrote:
>
> (snip)
>
>
>> real(huge(int(0,integer_kinds(i))),kind(1.0d0)), &
>> 1
>> Error: 'kind' argument of 'int' intrinsic at (1) must be a constant
> (snip)
>> write(*,*) huge(j)
>
>> A pity. N1830.pdf, section 7.1.12 (11) seems to allow this, but
>> not gfortran. Does a newer version of gfortran work here?
>
> I just found twi different ICEs with gfortran 4.1.2 testing out

GCC 4.1.2 was released on February 13, 2007.

There have been 26 newer version released since 13 Feb 2007.


troutmask:sgk[204] gfc4x -o z foo.f90
foo.f90:2.39:

integer, parameter:: is(1000000)=(/(i,i=1,1000000)/)
1
Error: The number of elements in the array constructor at (1) requires an
increase of the allowed 65535 upper limit. See -fmax-array-constructor option
foo.f90:3.28:

troutmask:sgk[213] grep max-array-constructor gcc/fortran/ChangeLog*
ChangeLog-2008: * lang.opt: Add -fmax-array-constructor option.


--
steve

robert....@oracle.com

unread,
Nov 22, 2011, 1:59:59 AM11/22/11
to
On Nov 21, 1:28 pm, Walt Brainerd <w...@swcp.com> wrote:

> BTW, they now seem to be called "constant expressions" :-).
>
> --
> Walt Brainerd

In Fortran 2008, constant expressions are no longer
required to have constant values. Consider the
program

PROGRAM MAIN
TARGET X
DATA X/0.0/
TYPE T
REAL, POINTER :: P
END TYPE
TYPE(T), PARAMETER :: C = T(X) !!!
READ *, X
CALL SUBR()
CONTAINS
SUBROUTINE SUBR
REAL, PARAMETER :: Y = C%P !!!
PRINT *, Y
END SUBROUTINE
END

The initializer in the first line marked with a
comment is a constant expression because of
item (3)(b) in Clause 7.1.12. The initializer in
the second line marked with a comment is a constant
expression because of item (1) in the same clause.
Therefore, Y is a standard conforming named constant
even though its value is not constant.

Robert Corbett

arjenmarkus

unread,
Nov 22, 2011, 2:57:51 AM11/22/11
to
On 2011-11-21 17:25, Richard Maine wrote:
> arjenmarkus <arjen.m...@gmail.com> wrote:
>
>> selected_int_kind(16) will return a negative number or the
>> kind to be used for integers that range up to and including 10**16.
>>
>> You would need some 16*log_2(10) = roughly 43 bytes to store an
>> integer that large.
>
> Make that bits instead of bytes.
>
Oops, that should have been bits indeed!

Regards,

Arjen

Erik Toussaint

unread,
Nov 22, 2011, 8:40:39 AM11/22/11
to
Gfortran seems to disagree with you:

$ gfortran constexpr.f90 -o constexpr
constexpr.f90:7.36:

TYPE(T), PARAMETER :: C = T(X) !!!
1
Error: Parameter 'x' at (1) has not been declared or is a variable,
which does not reduce to a constant expression
constexpr.f90:12.32:

REAL, PARAMETER :: Y = C%P !!!
1
Error: Parameter 'c' at (1) has not been declared or is a variable,
which does not reduce to a constant expression

$ gfortran -v
Using built-in specs.
COLLECT_GCC=e:\Programming\MinGW\gcc461\bin\gfortran.exe
COLLECT_LTO_WRAPPER=e:/programming/mingw/gcc461/bin/../libexec/gcc/mingw32/4.6.1/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.6.1/configure
--enable-languages=c,c++,fortran,objc,obj-c++ --disable-sjlj-exceptions
--with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry
--enable-libstdcxx-debug --enable-version-specific-runtime-libs
--build=mingw32 --prefix=/mingw
Thread model: win32
gcc version 4.6.1 (GCC)

Which interpretation is correct?
I guess the relevant text from the standard, as you stated, is item
(3)(b) in Clause 7.1.12:

"1 A constant expression is an expression with limitations that make it
suitable for use as a kind type parameter, initializer, or named
constant. It is an expression in which each operation is intrinsic, and
each primary is

[...]

(3) a structure constructor where each component-spec corresponding to

[...]

(b) a pointer component is an initialization target or a reference to
the intrinsic function NULL,

[...]"

But what is an 'initialization target'?

Erik.

Tobias Burnus

unread,
Nov 22, 2011, 9:27:17 AM11/22/11
to
On 11/22/2011 02:40 PM, Erik Toussaint wrote:
> On 22-11-2011 7:59, robert....@oracle.com wrote:
>> In Fortran 2008, constant expressions are no longer
>> required to have constant values. Consider the
>> program
>
> Gfortran seems to disagree with you:
>
> $ gfortran constexpr.f90 -o constexpr
> constexpr.f90:7.36:
>
> TYPE(T), PARAMETER :: C = T(X) !!!
> 1
> Error: Parameter 'x' at (1) has not been declared or is a variable,
> which does not reduce to a constant expression

Well, that's a Fortran 2008 feature - thus, don't expect that compilers
get already all details correct.

However, having said that, I think I have to agree with Malcolm Cohen
(on the J3 mailing list) that this is not valid for PARAMETER. The
problem is that the address of the variable X is not a compile-time
constant. Thus,
TYPE(T) :: CV = T(X) ! Initialization expression
is fine but not
TYPE(T), PARAMETER :: CP = T(X)

The problem with the latter is that it requires that the address is
known at compile time - for former, it just needs to point to the
variable, its address is not required by the compiler.

The latter allows the following, which cannot be done as the address is
not known at compile time:

INTEGER :: bits(1000)
bits = 0
bits = transfer(CP, bits)
call sub(bits)
X = 8
...
type(T) :: Y
Y = transfer(bits, Y)
if(Y%p /= 8) error stop

Tobias

John Harper

unread,
Nov 22, 2011, 6:10:57 PM11/22/11
to
Roland Rau wrote:

>
> I can see from my compiler description at
> http://gcc.gnu.org/onlinedocs/gfortran/KIND-Type-Parameters.html that
> only 1, 2, and 4 are guaranteed to be supported but not 8 or 16.
> However, it is not mentioned which systems support it and which
> don't. :-/
> I'd be happy for any pointers -- even a RTFM (hopefully with a link to
> the respective section in the respective "M").

You may find my 68-line f95 program for finding the properties of all the
integer kinds known to your compiler useful. (I have another one for real
kinds that I'll be happy to email to anyone who asks me, john.harper at
vuw.ac.nz). If you spot a bug or if it fails to compile with your f95 please
send details.

! F95 program to give useful properties of the (first 6) integer kinds
! It assumes huge(k6) < huge(1.0d0) (true in all 4 compilers I tested)
! By J.F.Harper, Mathematics, Victoria U, Wellington NZ. 22 Nov 2011
program intkinds
implicit none
integer ,parameter:: maxnk = 6, dp = kind(1d0), &
k1 = selected_int_kind(0)
integer(k1),parameter:: i1 = 1_k1
integer ,parameter:: sik2 = selected_int_kind(range(i1)+1), &
k2 = (sign(1,sik2)*(sik2-k1) + (sik2+k1))/2
! If kn different from the previous one, it has a larger range.
integer(k2),parameter:: i2 = 1_k2
integer ,parameter:: sik3 = selected_int_kind(range(i2)+1), &
k3 = (sign(1,sik3)*(sik3-k2) + (sik3+k2))/2
integer(k3),parameter:: i3 = 1_k3
integer ,parameter:: sik4 = selected_int_kind(range(i3)+1), &
k4 = (sign(1,sik4)*(sik4-k3) + (sik4+k3))/2
integer(k4),parameter:: i4 = 1_k4
integer ,parameter:: sik5 = selected_int_kind(range(i4)+1), &
k5 = (sign(1,sik5)*(sik5-k4) + (sik5+k4))/2
integer(k5),parameter:: i5 = 1_k5
integer ,parameter:: sik6 = selected_int_kind(range(i5)+1), &
k6 = (sign(1,sik6)*(sik6-k5) + (sik6+k5))/2
integer(k6),parameter:: i6 = 1_k6
integer,parameter:: karray(0:maxnk) = (/-1,k1,k2,k3,k4,k5,k6/)
integer:: i,iolen,k,nk = -1 ! But see the first do loop below.
integer(k6):: iprops(maxnk,6)
real(dp) :: dpihuge
character :: ck(maxnk)*7 = ' '
iprops(1,1:3) = (/digits(i1),radix(i1),range(i1)/) ! RHS default integer
iprops(2,1:3) = (/digits(i2),radix(i2),range(i2)/)
iprops(3,1:3) = (/digits(i3),radix(i3),range(i3)/)
iprops(4,1:3) = (/digits(i4),radix(i4),range(i4)/)
iprops(5,1:3) = (/digits(i5),radix(i5),range(i5)/)
iprops(6,1:3) = (/digits(i6),radix(i6),range(i6)/)
! iprops(:,4 ) = iolen in the second do loop below.
iprops(1,5:6) = (/int(bit_size(i1),k1),huge(i1)/) ! RHS kind k1
iprops(2,5:6) = (/int(bit_size(i2),k2),huge(i2)/) ! RHS kind k2
iprops(3,5:6) = (/int(bit_size(i3),k3),huge(i3)/) ! etc
iprops(4,5:6) = (/int(bit_size(i4),k4),huge(i4)/)
iprops(5,5:6) = (/int(bit_size(i5),k5),huge(i5)/)
iprops(6,5:6) = (/int(bit_size(i6),k6),huge(i6)/)
do k = maxnk,1,-1
if (nk < 0 .and. karray(k) /= karray(k-1)) nk = k
if (iprops(k,6) == int(huge(1),k6)) ck(k) = 'default'
end do ! so nk = min(6,number of different integer kinds)
do k = 1,nk
if (k==1) inquire(iolength=iolen) i1
if (k==2) inquire(iolength=iolen) i2
if (k==3) inquire(iolength=iolen) i3
if (k==4) inquire(iolength=iolen) i4
if (k==5) inquire(iolength=iolen) i5
if (k==6) inquire(iolength=iolen) i6
iprops(k,4) = iolen
if (karray(k)==kind(1)) ck(k) = 'default'
end do
print *
print *,'Integer kind digits radix range iolen bit_size huge'
do k = 1,nk
print "(1X,A7,I3,5I6,8X,I0)",ck(k),karray(k),(iprops(k,i),i=1,6)
dpihuge = real(iprops(k,6),dp)
print "(50X,A,I0,A,T64,A,ES9.2)", &
'= 2**',nint(log(dpihuge)/log(2._dp)),' - 1','~',dpihuge
end do
print *,merge( &
'No higher integer kind is available. ', &
'Warning: there may be more integer kinds.',nk<maxnk)
end program intkinds

Typical output below; your compiler may give different results:

Integer kind digits radix range iolen bit_size huge
1 7 2 2 1 8 127
= 2**7 - 1 ~ 1.27E+02
2 15 2 4 1 16 32767
= 2**15 - 1 ~ 3.28E+04
default 4 31 2 9 1 32 2147483647
= 2**31 - 1 ~ 2.15E+09
8 63 2 18 2 64 9223372036854775807
= 2**63 - 1 ~ 9.22E+18
No higher integer kind is available.

--
-- John Harper

robert....@oracle.com

unread,
Nov 22, 2011, 7:46:27 PM11/22/11
to
On Nov 22, 6:27 am, Tobias Burnus <bur...@net-b.de> wrote:
> On 11/22/2011 02:40 PM, Erik Toussaint wrote:
>
> > On 22-11-2011 7:59, robert.corb...@oracle.com wrote:
> >> In Fortran 2008, constant expressions are no longer
> >> required to have constant values. Consider the
> >> program
>
> > Gfortran seems to disagree with you:
>
> > $ gfortran constexpr.f90 -o constexpr
> > constexpr.f90:7.36:
>
> > TYPE(T), PARAMETER :: C = T(X) !!!
> > 1
> > Error: Parameter 'x' at (1) has not been declared or is a variable,
> > which does not reduce to a constant expression
>
> Well, that's a Fortran 2008 feature - thus, don't expect that compilers
> get already all details correct.
>
> However, having said that, I think I have to agree with Malcolm Cohen
> (on the J3 mailing list) that this is not valid for PARAMETER.

The Fortran 2008 clearly and explicitly allows it. The expression
that
gives the value of a named constant is required to be a constant
expression. Clause 7.1.12 of the Fortran 2008 standard defines what
it
means for an expression to be a constant expression. The structure
constructor is permitted by item (3) in the list in Clause 7.1.12.

The person who proposed adding the feature to the standard said in e-
mail
that he intended to allow structure constructors to include pointer
components initialized to non-NULL() values. His proposed fix is to
ban
structure values that include pointer components from appearing as
actual arguments to the intrinsic function TRANSFER and to ban pointer
components that are initialized to non-NULL() values from appearing in
constant expressions.

I would have preferred not to have allowed pointers to be initialized
to
non-NULL() values. Furthermore, I would not have permitted
polymorphic
pointers to be initialized at all.

Once non-NULL() pointer initializations are permitted, people will
naturally want to initialize arrays of structures that contain pointer
components to values that include non-NULL() initializations of those
components. I have often seen C code that includes initializations of
arrays of pointers. The most natural expression of similar code in
Fortran is as an array of structures that each have a single pointer
component. That form of initialized array is permitted by the
current Fortran 2008 standard.

Bob Corbett

Ian Harvey

unread,
Nov 22, 2011, 8:26:05 PM11/22/11
to
I thought that the value of a pointer component of an object of derived
type was not considered a subobject of that derived type, except to the
extent of its pointer association status (F2008 6.4.2 paragraph 5).

Hence your reference to the value of C%P is not a reference to a
subobject of a constant, so the initialiser for Y is not a constant
expression and that second marked line is invalid.

On the otherhand, the expression ASSOCIATED(C%P) is a constant
expression, but implementations should be able to cope with that.

robert....@oracle.com

unread,
Nov 22, 2011, 8:57:50 PM11/22/11
to
On Nov 22, 5:26 pm, Ian Harvey <ian_har...@bigpond.com> wrote:
That is an excellent point, one that was not raised during the recent
e-mail discussion in the J3 e-mail list. It does appear to make the
case about which I was concerned not a constant expression. The
structure constructor is still allowed, and Malcolm's example
involving
the intrinsic function TRANSFER might still be a problem.

Bob Corbett

Ian Harvey

unread,
Nov 22, 2011, 10:12:01 PM11/22/11
to
Your example confused me, perhaps because of some lines that have been
elided (what's the relevance of sub?). Could you please elaborate?

Ian Harvey

unread,
Nov 22, 2011, 10:44:25 PM11/22/11
to
On 23/11/2011 12:57 PM, robert....@oracle.com wrote:
> On Nov 22, 5:26 pm, Ian Harvey<ian_har...@bigpond.com> wrote:
>> On 22/11/2011 5:59 PM, robert.corb...@oracle.com wrote:
...
I had seen this on the J3 list archive and wondered how things would
play out. For info for others - Malcolm's example was:

INTEGER,PARAMETER :: ia(*) = TRANSFER(dt,[1]) + 1

CALL sub(ia)
...
SUBROUTINE sub(idum)
INTEGER idum(:)
TYPE(t) dt2
dt2 = TRANSFER(ia,dt) ! Guaranteed to give you back your original

He has a "+ 1" in the constant expression for the initializer for ia. I
presume that's an oversight or the later comment makes no sense. There
might be a bit of inadvertant ia/idum swappage going on in the
subroutine too.

What is TRANSFER supposed to do in the case of derived types with
pointer (or, while I'm here, allocatable) components? The component
value of a pointer component is its "pointer association". WTF does
that actually mean? Must the result of the transfer still point to the
same thing, or does it just need to have the same pointer association
status?

Allowing TRANSFER in constant expressions ==> root of all evil.

Richard Maine

unread,
Nov 22, 2011, 11:22:07 PM11/22/11
to
Ian Harvey <ian_h...@bigpond.com> wrote:

> What is TRANSFER supposed to do in the case of derived types with
> pointer (or, while I'm here, allocatable) components? The component
> value of a pointer component is its "pointer association". WTF does
> that actually mean? Must the result of the transfer still point to the
> same thing, or does it just need to have the same pointer association
> status?

I have long thought that the standard's definition of TRANSFER was
flawed in several regards. This is one of them. Such things perhaps
should be disallowed. At the very least, it ought to be made very clear
that all bets are off as to what the result is.

The standard (at least f2003; I haven't checked f2008) talks about
physical representations, but it completely fails to say anything about
cases where physical representations might be invalid. There are many
such possible cases.

1. Some types can have disallowed bit patterns, even for intrinsic
types. It isn't particularly common today, but it is allowed and such
cases have existed.

2. For things like pointers and allocatables, it is quite plausible that
some bit patterns might be invalid. Heck, there are high odds that
*MOST* bit patterns will be invalid. No, there is no guarantee that the
same pointer bit pattern will mean the same target if copied to another
variable. Imaagine things like relative addressing. For allocatables,
things are worse because it would be nonsense for two different
allocatable variables to share the same allocation; allocatables are not
supposed to do that, and allowing them to do so would completely trash
what allocatables are about. Allocatables also don't have an undefined
allocation status (at least as of f95), so you can't even escape by
saying that the result is undefined like that. You really just better
not do it, and the standard ought to say that. Avoiding subsequent
reference to the resulting allocatables doesn't help either, because
"things happen" to allocatables even without explicit reference.
(Notably, local non-saved allocatables get deallocated when the
procedure returns, and that's not going to work well in some of these
cases).

3. There are probably a bunch of other cases as well.

It is bad enough that the standard doesn't disallow such things, some of
which inevitably will lead to no good. Worse is that the standard all
but says in *NORMATIVE* text that they are ok. In f2003, there is
normative text about the value of TRANSFER(TRANSFER(E,D), E) being the
value of E, for scalar D and E, and that requirement has no restrictions
at all on the types of D and E other that that the physical
representation of D be at least as large as that of E. That means it
applies to all of these derived types with "nasty" components, as wel as
to types for which the physical representation might not even be
allowed. That's just horrible.

I never did figure out why that requirement was in normative text
anyway. For the "nice" cases, it seems to be just a deduction from the
definition of TRANSFER and thus ought to be a note. For the messy cases,
it seems wrong.

I've bitched about this before with no particular result. I suspect it
is one of those things that doesn't get much priority for fixing because
"you ought to know better than to do things like that even though the
standard doesn't say so." I'm not advocating that position, just
postulating it.

> Allowing TRANSFER in constant expressions ==> root of all evil.

TRANSFER has plenty more problems than that. Just taking it out of
constant expressions would leave plenty of evil. And I'm afraid I can
see some good argument for allowing it in constant expressions; not
horrible ones like these cases, but I can imagine things like
initializing reals with hex bit patterns. Doesn't take a lot of
imagination either, as I have seen it done. Sure, the value is machine
dependent, but there are times when it's really what you want.

robert....@oracle.com

unread,
Nov 23, 2011, 12:58:48 AM11/23/11
to
On Nov 22, 8:22 pm, nos...@see.signature (Richard Maine) wrote:

> TRANSFER has plenty more problems than that. Just taking it out of
> constant expressions would leave plenty of evil. And I'm afraid I can
> see some good argument for allowing it in constant expressions; not
> horrible ones like these cases, but I can imagine things like
> initializing reals with hex bit patterns.

That is not among the cases permitted by the Fortran 2008
standard. The intrinsic function TRANSFER is not allowed
to take a boz-literal-constant as an argument. The
functions CMPLX, INT, and REAL are allowed to take a
boz-literal-constant as an argument. I thought CHAR might
be able to take a boz-literal-constant as an argument, but
that is not the case. So

CHAR('7F')

is not permitted, but

CHAR(INT('7F'))

is permitted. The restriction seems pointless, given that
the same functionality can be expressed just less cleanly.

Bob Corbett

robert....@oracle.com

unread,
Nov 23, 2011, 1:06:19 AM11/23/11
to
On Nov 22, 7:44 pm, Ian Harvey <ian_har...@bigpond.com> wrote:

> I had seen this on the J3 list archive and wondered how things would
> play out.

So far, I count two votes on the committee for revising
the definition of a constant expression to ban
structure constructors include pointer components
with non-NULL() values, and two votes for changing
the specification of TRANSFER to ban the cases that
cause trouble.

Bob Corbett

glen herrmannsfeldt

unread,
Nov 23, 2011, 2:17:46 AM11/23/11
to
Richard Maine <nos...@see.signature> wrote:

(snip)
> I have long thought that the standard's definition of TRANSFER was
> flawed in several regards. This is one of them. Such things perhaps
> should be disallowed. At the very least, it ought to be made very
> clear that all bets are off as to what the result is.

> The standard (at least f2003; I haven't checked f2008) talks about
> physical representations, but it completely fails to say anything about
> cases where physical representations might be invalid. There are many
> such possible cases.

> 1. Some types can have disallowed bit patterns, even for intrinsic
> types. It isn't particularly common today, but it is allowed and such
> cases have existed.

Well, the standard doesn't even require binary. Still, one might hope
that the same storage base be used for all data types.

C allows for assignment between integers (of the appropriate size)
and pointers with a note similar to "those who understand the
underlying machine will know how it works." It seems to me that
in many cases TRANSFER should have a similar comment. If you know
what you are doing, what the actual data patterns are, then you
know what makes sense. Only do things that make sense.

The JVM (Java Virtual Machine) disallows any operation that mixes
reference objects (pointers) and primitive data types. There are
no operations that let you look inside a pointer. JVM also
restricts operations on 64 bit (long and double) such that you
can't look at part of one.

> 2. For things like pointers and allocatables, it is quite plausible
> that some bit patterns might be invalid. Heck, there are high odds that
> *MOST* bit patterns will be invalid. No, there is no guarantee that the
> same pointer bit pattern will mean the same target if copied to another
> variable. Imaagine things like relative addressing.

Well, relative addressing could be fixed if needed. I was remembering
in another recent discussion, there is an old trick to save memory
on a doubly-linked list by storing the XOR of the two pointers.
Since you always know where you came from, you can figure out the
next pointer by XOR the address you came from. In most cases,
subtracting the two pointers will give similar results.

But yes, doing things with the internal representation of
pointers makes the result system dependent.

> For allocatables,
> things are worse because it would be nonsense for two different
> allocatable variables to share the same allocation; allocatables are not
> supposed to do that, and allowing them to do so would completely trash
> what allocatables are about. Allocatables also don't have an undefined
> allocation status (at least as of f95), so you can't even escape by
> saying that the result is undefined like that. You really just better
> not do it, and the standard ought to say that. Avoiding subsequent
> reference to the resulting allocatables doesn't help either, because
> "things happen" to allocatables even without explicit reference.
> (Notably, local non-saved allocatables get deallocated when the
> procedure returns, and that's not going to work well in some of these
> cases).

It seems to me that for some systems it could be made to work,
such that deallocating all or any (system dependent) would
deallocate the actual data. For a garbage collecting system,
you deallocate all before the data goes away. For a double
indirect system you could do it either way. But again, one
should know that the result is system dependent.

> 3. There are probably a bunch of other cases as well.

There probably are.

> It is bad enough that the standard doesn't disallow such things, some of
> which inevitably will lead to no good. Worse is that the standard all
> but says in *NORMATIVE* text that they are ok. In f2003, there is
> normative text about the value of TRANSFER(TRANSFER(E,D), E) being the
> value of E, for scalar D and E, and that requirement has no restrictions
> at all on the types of D and E other that that the physical
> representation of D be at least as large as that of E. That means it
> applies to all of these derived types with "nasty" components, as wel as
> to types for which the physical representation might not even be
> allowed. That's just horrible.

Well, in that exact case the compiler can optimize away the double
TRANSFER. If you store the intermediate value, though, it can't.

Even more interesting, write the intermediate value to disk and read
it back in again. (C allows writing and reading pointers, but
doesn't guarantee that they still point to the same place.)

> I never did figure out why that requirement was in normative text
> anyway. For the "nice" cases, it seems to be just a deduction from
> the definition of TRANSFER and thus ought to be a note.
> For the messy cases, it seems wrong.

To me, it is too hard to separate the cases that work on a specific
machine from the ones that don't. Just remind people that it might
not work. Most now only use these things when they really need
to and know what the specific machine will do. (Or at least I
hope that is true.)

(snip)

-- glen

Richard Maine

unread,
Nov 23, 2011, 5:37:25 AM11/23/11
to
glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

> Richard Maine <nos...@see.signature> wrote:

> > I have long thought that the standard's definition of TRANSFER was
> > flawed in several regards.
...
> > 2. For things like pointers and allocatables, it is quite plausible
> > that some bit patterns might be invalid. [goes on about the problems]
...
> It seems to me that for some systems it could be made to work,...

One is going to make such a complicated scheme, majorly redoing how
allocatables are implemented? When getting all the corner cases of
allocatables to work in the first place took as long as it did? (It took
an awful long time, first just to get the requirements of the standard
to make sense, and then to get most compilers to implement it at least
approximately correctly. There were *LOTS* of bugs along the way). And
someone is going to do this just to make a strange case of the TRANSFER
intrinsic work as the standard poorly describes it? I don't think so;
not in this world.

(Not to speak of the fact that you only described an approach for
deallocation. One would have to add yet more complication to get all the
other semantics right. I suppose you'd suggest some mess like
copy-on-write to avoid having two different variables act like they were
associated when they weren't supposed to be).

*MUCH* simpler to just fix the definition of TRANSFER. It isn't as
though there is any actual utility to make TRANSFER work in the odd
cases described. If one wants the functionality of derived type
assignment, there is already... derived type assignment, which isn't
handicapped by being defined as a copy of the physical representation.
The cost/benefit of contorting everything to avoid fixing the definition
of TRANSFER just isn't there; it isn't even close.

> > It is bad enough that the standard doesn't disallow such things, some of
> > which inevitably will lead to no good. Worse is that the standard all
> > but says in *NORMATIVE* text that they are ok. In f2003, there is
> > normative text about the value of TRANSFER(TRANSFER(E,D), E) being the
> > value of E, for scalar D and E, and that requirement has no restrictions
> > at all on the types of D and E other that that the physical
> > representation of D be at least as large as that of E. That means it
> > applies to all of these derived types with "nasty" components, as wel as
> > to types for which the physical representation might not even be
> > allowed. That's just horrible.
>
> Well, in that exact case the compiler can optimize away the double
> TRANSFER. If you store the intermediate value, though, it can't.

Optimizing requires that you have something well defined in the first
place. It is nonsense to have a definition that doesn't make sense
unless you optimize it.

glen herrmannsfeldt

unread,
Nov 23, 2011, 9:42:01 AM11/23/11
to
Richard Maine <nos...@see.signature> wrote:
> glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
>> Richard Maine <nos...@see.signature> wrote:

>> > I have long thought that the standard's definition of TRANSFER was
>> > flawed in several regards.

>> > 2. For things like pointers and allocatables, it is quite plausible
>> > that some bit patterns might be invalid. [goes on about the problems]

>> It seems to me that for some systems it could be made to work,...

> One is going to make such a complicated scheme, majorly redoing how
> allocatables are implemented? When getting all the corner cases of
> allocatables to work in the first place took as long as it did? (It took
> an awful long time, first just to get the requirements of the standard
> to make sense, and then to get most compilers to implement it at least
> approximately correctly. There were *LOTS* of bugs along the way). And
> someone is going to do this just to make a strange case of the TRANSFER
> intrinsic work as the standard poorly describes it? I don't think so;
> not in this world.

No. What I do is say that it is system dependent. That if it
works on your system then you can use it, if you know what it
does and why.

That is already true for other types. Assignment between fixed
and floating point could generate illegal patterns in one, most
likely in floating point. For VAX, the bit pattern representing
negative zero is a trap representation. You need to know that
if you use TRANSFER between INTEGER and REAL on VAX.

Some machines will normalize floating point values which messes
up any bit patterns one might store in them.

As I said before, the standard doesn't even require binary, so
it might not even make sense to ask about bit patterns.

But for many currently popular systems you can copy back and
forth between fixed and floating point, and do that without
any unusual problems. Well, you might run into signaling NaN
in IEEE floating point.

> (Not to speak of the fact that you only described an approach for
> deallocation. One would have to add yet more complication to get all the
> other semantics right. I suppose you'd suggest some mess like
> copy-on-write to avoid having two different variables act like they were
> associated when they weren't supposed to be).

No, other way around. If you use it on a system where it works,
then you get the specified (on that system) results.

> *MUCH* simpler to just fix the definition of TRANSFER. It isn't as
> though there is any actual utility to make TRANSFER work in the odd
> cases described. If one wants the functionality of derived type
> assignment, there is already... derived type assignment, which isn't
> handicapped by being defined as a copy of the physical representation.
> The cost/benefit of contorting everything to avoid fixing the definition
> of TRANSFER just isn't there; it isn't even close.

>> > It is bad enough that the standard doesn't disallow such things, some of
>> > which inevitably will lead to no good. Worse is that the standard all
>> > but says in *NORMATIVE* text that they are ok. In f2003, there is
>> > normative text about the value of TRANSFER(TRANSFER(E,D), E) being the
>> > value of E, for scalar D and E, and that requirement has no restrictions
>> > at all on the types of D and E other that that the physical
>> > representation of D be at least as large as that of E. That means it
>> > applies to all of these derived types with "nasty" components, as wel as
>> > to types for which the physical representation might not even be
>> > allowed. That's just horrible.
>>
>> Well, in that exact case the compiler can optimize away the double
>> TRANSFER. If you store the intermediate value, though, it can't.

> Optimizing requires that you have something well defined in the first
> place. It is nonsense to have a definition that doesn't make sense
> unless you optimize it.

It allows for the given statement to work, but not more.

If instead you say:

D=TRANSFER(E,D)
E=TRANSFER(D,E)

and state that gives the original value of E, and note that you
also get to keep D, that seems to me to be a stronger statement,
but also one that the standard seems not to make.

But go back to VAX. Say you do TRANSFER(TRANSFER(E,D),E) for
the value that is a trap representation in floating point.
Should it, in that statement, actually trap? That might mean
actually storing in a floating point register, which, as
far as I know, isn't required.

If you store into an actual floating point variable, though,
it is harder to argue that it not trap.

-- glen

Louisa

unread,
Nov 23, 2011, 10:19:27 AM11/23/11
to
On Nov 23, 10:10 am, John Harper <john.har...@vuw.ac.nz> wrote:

> You may find my 68-line f95 program for finding the properties of all the
> integer kinds known to your compiler useful. (I have another one for real
> kinds that I'll be happy to email to anyone who asks me, john.harper at
> vuw.ac.nz). If you spot a bug or if it fails to compile with your f95 please
> send details.

It fails to compile with Silverfrost F95, with invalid kind numbers.
The stumbling block is the argument 0 in SELECTED_INT_KIND at the
beginning. It needs to be 1, and the compilation is fine.

Selected_int_kind(r) specifies that the values required to be stored
have a modulus less than 10**0, which is 1.
Now, the only value that can be stored with r = 0 is 0,
which is kind of ... silly.

Richard Maine

unread,
Nov 23, 2011, 11:17:48 AM11/23/11
to
glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

> No. What I do is say that it is system dependent. That if it
> works on your system then you can use it, if you know what it
> does and why.

Ok. But we have a term for that. It is called nonstandard conforming,
which is exactly what I was proposing it be. That's exactly what it
means for something to be nonstandard. It doesn't mean you absolutely
can't do it. It means that the standard doesn't guarantee that you can
do it, even though you might be able top on some systems.

Do note that there is a difference between being nonstandard and having
system-dependent results. If something has system-dependent results,
then the standard guarantees that you can do it and get something, even
though the value of the something might vary from system to system.

> That is already true for other types. Assignment between fixed
> and floating point could generate illegal patterns in one, most
> likely in floating point. For VAX, the bit pattern representing
> negative zero is a trap representation. You need to know that
> if you use TRANSFER between INTEGER and REAL on VAX.
>
> Some machines will normalize floating point values which messes
> up any bit patterns one might store in them.

Yep. And those kinds of cases are exactly why my first bullet a few
posts back said

>> 1. Some types can have disallowed bit patterns, even for intrinsic
>> types. It isn't particularly common today, but it is allowed and such
>> cases have existed.

> As I said before, the standard doesn't even require binary, so
> it might not even make sense to ask about bit patterns.

Yes. I've been a bit lazy in using the phrase "bit pattern". For the
most part, just substitute "physical representation".

> > Optimizing requires that you have something well defined in the first
> > place. It is nonsense to have a definition that doesn't make sense
> > unless you optimize it.
>
> It allows for the given statement to work, but not more.

Then it isn't an "optimization". An optimization starts with something
that is well-defined and transforms it into something else that gives
the "same mathematical result" (with all the quibbles about exactly what
that means).

It looks to me like we are arguing about a variant of a viewpoint
difference we often have, where you are looking more at implementation
compared to my looking at the specification of the standard. Sure an
implementation might make a form like that do something even though the
individual parts couldn't work. But the standard defines things like
F(F(x)) in terms of evaluating F(X) and using that as an actual argument
for F. A particular implementation might transform special cases of
F(F(X)) into something that would run even if F(X) wouldn't, but that's
not how the standard specifies things. I'm talking about what should be
specified by the standard, with the acknowledgement that yes, particular
implementations often do things, sometimes useful things, in cases that
are nonstandard.

glen herrmannsfeldt

unread,
Nov 23, 2011, 4:54:13 PM11/23/11
to
Richard Maine <nos...@see.signature> wrote:
> glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

>> No. What I do is say that it is system dependent. That if it
>> works on your system then you can use it, if you know what it
>> does and why.

> Ok. But we have a term for that. It is called nonstandard conforming,
> which is exactly what I was proposing it be. That's exactly what it
> means for something to be nonstandard. It doesn't mean you absolutely
> can't do it. It means that the standard doesn't guarantee that you can
> do it, even though you might be able top on some systems.

I suppose some hint that one should be careful wouldn't seem
a bad idea. It seems, though, that there are enough cases where
it can fail with just integers, more when you consider floating
point, and way more with pointers and allocatables.

However, defining it as giving the same physical representation
means that you know exactly what it will try to do, good or bad.

OK, say you TRANSFER from integer to real, such that the real
value is a trap representation, and will trap when loaded into
a floating point register. Now, should TRANSFER (TRANSFER (E, D)
trap in that case? On many systems, you can get a floating point
value into memory without going through a floating point register,
so on those it is possible to avoid the problem.

Now, if you have a machine that uses base 3 for integers and
base 7 for floating point then you are stuck. There isn't a
physical representation that makes sense in the other base.

> Do note that there is a difference between being nonstandard and having
> system-dependent results. If something has system-dependent results,
> then the standard guarantees that you can do it and get something, even
> though the value of the something might vary from system to system.

OK, but we know that the value can be system dependent in too
many ways. If you just said that TRANSFER was non-standard, you
get what you get, then it wouldn't be very useful. The way it is,
you know that the system does as best it can to transfer the
physical representation, and that you are responsible for what you
do with the result.

There are probably enough systems that can TRANSFER pointers
with useful results, but one should not be surprised to see
it fail on other systems.

>> That is already true for other types. Assignment between fixed
>> and floating point could generate illegal patterns in one, most
>> likely in floating point. For VAX, the bit pattern representing
>> negative zero is a trap representation. You need to know that
>> if you use TRANSFER between INTEGER and REAL on VAX.

>> Some machines will normalize floating point values which messes
>> up any bit patterns one might store in them.

> Yep. And those kinds of cases are exactly why my first bullet a few
> posts back said

>>> 1. Some types can have disallowed bit patterns, even for intrinsic
>>> types. It isn't particularly common today, but it is allowed and such
>>> cases have existed.

But even then, in many systems the disallowed cases are only
disallowed when used in a certain way. For floating point values,
only if used in a floating point operation, though possibly just
loading into a floating point register. Machines with signaling
NaN aren't so uncommon, either. (I am not sure what the
standard says about Signaling NaN.)

>> As I said before, the standard doesn't even require binary, so
>> it might not even make sense to ask about bit patterns.

> Yes. I've been a bit lazy in using the phrase "bit pattern". For the
> most part, just substitute "physical representation".

>> > Optimizing requires that you have something well defined in the first
>> > place. It is nonsense to have a definition that doesn't make sense
>> > unless you optimize it.

>> It allows for the given statement to work, but not more.

> Then it isn't an "optimization". An optimization starts with something
> that is well-defined and transforms it into something else that gives
> the "same mathematical result" (with all the quibbles about exactly what
> that means).

> It looks to me like we are arguing about a variant of a viewpoint
> difference we often have, where you are looking more at implementation
> compared to my looking at the specification of the standard.

In this case, though, that is hard to avoid. You can't really
discuss physical representation without an implementation.

> Sure an
> implementation might make a form like that do something even though the
> individual parts couldn't work. But the standard defines things like
> F(F(x)) in terms of evaluating F(X) and using that as an actual argument
> for F. A particular implementation might transform special cases of
> F(F(X)) into something that would run even if F(X) wouldn't, but that's
> not how the standard specifies things. I'm talking about what should be
> specified by the standard, with the acknowledgement that yes, particular
> implementations often do things, sometimes useful things, in cases that
> are nonstandard.

OK, but it could be read to require implementers to try to
avoid the possible problems. If there are two reasonable
implementations, and one causes F(F(X)) to fail then one shouldn't
implement it that way.

To be more specific, it is reasonable to transfer to/from
a Signaling NaN without signaling. I might want to assign one
to a variable, and only have it signal when using that value.

If one wants more, TRANSFER(TRANSFER(D,E)+0)

Still, I wouldn't fault a system that signals on the transfer
if that was the only possible implementation.

-- glen

John Harper

unread,
Nov 23, 2011, 10:17:27 PM11/23/11
to
Thank you - Silverfrost was not one of my 4 compilers. As I read the specs
selected_int_kind(0) should allow for 3 values,-1,0,+1, so it could be
useful for 3-valued logic. But I'll change the program.

--
-- John Harper

arjenmarkus

unread,
Nov 24, 2011, 9:57:56 AM11/24/11
to
Hm, IIRC, selected_int_kind(r) is supposed to return the kind of the
smallest integer type that can store a value 10**r. Such an integer type
is however allowed to be able to store larger values.

So I think there can be only one outcome and that Silverfrost is wrong.

Regards,

Arjen
su

Richard Maine

unread,
Nov 24, 2011, 12:33:38 PM11/24/11
to
I'll quibble slightly with your exact definition of the range. I think
you have an off-by-one error. There are no current implementations where
the difference matters, but the standard says that the integer type must
be able to store values less than 10**r. It doesn't have to be able to
store that value. Thus r=0 would not necessarily imply the ability to
store the values 1 and -1.

But as you say, the integer type is allowed to be able to store larger
values. Indeed, there being no current decimal integer representations
that I know of, that's basically the case for the kinds you get for all
values of r. I agree that Silverfrost is wrong to reject the code. I
don't see the exact message, but I'm assuming that selected_int_kind(0)
is returning -1. I can't see any excuuse in the standard for that.

In fact, as far as I can see, even negative values of r are allowed and
should return a valid kind value. It might not make a lot of sense to
use selected_int_kind with a negative value of r, but I see nothing that
says it is invalid.

Louisa

unread,
Nov 24, 2011, 6:56:04 PM11/24/11
to
No, the spec requires that a variable be capable of storing values
less than 10**0 in magnitude. Since 10**0 is 1, that means that
such a variable could store only the value 0, which seems pretty
meaningless.

Louisa

unread,
Nov 24, 2011, 7:00:01 PM11/24/11
to
On Nov 25, 1:57 am, arjenmarkus <arjen.markus...@gmail.com> wrote:
> On 2011-11-24 04:17, John Harper wrote:
>
>
>
>
>
> > Louisa wrote:
>
> >> On Nov 23, 10:10 am, John Harper <john.har...@vuw.ac.nz> wrote:
>
> >>> You may find my 68-line f95 program for finding the properties of all the
> >>> integer kinds known to your compiler useful. (I have another one for real
> >>> kinds that I'll be happy to email to anyone who asks me, john.harper at
> >>> vuw.ac.nz). If you spot a bug or if it fails to compile with your f95
> >>> please send details.
> >> It fails to compile with Silverfrost F95, with invalid kind numbers.
> >> The stumbling block is the argument 0 in SELECTED_INT_KIND at the
> >> beginning. It needs to be 1, and the compilation is fine.
>
> >> Selected_int_kind(r) specifies that the values required to be stored
> >> have a modulus less than 10**0, which is 1.
> >> Now, the only value that can be stored with r = 0 is 0,
> >> which is kind of ... silly.
>
> > Thank you - Silverfrost was not one of my 4 compilers. As I read the specs
> > selected_int_kind(0) should allow for 3 values,-1,0,+1, so it could be
> > useful for 3-valued logic. But I'll change the program.
>
> Hm, IIRC, selected_int_kind(r) is supposed to return the kind of the
> smallest integer type that can store a value 10**r.

No, it must be capable of storing a value LESS than 10**r
(in magnitude).

> Such an integer type
> is however allowed to be able to store larger values.

That's a bonus, if larger values can be stored, if such is the case.

> So I think there can be only one outcome and that Silverfrost is wrong.

See previous posting.

Louisa

unread,
Nov 24, 2011, 7:20:27 PM11/24/11
to
On Nov 25, 4:33 am, nos...@see.signature (Richard Maine) wrote:
The literal interpretasion of 10**(-1) or another other negative value
of R, in the Fortran integer sense, is that values less than zero
[in magnitude] can be stored.
Doesn't sound like a sensible specification to me.

Richard Maine

unread,
Nov 24, 2011, 11:06:54 PM11/24/11
to
No. The exact words of the standard are "an integer type that represents
all integer values n with -10**R < n < 10**R. (I've substituted ** for
the standard's superscript). For the case of R=-1, that would be the set
of integers n with -0.1 < n < 0.1. That is a perfectly well-defined set
of integers, which includes the single value 0. I see no words in the
standard that say anything about values less than zero in magnitude or
anything particularly close to that.

> Doesn't sound like a sensible specification to me.

That's because the specification you paraphrase isn't in the standard.
The words that actually *ARE* in the standard make a lot more sense than
your rephrased version. I really don't see where you get the bit about
values less than zero in magnitude. At first I thought you were talking
about values less than 1 in magnitude. That is closer to what the
standard says, even if not it's exact wording. But your "values less
than zero [in magnitude]" seems to have come out of thin air; there's
nothing even close to that.

Erik Toussaint

unread,
Nov 25, 2011, 7:27:47 AM11/25/11
to
I think Louisa interprets 10**R as a Fortran integer expression, which
would indeed return 0 for negative values of R, as opposed to the
'regular mathematical' interpretation, which returns a fractional number.

Erik.

Richard Maine

unread,
Nov 25, 2011, 11:26:01 AM11/25/11
to
Erik Toussaint <us...@example.net.invalid> wrote:

> On 25-11-2011 5:06, Richard Maine wrote:

> > No. The exact words of the standard are "an integer type that represents
> > all integer values n with -10**R< n< 10**R. (I've substituted ** for
> > the standard's superscript). For the case of R=-1, that would be the set
> > of integers n with -0.1< n< 0.1. That is a perfectly well-defined set
> > of integers, which includes the single value 0. I see no words in the
> > standard that say anything about values less than zero in magnitude or
> > anything particularly close to that.

> I think Louisa interprets 10**R as a Fortran integer expression, which
> would indeed return 0 for negative values of R, as opposed to the
> 'regular mathematical' interpretation, which returns a fractional number.

Perhaps. But if so, I don't see support for that interpretation. There
have been cases where there was plausible question whether an expression
was meant as a mathematical one or a Fortran one. I don't recall a
specific example off-hand, but there have been some.

However, in this case, the form in the standard does not at all support
interpretation as a Fortran expression.

1. See my note above about how I substituted a ** for the standard's
superscript. The standard doesn't have a ** in this expression. It has a
superscript. Superscripts are not Fortran.

2. The form x<y<z is not Fortran. People have been known to wish that it
was or even mistakenly write code like that, but it isn't - at least not
without a defined operation, which won't be able to match the result of
the mathematical form. It parses as (x<y)<z. The (x<y> gives a logical
result and the standard does not define < for comparing a logical first
operand with a numeric second operand. A user could make that a defined
operation, but it won't be able to get the "expected" answer.

3. The n in the standard's version of the formula is in italic lower
case. That's right for a mathematical expression. The standard never
uses that form for Fortran expressions.

4. It would be self-contradictory as a Fortran expression. It says that
10**R (with a superscript instead of the **) is greater than the largest
value that it says must be representable. Elsewhere the standard says
that you are not allowed to do the intrinsic operations with operands
that give results that are out of the range of representable values.

So if that was what he meant, I'm going to (well, I guess I just did)
come down pretty hard on saying that the interpretation is not
reasonably supportable.

Terence

unread,
Nov 26, 2011, 4:16:33 PM11/26/11
to
Replying to the follow-up question on minimum integer size, one of my HP F77
compilers allows INTEGER*1 (8 bits).
All allow INTEGER*2 (16 bits).including the F90/95 ones.
Unless obsoleted I would assume the answer is 16 if not still 8.
Certainly I have compiled and used modules offering Integer*2 arithmetic
routines to match some early calling standards.






Louisa

unread,
Nov 28, 2011, 6:23:58 PM11/28/11
to
On Nov 25, 4:33 am, nos...@see.signature (Richard Maine) wrote:
Correct.

> But as you say, the integer type is allowed to be able to store larger
> values.

But only if it can store such values.
And there can be large differences from one implementation to another.
For example, if you asked for 2 decmal digits, you could get a byte
(values up to 127) in one implemtnation, or you could get 4 bytes
(up to 2147483647) in another implementation.
I guess that the only real guarantee that you have is that you can
store values up to 99.

> Indeed, there being no current decimal integer representations
> that I know of, that's basically the case for the kinds you get for all
> values of r. I agree that Silverfrost is wrong to reject the code. I
> don't see the exact message, but I'm assuming that selected_int_kind(0)
> is returning -1. I can't see any excuuse in the standard for that.
>
> In fact, as far as I can see, even negative values of r are allowed and
> should return a valid kind value. It might not make a lot of sense to
> use selected_int_kind with a negative value of r, but I see nothing that
> says it is invalid.

Except that ith a negative value for R, 10**r equates to zero,
and you are effectively asking to store values less than zero, in
magnitude. As I said, that's kinda silly.

Louisa

unread,
Nov 28, 2011, 6:34:44 PM11/28/11
to
On Nov 25, 11:27 pm, Erik Toussaint <u...@example.net.invalid> wrote:

> I think Louisa interprets 10**R as a Fortran integer expression, which
> would indeed return 0 for negative values of R, as opposed to the
> 'regular mathematical' interpretation, which returns a fractional number.

Indeed.

Louisa

unread,
Nov 28, 2011, 6:33:54 PM11/28/11
to
On Nov 25, 3:06 pm, nos...@see.signature (Richard Maine) wrote:
> Louisa <louisa.hu...@gmail.com> wrote:
> > On Nov 25, 4:33 am, nos...@see.signature (Richard Maine) wrote:
> > > In fact, as far as I can see, even negative values of r are allowed and
> > > should return a valid kind value. It might not make a lot of sense to
> > > use selected_int_kind with a negative value of r, but I see nothing that
> > > says it is invalid.
>
> > The literal interpretasion of 10**(-1) or another other negative value
> > of R, in the Fortran integer sense, is that values less than zero
> > [in magnitude] can be stored.
>
> No. The exact words of the standard are "an integer type that represents
> all integer values n with -10**R < n < 10**R. (I've substituted ** for
> the standard's superscript). For the case of R=-1, that would be the set
> of integers n with -0.1 < n < 0.1. That is a perfectly well-defined set
> of integers, which includes the single value 0. I see no words in the
> standard that say anything about values less than zero in magnitude or
> anything particularly close to that.
>
> > Doesn't sound like a sensible specification to me.
>
> That's because the specification you paraphrase isn't in the standard.

But it is. -10**R < n < 10**R [that you quote] becomes
-10**(-1) < n < 10**(-1) when R = -1.
That looks like -0 < n < 0 to me (and not the -0.1 < n < 0.1 that
you think). That equates to less than zero, in magnitude.

It seems to me that quoting fractions wrt integer values
makes no sense.

> The words that actually *ARE* in the standard make a lot more sense than
> your rephrased version. I really don't see where you get the bit about
> values less than zero in magnitude. At first I thought you were talking
> about values less than 1 in magnitude. That is closer to what the
> standard says, even if not it's exact wording. But your "values less
> than zero [in magnitude]" seems to have come out of thin air; there's
> nothing even close to that.

See above.

Louisa

unread,
Nov 28, 2011, 6:42:47 PM11/28/11
to
Think of it another way.
When you write selected_int_kind(R),
you are saying that you want to store values having up to
R decimal digits.

Writing selected_int_kind(0) means that you want to store
values having no decimal digits (or if you prefer, zero decimal
digits).

Writing selected_int_kind(-1) is even sillier.

Richard Maine

unread,
Nov 28, 2011, 8:54:03 PM11/28/11
to
Then see my other followup where I show how unsupportable that
interpretation is.

Richard Maine

unread,
Nov 28, 2011, 8:54:04 PM11/28/11
to
Louisa <louisa...@gmail.com> wrote:

> Writing selected_int_kind(-1) is even sillier.

Indeed. But it has a result that is well-defined by the standard. The
standard most definitely does *NOT* prohibit one from writing "silly"
code. Innumerable examples exist. Sometimes they are even things that
look silly to the casual observer, but actually had very good reasons. I
could quote several specific examples, but I think I'll not bother.

The question was not whether the code was sily, but whether it conformed
to the standard. It is standard-conforming code and a compiler is in
error to give the result -1, as Salford reportedly did.

David Thompson

unread,
Jan 19, 2012, 2:41:43 AM1/19/12
to
On Wed, 23 Nov 2011 07:17:46 +0000 (UTC), glen herrmannsfeldt
<g...@ugcs.caltech.edu> wrote:

> Richard Maine <nos...@see.signature> wrote:
<snip: TRANSFER>
> C allows for assignment between integers (of the appropriate size)
> and pointers with a note similar to "those who understand the
> underlying machine will know how it works." It seems to me that
> in many cases TRANSFER should have a similar comment. If you know
> what you are doing, what the actual data patterns are, then you
> know what makes sense. Only do things that make sense.
>
C assignment between different types converts the value. To
re-interpret the representation (aka bit pattern) like TRANSFER you
must use a pointer (e.g. convert a float* to an int* and then
dereference) or a union. And then you face basically the same
limitations: if you read through a 'wrong-type' pointer or a 'wrong'
union choice, it's implementation-defined or worse. One exception: C
allows any valid chunk of memory to be accessed as array of unsigned
char, for things like memcpy(), and usually signed or plain char also.

> The JVM (Java Virtual Machine) disallows any operation that mixes
> reference objects (pointers) and primitive data types. There are
> no operations that let you look inside a pointer. JVM also
> restricts operations on 64 bit (long and double) such that you
> can't look at part of one.
>
There is one operation type that arguably mixes: arrays are objects,
and array access operations (iaload, faload, iastore, fastore, etc.)
take an object which must be an array (of a particular primitive type
or any object type) and an int subscript.

The standard support library provides methods that convert integer bit
patterns to floating-point and vice versa, implemented as 'native'
(outside the JVM proper). For 'long' integers, although there are no
operations to access the halves as such, you can of course get the
same result with bitshift and int<->long conversions.

For safety there must not be (and isn't) any way to cheat on pointers.

0 new messages