Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Bit inquiry intrinsic functions

david_______
Beginner
1,310 Views
Hi!

I am trying to convert a FORTRAN code that was written many years ago on a Univac computer (36-bit) that I am assuming was running FORTRAN IV or FORTRAN Vto FORTRAN 90 (32- and 64-bit). There are two intrinsic functions the code uses that I can not seem to replicate in FORTRAN 90 and am looking for a workaround, if possible.

1) The "FLD" function. The inputs are as follows,

fld(start, number, variable)

start = starting bit in floating point word
number = number of bits to use
variable = floating point value

FORTRAN90 intrinsic, IBITS is close but the variable must be an integer. My variable is a real, floating point value. This is very important. It must be a real, not integer input.

2) Logical AND function.

I need to logically AND two values together. The first is a real, floating point value and the second will be input as a binary or hexidecimal value. FORTRAN 90 has the IAND intrinsic but again, the inputs must be integer. I need it to accept non-integer inputs.

The algorithm I am trying to write was written for extreme speed.

Any help would be greatly appreciated.

Thank you very much for your time.

Sincerely,

David
0 Kudos
11 Replies
jimdempseyatthecove
Honored Contributor III
1,310 Views

David,

The old 36-bit floating point format is bit size, bit field, and may not have the assumed always 1 characteristics of the REAL(4) and REAL(8) floating point formats used on PCs. This being the case, even if there were an FLD function in IVF the bit positions and extents used in your old code on 36-bit data would not function properly with the same arguments when used on REAL(4) and/or REAL(8) values. And there may be Little-Endian vs, Big-Endian issues too.

That said, if you have 36-bit packed binary data files that you must read/convert, then it may be more suitable to write a C/C++ function to perform the translation.

Jim Dempsey

0 Kudos
david_______
Beginner
1,310 Views
Hi Jim!

Thank ou for your quick reply. In reading your response, I think I was a bit vague on what I was asking. Let me give you more information. I am not trying to read old data but instead am trying to replicate the algorithm that was used years ago. I totally understand what was done and am trying to replicate it using FORTRAN 90 and their instrinsic functions. The issue is not 36 versus 32 (or 64) bit word sizes or Little/Big Endian, its more of, are their equivalent intrinsics that will allow me to do was done in a previous version of FORTRAN. The algorithm takes a real value and performs a function on this value where the algorithm uses the FLD and AND intrinsics. I can set the algorithm up for 32 and 64 bit word sizes but need the functionality of these intrinsics for it to work.

Now, you also mentioned C/C++. Are there intrinsics in C/C++ that will do this? If so, is it possible to embed C/C++ code within FORTRAN code to do this? I do not want to call a subroutine as this will add too much time to an extrememly fast algorithm that I am desparatly trying to replicate.

Thanks again for your help. It is greatly appreciated.

Sincerely,

David
0 Kudos
Paul_Curtis
Valued Contributor I
1,310 Views
The post doesn't provide any information on out what the FLD and AND functions are supposed to do, but your chat indicates this might have been an attempt to speed up floating-point computations by directly fiddling the bit representation of a floating-point value. If so, have you considered intrinsics such as AINT() and ANINT(); these might offer similar functionality to what you're trying to do. If the AND of a REAL and a binary value serves some purpose then perhaps you could procure the characteristic and the mantissa separately as integers, do the operation using intrinsic bit functions, then recombine the results back into a REAL representation. And, of course, you could always EQUIVALENCE your float with an integer array, which would permit direct bit manipulations on the floating-point value.
0 Kudos
Steven_L_Intel1
Employee
1,310 Views
I suggest using the TRANSFER intrinsic to "cast" your REAL values as INTEGER for the purpose of the bit intrinsics. Please note that the 36-bit real format from the UNIVAC won't look anything like the IEEE real used by Intel processors.
0 Kudos
TimP
Honored Contributor III
1,310 Views
25 years ago, we laughed when we were presented with code which emulated a 36-bit machine (of which we still had examples) on a VAX.
It's difficult to imagine how performance could be enhanced by performing integer operations on sub-fields of floating point numbers. Compilers already did risky things automatically, like dividing or multiplying by 2 by integer arithmetic on the exponent field. A more likely reason for these bit field operations would be to pack multiple data into a 36-bit word, on account of the limited memory available on those machines, and lack of short integer data types.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,310 Views

