Community
cancel
Showing results for
Did you mean:
Highlighted
Beginner
45 Views

## Initialization of int64 parameters with boz-literal-constants

Hello,

If, in the body of a program, in a call to the INT intrinsic with second argument kind=int64, I use as first argument a boz-literal-constant such that either (A) the bit #31 is the highest bit specified and has value one (rightmost bit is #0) or (B) the boz constant is an octal constant where the two highest bit specified are #32 set to zero and #31 set to one (that is, the most significant octal digit is a 2 or a 3), I obtain the result I would expect according to the 2008 version of the Fortran standard (section 13.3.3):

"When a boz-literal-constant is the argument A of the intrinsic function INT or REAL, if the length of the sequence of bits specified by A is less than the size in bits of a scalar variable of the same type and kind type parameter as the result, the boz-literal-constant is treated as if it were extended to the length equal to the size in bits of the result by padding on the left with zero bits [...],"

and the result is a positive integer number; e.g.,

```   integer(kind=int64) :: Vz
!76543210
Vz = int(z'80000000', kind=int64)
write(*,'(a, 24x,    a)') "Position", "76543210"
write(*,'(a,i18,1x,z16)') "Vz = ", Vz, Vz```

results in

```Position                        76543210
Vz =         2147483648         80000000
```

However, if this happens when setting the value of a parameter, the boz-literal-constant seems to be padded with ones to the left: the code

```                                               !76543210
integer(kind=int64), parameter :: Pz = int(z'80000000', kind=int64)
write(*,'(a, 24x,    a)') "Position", "76543210"
write(*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz```

results in a negative integer

```Position                        76543210
Pz =        -2147483648 FFFFFFFF80000000```

I initially thought I might be interpreting incorrectly the standard, and that this behaviour could be related to the last sentence in the Result Value section of the INT intrinsic (section 13.7.81):

"The interpretation of a bit sequence whose most significant bit is 1 is processor dependent."

However, (a) I think this only makes sense if the most significant bit is 1 after the padding/truncation described in 13.3.3 has taken place, and (b) this would not include the octal case described in (B) above, since in that case the most significant bit specified is indeed zero.

Would it be possible for you to clarify whether my interpretation of the standard is wrong, or whether there might be a bug in the compiler?

I am experiencing this behaviour with the Intel compiler versions 16.0.3, 17.0.2 and 18.0.0 20170510.  I am attaching a source file that exemplifies this - the outputs I obtain with the three versions above are the same:

```\$ ifort minbozint.f90 -o minbozint.ifort -check all -warn all -std08 && ./minbozint.ifort
Position                        76543210
Pz =        -2147483648 FFFFFFFF80000000
Po =        -2147483648 FFFFFFFF80000000
Pb =        -2147483648 FFFFFFFF80000000
Vz =         2147483648         80000000
Vo =         2147483648         80000000
Vb =         2147483648         80000000```

Thank you very much for your help.

Tags (1)

Accepted Solutions
Highlighted
Black Belt Retired Employee
45 Views

Whichever choice is correct, the compiler ought to be consistent about it. My reading of the standard is that the value should be padded with zeroes. That it is not is a compiler bug.

That last sentence about "processor-dependent" is referring to the final value of A, after padding or truncation (if any). There's nothing in the standard that says a leftmost bit of 1 means a negative value - the standard goes out of its way to discuss the "bit model" (13.3) in terms of "non-negative" values. The sentence is not relevant to HOW the compiler does its padding or truncation.

16 Replies
Highlighted
Black Belt Retired Employee
46 Views

Whichever choice is correct, the compiler ought to be consistent about it. My reading of the standard is that the value should be padded with zeroes. That it is not is a compiler bug.

That last sentence about "processor-dependent" is referring to the final value of A, after padding or truncation (if any). There's nothing in the standard that says a leftmost bit of 1 means a negative value - the standard goes out of its way to discuss the "bit model" (13.3) in terms of "non-negative" values. The sentence is not relevant to HOW the compiler does its padding or truncation.

Highlighted
Moderator
45 Views

Thank you for your report! This issue is better to be reported via our Online Service Center at https://supporttickets.intel.com/
Instructions on how to file a ticket are available here:
https://software.intel.com/en-us/articles/how-to-create-a-support-request-at-online-service-center

