Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
This community is designed for sharing of public information. Please do not share Intel or third-party confidential information here.

UNSIGNED INTEGERS

carlls
Beginner
1,954 Views
Doing some C/FORTRAN interface code and have run across the unsigned data type in C.

A quick Google search says F95 ( at least sun's F95) implements a

unsigned (KIND=4) My_Int

with a definition of

My_Int=2u_4 (the u_4 implies unsigned kind=4)

I cannot seem to get this to work in Ifort 9.1

unsigned_int.f90(2) : Error: Syntax error, found '=' when expecting one of: .EQV
. .NEQV. .XOR. .OR. .AND. .LT. < .LE. <= .EQ. == .NE. /= .GT. > ...
UNSIGNED (KIND=4) MY_INT


Suggestions on how to robustly deal with the unsigned int data type?

Regards
Carl
0 Kudos
18 Replies
TimP
Black Belt
1,954 Views
Quoting - carlls

A quick Google search says F95 ( at least sun's F95) implements a

unsigned (KIND=4) My_Int

Suggestions on how to robustly deal with the unsigned int data type?

Turn on your search engine again, read some of the voluminous comments about the pros and cons, and go back to standard Fortran.
carlls
Beginner
1,954 Views
Quoting - tim18
Turn on your search engine again, read some of the voluminous comments about the pros and cons, and go back to standard Fortran.

Fine, what is the standard mapping from FORTRAN to an unsigned int in C?

I could not find it in either ifort 9 or 11's doc
jimdempseyatthecove
Black Belt
1,954 Views

Carl

Look in the IVF help under

operators | generic

The sample code shows a generic operator for logical arrays.

In your case you would make a user defined type for the unsigned int (make one for uchar, ushort, uint, ulong, ...) and then declare the operators for operatons performed on this type.

Jim Dempsey
Steven_L_Intel1
Employee
1,954 Views
There isn't one. Fortran does not have unsigned integers. In many cases, you can get away with INTEGER(C_INT), where C_INT is a constant defined in intrinsic module ISO_C_BINDING (10.0 and later), but don't try to do unsigned arithmetic with it directly. With some care, you can generally get what you need, but sometimes an unsigned conversion (ZEXT) to INTEGER(8) and then a truncation back to INTEGER(C_INT) will be needed.
carlls
Beginner
1,954 Views
There isn't one. Fortran does not have unsigned integers. In many cases, you can get away with INTEGER(C_INT), where C_INT is a constant defined in intrinsic module ISO_C_BINDING (10.0 and later), but don't try to do unsigned arithmetic with it directly. With some care, you can generally get what you need, but sometimes an unsigned conversion (ZEXT) to INTEGER(8) and then a truncation back to INTEGER(C_INT) will be needed.

Thanks Steve ... knowing there isn't a one to one mapping at least means I am doing "the best I can"
eos_pengwern
Beginner
1,954 Views
There isn't one. Fortran does not have unsigned integers. In many cases, you can get away with INTEGER(C_INT), where C_INT is a constant defined in intrinsic module ISO_C_BINDING (10.0 and later), but don't try to do unsigned arithmetic with it directly. With some care, you can generally get what you need, but sometimes an unsigned conversion (ZEXT) to INTEGER(8) and then a truncation back to INTEGER(C_INT) will be needed.

So I have a question related to this topic... the image-processing application I'm working on requires the data to be formatted as an array of C unsigned chars (i.e. 8-bit variables with values between 0 and 255). Currently, my Fortran application has no difficulty in generating a matrix of integers, each corresponding to one pixel and with a value in the required range. What I can't figure out is how to compress each of the Fortran integers (which occupy four bytes) down to a single byte while retaining the value. Each of the one-byte Fortran types (CHAR, INT(kind = 1) and BYTE) are geared to take values between -128 and +127, (OK, zero to 127 for CHAR), with behaviour undefined for assignments outside these ranges. According to Metcalf Read and Cohen, the kind type equivalent to C unsigned char provided by ISO_C_BINDING is "c_signed_char", which doesn't help much.

Note that I don't want to do any math with the unsigned integers, which is what Tim and Jim's advice seemed to be concerned with: I simply want to convert the data to the appropriate format and then send it on to another application. I could of course do so in C++ and have done with it, but I'd far rather keep it within my Fortran application (where parallellising the subsequent transposition with OpenMP is much more convenient) if possible.

So, what's the best way to accomplish this?
jimdempseyatthecove
Black Belt
1,954 Views

Assuming your FORTRAN array is using INTEGER, INTEGER(2), INTEGER(4), or INTEGER(8)
Assuming your array contains numbers in range of 0:255

Converson from larger integer to INTEGER(1) is relatively straitforward:

INTEGER :: in(n)
INTEGER(1) :: out(n)

do i=1,n
out(i) = INT1(in(i))
end do

Conversion back is not that much more difficult


INTEGER(1) :: in(n)
INTEGER :: out(n)

do i=1,n
out(i) = IAND(INT(in(i)),255)
end do

Jim Dempsey
eos_pengwern
Beginner
1,954 Views

Assuming your FORTRAN array is using INTEGER, INTEGER(2), INTEGER(4), or INTEGER(8)
Assuming your array contains numbers in range of 0:255

Converson from larger integer to INTEGER(1) is relatively straitforward:


Thanks Jim; that's just the sort of bitwise trick that I'd hoped there'd be!
IanH
Black Belt
1,954 Views
I'm curious about this, because when I thought about it I couldn't come up with a "robust" fortran only answer and gave up. I accept that something like out = INT(in, C_SIGNED_CHAR) works in practice with Intel Fortran (I think boring old "out = in" assignment does that implicitly anyway), but if "in" is in the range 128 to 255, (ie bigger than HUGE(1_C_SIGNED_CHAR) and hence "outside the range of values representable by objects of the specified type"), couldn't the resulting program technically (perhaps on a different platform or with a different compiler) run off and do nasty things?



TimP
Black Belt
1,954 Views
INT1(in) appears less portable than INT(in,1). I don't know if there may be Fortran compilers where a suitable type has non-unity kind. Simple assignment from a wider to a narrower kind would work as well.
IAND(in,z'ff') clearly produces a default integer, which must be positive for 128 <= in <= 255, where simple assignment would be expected to give negative sign extension, so Jim's advice appears to be the standard way to suppress sign extension in type widening.
ifort also supports the non-standard zext() intrinsics for this purpose, but I agree with Jim in recommending a portable alternative.
jimdempseyatthecove
Black Belt
1,954 Views

Ian,

In my reply I stated something to the effect "assuming that the larger integer numberic range was valid and in the range of 0:255" ...

If the Fortran larger integer violates this, then garbage in - garbage out. Actually you get the modulus 256 of the number.

Tim,

Yes, INT1(x) may be less portable than INT(x,1), and the user now seeing "oh I can do this" can tweek the code to use more portable language that does the same thing. You can also use an "uggly" union if you wish.

Jim Dempsey


jimdempseyatthecove
Black Belt
1,954 Views

Tim

For others not so observant, let's disect

out(i) = IAND(INT(in(i)),255)

where the 8-bit C-side unsigned char value is 0xFE (254)
but observed in Fortran as INTEGER(1) value of -2

INT(in(i)) produces 0xFFFFFFFE (-2)

IAND(0xFFFFFFFE, 255) produces 0x000000FE (254)

Jim Dempsey
Steven_L_Intel1
Employee
1,954 Views

The Intel compiler, as an extension, allows the use of values 128-255 for an INTEGER(1). You may want to look at IBITS as alternative tool.
eos_pengwern
Beginner
1,954 Views

The Intel compiler, as an extension, allows the use of values 128-255 for an INTEGER(1). You may want to look at IBITS as alternative tool.

There's the rub of course, that it's an extension. This non-standard aspect to the conversion is making me uncomfortable. I think I'm going to pass the array back to C++ as 32-bit integers, then let C++ do the casting to 8-bit uchars, then pass the (presumably much smaller) array back to Fortran to transpose. Fortran will see the incoming array as "c_signed_char"s, but this shouldn't make any difference as Fortran will never read the values, just transpose them and send them back.
Steven_L_Intel1
Employee
1,954 Views

You could do it this way:

INTEGER(1), PARAMETER :: X_FF = INT(Z'FF',1)

This is standard conforming, as best as I know, and you can then use X_FF instead of 255. -1 would work instead of Z'FF as well. There's no need to go to C just for this.
eos_pengwern
Beginner
1,954 Views

You could do it this way:

INTEGER(1), PARAMETER :: X_FF = INT(Z'FF',1)

This is standard conforming, as best as I know, and you can then use X_FF instead of 255. -1 would work instead of Z'FF as well. There's no need to go to C just for this.

I think I've found a good solution in the form of the TRANSFER function:

[cpp]! Convert an unsigned 8-bit integer, held in the 8 
! rightmost bits of 'i', into the 8 bits of 'c':
integer :: i
character(c_char) :: c, mold

c = transfer(i, mold)[/cpp]

This seems to fit the requirement of guaranteeing that all 8 bits of 'c' are set as determined by the value of 'i', while remaining standard-compliant.

Unless I've overlooked anything.
TimP
Black Belt
1,954 Views
Doesn't this have a totally different effect on big and little-endian CPUs? My references say this takes the "leading part" of i, not "rightmost bits." By "rightmost bits," in the context of the previous discussion, you mean the low order bits, which would be rightmost only in a big-endian representation, and would be leading bits only in a little-endian representation. It may be reasonable to assume little-endian on this forum, except that you use terminology which seems clearly to conflict with that assumption.
eos_pengwern
Beginner
1,954 Views
Quoting - tim18
Doesn't this have a totally different effect on big and little-endian CPUs? My references say this takes the "leading part" of i, not "rightmost bits." By "rightmost bits," in the context of the previous discussion, you mean the low order bits, which would be rightmost only in a big-endian representation, and would be leading bits only in a little-endian representation. It may be reasonable to assume little-endian on this forum, except that you use terminology which seems clearly to conflict with that assumption.

Yes, you're right, but having checked the standard (which indeed says "leading part"), it looks as though it would still do what's required - namely, deposit a bit pattern equivalent to an 8-bit unsigned integer into an 8-bit CHAR container. I was too specific in my use of the word "rightmost" in my program comment.
Reply