Steve,

I am aware you are a strong proponent of using TRANSFER. However, to use a programmer's technical term, the documentation on TRANSFER really sucks. Or at least your statement that TRANSFER is similar to a "cast" operation. If you could provide some samples that clarify this it would be appreciated (then include the examples in the next go around for the documentation).

For example, I would like to "cast" a 3 diemensional array as a 1 dimensional array (note I do not wish for the "cast"to perform acopy)

If TRANSFER has any functionalitysimilar to "cast"I would be able to do something like

real,target :: A(nx, ny, nz)
AscalarValue = TRANSFER(A, ??, nx*ny*nz)(index)

Where ?? is something like (/0.0/) indicating real, nx*ny*nz indicates the size of the array, and (index) is a subscript of the RVALUE of the "cast" of the TRANSFER.

To me, a UNION or equivilance is much clearer.

Along the same subject

real,target, allocatable:: A(:,:,:)
real,pointer :: p_A(:)

How would one "cast" a one dimensionalpointer to all of A or part of A?

And while you are at it specify the base and extent for p_A?

I know I can coerce this by way of calling a subroutine with the starting cell within array A, then dimensioning the dummy in the subroutine approriatly then constructing the descriptor for use in => but this is a lot of hoop jumping for respecifying an array layout without having to perform a copy operation.

Any light you can shed on this would be greatly appreciated.

Jim Dempsey


0 Kudos
Steven_L_Intel1
Employee
1,310 Views
Perhaps cast is not the right word, though it comes close. TRANSFER looks like a function that returns a result that has the same "bits" as the source but with the type and shape you specify in the other arguments. It is an expression and in Fortran an expression cannot be indexed.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,310 Views

Steve,

>>Perhaps cast is not the right word, though it comes close. TRANSFER looks like a function that returns a result that has the same "bits" as the source but with the type and shape you specify in the other arguments. It is an expression and in Fortran an expression cannot be indexed.<<

Does TRANSFER (when remolding an array) produce an array descriptor?

i.e. can TRANSFER be used to generate an array descriptor for use on call to subroutine without performing a copy of the data to a temporary array?

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,310 Views
TRANSFER produces a value. A descriptor is created when you pass an array to a routine for which the explicit interface has the corresponding dummy as an assumed-shape array. A copy is never made in that circumstance.

I now realize that I left out an important aspect of TRANSFER. TRANSFER really does type conversion. While you can specify an array as MOLD, if you do the result is a one-dimensional array - the shape of the MOLD argument is ignored.

It might be that what you're looking for is RESHAPE to avoid making a source copy if your actual argument is a different shape than the corresponding dummy argument and the dummy is assumed shape. But RESHAPE will generally make a copy.

If the dummy is not assumed-shape, then you can pass the first element of the array and the rest of the array will be "sequence associated" with the dummy argument. For example:

integer a(10,5)

a = 0
print *, loc(a)
call sub(a(1,1))

contains

subroutine sub (a)
integer a(2,5,2)

print *, loc(a)
return
end subroutine sub
end

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,310 Views

Steve,

Thanks for your input on this.

I have been using CALL and dummy argument of different shape for years (decades) but I thought it would be nice if one could do the equivilent in-line with the code. A simple cast like operator would be nice.

The gen-interfaces/check-interfaces if strictly enforced would balk at the call reshaping.

Jim

0 Kudos
Steven_L_Intel1
Employee
1,310 Views
The form of the "call reshaping" I did is legal and standard-conforming. Interface checking would not complain. In fact, note that I used a contained procedure which is itself an explicit interface. You can use RESHAPE if the dummy argument is assumed-shape, but if it's explicit shape, simply passing the first element works fine.
0 Kudos
Reply