Highlighted
Black Belt
45 Views

z'80000000'

Is interpreted as INTEGER(4)

int(z'80000000', kind=int64)

Converts an INTEGER(4) to INTEGER(8)... with sign propagation.

use z'0000000080000000'

or try z'080000000'

thus forcing the literal to 36 bits (IOW into 64-bit internal form).

Jim Dempsey

Highlighted
Black Belt Retired Employee
45 Views

It should not be doing sign propagation.

Highlighted
Beginner
45 Views

Dear All,

Steve: Thank you for your clarifications regarding the interpretation of the standard - and congratulations on your election as convenor of WG5!

Jim: Thank you, there are a number of workarounds that I could use, but that wasn't what I was asking for. I think that what you say about interpretations and conversions is not correct: boz-literal-constants such as z'80000000' are not interpreted standalone, they are only valid in a few situations specified by the standard, and their interpretation has to follow section 13.3.  According to the standard, there is no "interpretation as integer(kind=int32) and then conversion to integer(kind=int64)", there's a direct interpretation as integer(kind=int64) after the padding with zeroes described above has taken place.  If the compiler was doing a conversion from int32 to int64, that would not be in agreement with the standard and would be the source of the issue here reported.

Kind regards,

Highlighted
Valued Contributor II
45 Views

I was going to say that Quote #4 makes no sense, but it is kinda consistent with test programs for ifort 16.0. Consider:

```module M
use ISO_FORTRAN_ENV
implicit none
interface bitseq
module procedure bs1,bs2,bs4,bs8
end interface bitseq
contains
subroutine bs1(X)
implicit none
integer(INT8), intent(IN) :: X
write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X
end subroutine bs1
subroutine bs2(X)
implicit none
integer(INT16), intent(IN) :: X
write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X
end subroutine bs2
subroutine bs4(X)
implicit none
integer(INT32), intent(IN) :: X
write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X
end subroutine bs4
subroutine bs8(X)
implicit none
integer(INT64), intent(IN) :: X
write(*,'(3(g0),Z0)') 'KIND = ',KIND(X),', X = ',X
end subroutine bs8
end module M

program P
use M
implicit none
call bitseq(Z'80000000')
call bitseq(Z'080000000')
call bitseq(Z'0000000080000000')
end program P
```

The output with both 32- and 64-bit compilers is:

```KIND = 8, X = 80000000
KIND = 8, X = 80000000
KIND = 8, X = 80000000```

So that in an ordinary expression, the KIND is 8 in all 3 cases. However:

```program P
implicit none
integer, parameter :: K1 = KIND(Z'80000000')
integer, parameter :: K2 = KIND(Z'080000000')
integer, parameter :: K3 = KIND(Z'0000000080000000')
write(*,'(*(g0))') 'K1 = ',K1
write(*,'(*(g0))') 'K2 = ',K2
write(*,'(*(g0))') 'K3 = ',K3
end program P
```

Yields the output:

```K1 = 4
K2 = 8
K3 = 8```

Which is consistent with the prediction of @jimdempseyatthecove. Now we have to ask: is the fact that the BOZ constant is used in an initialization expression or a specification expression that triggers the bug? Let's try an example with only a specification function:

```module M
use ISO_FORTRAN_ENV
implicit none
interface bitseq
module procedure bs1,bs2,bs4,bs8
end interface bitseq
contains
pure function bs1(X)
implicit none
integer bs1
integer(INT8), intent(IN) :: X
bs1 = KIND(X)
end function bs1
pure function bs2(X)
implicit none
integer bs2
integer(INT16), intent(IN) :: X
bs2 = KIND(X)
end function bs2
pure function bs4(X)
implicit none
integer bs4
integer(INT32), intent(IN) :: X
bs4 = KIND(X)
end function bs4
pure function bs8(X)
implicit none
integer bs8
integer(INT64), intent(IN) :: X
bs8 = KIND(X)
end function bs8
pure function F1(X)
integer, intent(IN) :: X
integer F1(bitseq(Z'80000000'))
F1 = X
end function F1
pure function F2(X)
integer, intent(IN) :: X
integer F2(bitseq(Z'080000000'))
F2 = X
end function F2
pure function F3(X)
integer, intent(IN) :: X
integer F3(bitseq(Z'0000000080000000'))
F3 = X
end function F3
end module M

program P
use M
implicit none
write(*,'(*(g0))') 'SIZE(F1(0)) = ',SIZE(F1(0))
write(*,'(*(g0))') 'SIZE(F2(0)) = ',SIZE(F2(0))
write(*,'(*(g0))') 'SIZE(F3(0)) = ',SIZE(F3(0))
end program P
```

Output with ifort:

```SIZE(F1(0)) = 8
SIZE(F2(0)) = 8
SIZE(F3(0)) = 8```

So it's OK in just a specification expression. Curious that the bug requires such a specific trigger, and really has two components: one as a BOZ extension and one as standard BOZ usage.

Highlighted
Black Belt
45 Views

Steve,

Thanks, I should re-read docs re: INT:

If a is a binary, octal, or hexadecimal literal constant, the value of the result is the value whose bit sequence according to the model in Bit Model is the same as that of a as modified by padding or truncation according to the following:

If the length of the sequence of bits specified by a is less than the size in bits of a scalar variable of the same type and kind type parameter as the result, the binary, octal, or hexadecimal literal constant is treated as if it were extended to a length equal to the size in bits of the result by padding on the left with zero bits.

So it appears that in the case of an argument to INT, the (8-character) hex literal lost its hex-iness.

Here is an alternate test case to RO's:

```program TestHex
implicit none
if(Z'80000000' .gt. 0) then
print *, "gt 0"
else
print *, "lt 0"
endif
if(Z'80000000' .gt. 0_8) then
print *, "gt 0_8"
else
print *, "lt 0_8"
endif
if(int(Z'80000000',kind=8) .gt. 0) then
print *, "kind 8, gt 0"
else
print *, "kind 8, lt 0"
endif
end program TestHex

lt 0
gt 0_8
kind 8, gt 0```

This illustrates that the interpretation is correct (for the above code example, and V17u1).

I can see how this bug passed inspection.

Jim Dempsey

Highlighted
Black Belt
45 Views

V17 is ok

```program TestHex
implicit none
integer, parameter :: int64 = 8
integer(kind=int64) :: Vz,Vx
!76543210
Vz = int(z'80000000', kind=int64)
Vx = int(z'80000000', kind=int64) + 0_8
write(*,'(a, 24x,    a)') "Position", "76543210"
write(*,'(a,i18,1x,z16)') "Vz = ", Vz, Vz
write(*,'(a,i18,1x,z16)') "Vx = ", Vx, Vx
end program TestHex

Position                        76543210
Vz =         2147483648         80000000
Vx =         2147483648         80000000```

Jim Dempsey

Highlighted
Valued Contributor II
45 Views

I think you're missing what ifort is doing to assign the KIND of a BOZ literal in Quotes #8 and #9 above. In the first two cases of Quote #8, the BOZ literal, being one of the operands to a 2-operand operator, takes the KIND of the other operand, as per the ifort docs. In the last case of Quote #8 and in Quote #9, the standard usage of a BOZ literal is happening in the execution-part of the program, where ifort is doing the right thing. Put the same syntax in the specification-part of the program and I am pretty sure that it will fail, just as in Quote #1.

Highlighted
Black Belt Retired Employee
45 Views

jme wrote:

Steve: Thank you for your clarifications regarding the interpretation of the standard - and congratulations on your election as convenor of WG5

That hasn't actually happened yet, and it is very likely that there will be no "election" in that no other candidates have volunteered! My nomination still needs to be approved by the US SC22 Steering Committee and then confirmed by the ISO committees.  One might say I "didn't duck fast enough" when asked, but in truth it was an honor I was pleased to be able to accept.

Highlighted
Valued Contributor II
45 Views

Ooh, here's another test I wanted to try but I don't have recent enough ifort. What output does this produce on the most recent version of ifort?

```module M
use ISO_FORTRAN_ENV
implicit none
contains
subroutine bitseq(X)
class(*) X
select type(X)
type is(integer(int8))
write(*,'(*(g0))') 'KIND = ',KIND(X)
type is(integer(int16))
write(*,'(*(g0))') 'KIND = ',KIND(X)
type is(integer(int32))
write(*,'(*(g0))') 'KIND = ',KIND(X)
type is(integer(int64))
write(*,'(*(g0))') 'KIND = ',KIND(X)
end select
end subroutine bitseq
end module M

program P
use M
implicit none
class(*), allocatable :: X
X = Z'80000000'
call bitseq(X)
X = Z'080000000'
call bitseq(X)
end program P
```

Replacing X = Z'80000000' with allocate(X,source=Z'80000000') causes an access violation on the ALLOCATE statement in ifort 16.0.

Highlighted
Black Belt
45 Views

KIND = 8
KIND = 8

Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R
) 64, Version 18.0.0.083 Beta Build 20170510

Highlighted
Valued Contributor III
45 Views

jme wrote:

.. Jim: Thank you, there are a number of workarounds that I could use, but that wasn't what I was asking for. ..

@jme,

Please, pray tell which other workaround will you use?  Since the problem presented in the original post is within the context of a named constant, I thnk you are going to struggle coming up with even one other sensible workaround, let alone "a number of" them.

And since what is at stake is a compiler bug, it is largely meaningless what the standard says, especially in section 13.3, when it comes to developing workarounds.  Regardless of how the verbiage in the standard evolves, there is only ever an infinite array of bugs that separate a compiler implementation from the text and Jim's statement in Quote #4 appears closer to what may actually be going on in Intel Fortran implementation and his workaround seems to make best sense:

```program p

use, intrinsic :: iso_fortran_env, only : int64, compiler_version

implicit none

write (*,*) "Compiler Version: ", compiler_version()

blk1: block
!76543210
integer(kind=int64), parameter :: Pz = int(z'80000000', kind=int64)
write (*,*) "Block 1:"
write (*,'(a, 24x,    a)') "Position", "76543210"
write (*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz

end block blk1

blk2: block
!76543210
integer(kind=int64), parameter :: Pz = int(z'080000000', kind=int64)
write (*,*) "Block 2:"
write (*,'(a, 24x,    a)') "Position", "76543210"
write (*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz

end block blk2

blk3: block
!76543210
integer(kind=int64), parameter :: Pz = int(z'0000000080000000', kind=int64)
write (*,*) "Block 3:"
write (*,'(a, 24x,    a)') "Position", "76543210"
write (*,'(a,i18,1x,z16)') "Pz = ", Pz, Pz

end block blk3

stop

end program p
```

Upon execution,

``` Compiler Version:
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(

R) 64, Version 18.0.0.083 Beta Build 20170510

Block 1:
Position                        76543210
Pz =        -2147483648 FFFFFFFF80000000
Block 2:
Position                        76543210
Pz =         2147483648         80000000
Block 3:
Position                        76543210
Pz =         2147483648         80000000
```

If you have not done so, please follow up as suggested by Devorah in Quote #3 and report an incident at Intel's Online Service Center (OSC),, for only then is there some assurance Intel staff will follow up on the compiler bug.

Highlighted
Black Belt
45 Views

FWIW, in my 50 years of programming I've experienced too many compiler errors to count. Once discovered, life must go on. i.e. when code must get finished - produce a work around, don't wait for a fix. The trick is (one gets better the more the do this) to "divine" a probable cause, test the premise, and construct a work around. With fortuitous luck, the work around will be non-intrusive as well as have no impact on performance.

In this case, do not be too picky about adding an otherwise unnecessary 0 to the literal.

Also node, that a well constructed fix will work when the bug is removed from the compiler.

I think jme's post was simply a disclosure of a bug, and not a plea for a work around.

Jim Dempsey

Highlighted
Beginner
45 Views

Ticket submitted.

I was not completely sure that this was a bug, but I thought it might be one, and I was mostly seeking confirmation.

I had noticed that adding one or more zeros fixed the issue (at least for the binary and hex constants), like Jim did, and I think this is the most elegant workaround.  However, in the end this is about initialising an integer, so you could just compute its value manually (in this case, initialise to 2147483648_int64), or INT(<boz-literal-constant with bit #31 set to zero>, kind=int64) + 2_int64**31_int64, etc.

Highlighted
Moderator
45 Views

jme wrote:

Ticket submitted.

Thank you!