I am now considering the indication of constants as hex, oct or binary
constants. I have considered fortran, C, Java, IDL and (my)sql. I have a
question on the first three.
As a reference I started in Fortran with cases like these (I did also
byte, short and 64bit integers, not shown) :
integer j
j=somevalue
write(*,3)j,j,j,j
3 format(I11.10,1X,B32.32,1X,O11.11,1X,Z8.8)
real r
r=somevalue
write(*,4)r,r,r,r
4 format(G13.7 ,1X,B32.32,1X,O11.11,1X,Z8.8)
character*4 s
equivalence (j,s)
s=somestring
write(*,5)s,s,s,s
5 format(A4 ,1X,B32.32,1X,O11.11,1X,Z8.8)
I tried first with some explicit values (1, -1, 32767, 1.0, 2.0,
huge(0.0), tiny(0.0), "ABCD") and obtained perfectly meaningful binary,
oct and hex values. Then I replaced the assignment using bin, oct or hex
constants
j=z'7FFE' ! gives 32866
j=o'37777777776' ! give -2
j=b'11111111111111111111111111111110'
r=z'80800000' ! gives tiny
j=z'44434241' ! gives "ABCD"
Everything works perfectly. I can assign directly a binary
representation to an integer and to a real, and I can even assign it to
a string if this is in equivalence with an appropriate integer.
I then moved to C, I tried statements like
short i ;
i=somevalue;
printf("%6.5d %6.6o %4.4X %d \n",i,i,i,sizeof(i)) ;
int j ;
j=somevalue ;
printf("%11.10d %11.11o %8.8X %d \n",j,j,j,sizeof(j)) ;
float f ;
f=somevalue ;
printf("%13.7g %11.11o %8.8X %d \n",f,f,f,sizeof(f)) ;
Here I find two problems, a minor and a major one
The minor one is that a positive short is displayed OK
But a negative short is displayed with too many oct and hex digits
i=32767 ; /* 32767 077777 7FFF */
i=-1; /* -00001 37777777777 FFFFFFFF */
although a sizeof says that i is 2 bytes
The major problem is that an assignment to a float gives an
unexpected result (no compile or runtime error)
f=0X40800000; /* should return 4.0 */
f=0X80800000; /* should return tiny */
For instance the latter returns 2.155872e+09, the former 2.155872e+09
and BOTH THE SAME 00000000000 as octal and 41E01000 as hex (different
from the one I assigned)
In Java I tried
int i ;
System.out.format("i is: %11d %11o %8x %n", i,i,i);
float f ;
System.out.format("f is: %e %n", f );
Here format does not support the o and x descriptors for float argument.
Anyhow I tested assignments for integer and they do work
i=037777777776 ; /* -2 */
i=0X7FFE ; /* 32766 */
while assignment for real do not work (as in C)
f=0X3F800000; /* should be 1.0 */
f=0X40800000; /* should be 4.0 */
f=0X80800000; /* should by tiny */
(the compiler does not complain, there are no runtime exceptions, but
the result is not what expected
for instance the latter returns -2.139095e+09 and the one for 4.0
returns 1.082130e+09
I haven't tested assignment of hex or oct constants to strings in
neither of the two latter languages (I guess Java will be using unicode,
not plain ascii)
--
----------------------------------------------------------------------
nos...@mi.iasf.cnr.it is a newsreading account used by more persons to
avoid unwanted spam. Any mail returning to this address will be rejected.
Users can disclose their e-mail address in the article if they wish so.
> Then I replaced the assignment using bin, oct or hex constants
>
> j=z'7FFE' ! gives 32866
> j=o'37777777776' ! give -2
> j=b'11111111111111111111111111111110'
> r=z'80800000' ! gives tiny
> j=z'44434241' ! gives "ABCD"
>
> Everything works perfectly.
None of these are standard Fortran. The fact that some particular
compiler might happen to accept them is another matter; they are not
Fortran. In fact, because these violate a constraint (C410 in F2003 or
an even more stringent one in f95), the compiler is required to be able
to diagnose their usage. Have you tried the compiler switch to warn
about nonstandard forms? If you did so and the compiler failed to give
you a message about these, then the compiler violates the standard.
> I can assign directly a binary
> representation to an integer and to a real,
The ones assigning directly to a real are particularly nonportable. Even
among compilers that accept the nonstandard syntax, you will find
differences in interpretation of this. Indeed, the most "natural"
extension of the standard would not give the result you expect.
> and I can even assign it to
> a string if this is in equivalence with an appropriate integer.
Such an equivalence is also nonstandard.
It appears that you are not actually comparing the Fortran language to
other languges, but instead comparing a particular Fortran compiler.
That's not the same thing.
--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
The '%o" and "%X" format specifiers require an unsigned int argument,
'i' doesn't qualify. The "%d" format specifier require an int. This is
OK for the first "%d", because 'i' is automatically promoted to an
'int'. It is not OK for the final %d, because sizeof expressions have
a value of type size_t, which is not only unsigned, but on many
platforms is larger than an int.
> int j ;
> j=somevalue ;
> printf("%11.10d %11.11o %8.8X %d \n",j,j,j,sizeof(j)) ;
Exactly the same issues apply here.
> float f ;
> f=somevalue ;
> printf("%13.7g %11.11o %8.8X %d \n",f,f,f,sizeof(f)) ;
The problems with the "%o" and "%X" format specifiers in this case are
technically exactly the same as in the previous two cases. However,
while there are many systems where they will work as you might expect
them to with a signed int value, there's very few, if any, systems
where they'll work with floating point values.
> Here I find two problems, a minor and a major one
>
> The minor one is that a positive short is displayed OK
> But a negative short is displayed with too many oct and hex digits
> i=32767 ; /* 32767 077777 7FFF */
> i=-1; /* -00001 37777777777 FFFFFFFF */
>
> although a sizeof says that i is 2 bytes
'i' is promoted to an int before being passed to printf(), and you
printed it using a format specifier for an unsigned int. Why do you
think that sizeof(short) has anything to do with the result that you
get?
> The major problem is that an assignment to a float gives an
> unexpected result (no compile or runtime error)
No, the major problem is that you expected any particular result. The
standard does not provide any support for any such expectations. If
printf() had decided to print out "You have no idea what you're
doing.", it would have been both fully conforming and fairly accurate.
> f=0X40800000; /* should return 4.0 */
0x40800000 is a hex constant with a value of 1082130432. Assigning it
to a float object causes it to be converted to one of the two values
representable as a float that are closest to 1082130432.0, which will
usually be1082130432.0 itself, except in the unlikely (but legal) case
where FLT_RADIX is something other than a small power of 2 . Why would
expect the result to be 4.0?
> f=0X80800000; /* should return tiny */
I don't believe that a value of 2155872256.0 counts as tiny, though
astronomers might disagree.
> For instance the latter returns 2.155872e+09, the former 2.155872e+09
> and BOTH THE SAME 00000000000 as octal and 41E01000 as hex (different
> from the one I assigned)
Well, when you ask printf() to print an unsigned integer, and you give
it a floating point value instead, you really can have no justified
grounds for complaint, regardless of what it prints.
> j=z'7FFE' ! gives 32866
> j=o'37777777776' ! give -2
> j=b'11111111111111111111111111111110'
> r=z'80800000' ! gives tiny
> j=z'44434241' ! gives "ABCD"
A problem here is that the above isn't legal Fortran, not even F08. The
key ambiguity lies in the assignment:
r = z'80800000'
which is supposed to yield -tiny(0.0). It is controversial what a
compiler should do here: should it interpret z'80800000' as a
Hollerith constant and assign as if via TRANSFER (with result -tiny(0.0))
or should it be treated as an integer constant, thus -2139095040?
F08 allows different conpilers to interpret this differently, even
when couched as a DATA statement by disallowing the assignment form
entirely and only permitting the DATA statement form when the
corresponding data-stmt-object is of type integer. The result is that
compilers can accept their traditional form as an extension and users
of a given compiler don't have to change their hoary code because the
compiler wasn't required to changed its behavior by the standard.
F08 does have a form where the programmer is required to specify
which interpretation he wants:
r = INT(z'80800000') ! r = -2139095040
r = REAL(z'80800000') ! r = -tiny(0.0)
> I then moved to C, I tried statements like
> short i ;
> i=somevalue;
> printf("%6.5d %6.6o %4.4X %d \n",i,i,i,sizeof(i)) ;
> int j ;
> j=somevalue ;
> printf("%11.10d %11.11o %8.8X %d \n",j,j,j,sizeof(j)) ;
> float f ;
> f=somevalue ;
> printf("%13.7g %11.11o %8.8X %d \n",f,f,f,sizeof(f)) ;
> Here I find two problems, a minor and a major one
> The minor one is that a positive short is displayed OK
> But a negative short is displayed with too many oct and hex digits
> i=32767 ; /* 32767 077777 7FFF */
> i=-1; /* -00001 37777777777 FFFFFFFF */
> although a sizeof says that i is 2 bytes
In the above, i was printed with the %o format. The mechanism for
passing i to printf means that there is no way for the printf
function to distinguish it from an int, so the calling program
has to convert to type int via sign extension (so that it could
print (short)(-1) as -1 with a %d format) and printf doesn't know
that it started life as a short so you get what you get. If you
don't like it, you can always change the format to "%6.6ho".
> The major problem is that an assignment to a float gives an unexpected
> result (no compile or runtime error)
> f=0X40800000; /* should return 4.0 */
> f=0X80800000; /* should return tiny */
> For instance the latter returns 2.155872e+09, the former 2.155872e+09 and
> BOTH THE SAME 00000000000 as octal and 41E01000 as hex (different from the
> one I assigned)
C defines hex constants as being unsigned ints, maybe unsigned long ints,
I'm not clear on the fine points, but you should definitely get the big
numbers you are getting. I haven't thought about the octal and hex
outputs you report above. That's a different problem.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
> for instance the latter returns -2.139095e+09 and the one for 4.0
> returns 1.082130e+09
Huh. Mine seems fine. What hardware do you run on and what Java
compiler do you use? SSCCE?
<code>
/** Java float test */
public class FloatTest {
public static void main(String[] args) {
float f = 1.0f;
int fi = Float.floatToRawIntBits(f);
f = Float.intBitsToFloat( 0x3f800000 );
System.out.printf("%x\n", fi );
System.out.printf("%g\n", f );
}
}
</code>
<output>
run:
3f800000
1.00000
BUILD SUCCESSFUL (total time: 0 seconds)
</output>
I believe this is right, though I am not so srue about the
part after the decimal point.
< real r
< r=somevalue
< write(*,4)r,r,r,r
< 4 format(G13.7 ,1X,B32.32,1X,O11.11,1X,Z8.8)
This is non-standard, and likely won't work with some systems.
As default real and default integer are supposed to be the same
size, it should work with TRANSFER (and likely also with
EQUIVALENCE).
< character*4 s
< equivalence (j,s)
< s=somestring
< write(*,5)s,s,s,s
< 5 format(A4 ,1X,B32.32,1X,O11.11,1X,Z8.8)
Even less likely to work than REAL. Again TRANSFER is
a good solution. Though there is no guarantee that a default
integer is four characters long.
< I tried first with some explicit values (1, -1, 32767, 1.0, 2.0,
< huge(0.0), tiny(0.0), "ABCD") and obtained perfectly meaningful binary,
< oct and hex values. Then I replaced the assignment using bin, oct or hex
< constants
< j=z'7FFE' ! gives 32866
< j=o'37777777776' ! give -2
< j=b'11111111111111111111111111111110'
< r=z'80800000' ! gives tiny
< j=z'44434241' ! gives "ABCD"
< Everything works perfectly. I can assign directly a binary
< representation to an integer and to a real, and I can even assign it to
< a string if this is in equivalence with an appropriate integer.
That seems likely not to work on many systems. Fortran 2003 suggest
that the REAL function should work in the REAL case. I suppose
TRANSFER for the string case.
< I then moved to C, I tried statements like
< short i ;
< i=somevalue;
< printf("%6.5d %6.6o %4.4X %d \n",i,i,i,sizeof(i)) ;
< int j ;
< j=somevalue ;
< printf("%11.10d %11.11o %8.8X %d \n",j,j,j,sizeof(j)) ;
< float f ;
< f=somevalue ;
< printf("%13.7g %11.11o %8.8X %d \n",f,f,f,sizeof(f)) ;
< Here I find two problems, a minor and a major one
< The minor one is that a positive short is displayed OK
< But a negative short is displayed with too many oct and hex digits
< i=32767 ; /* 32767 077777 7FFF */
< i=-1; /* -00001 37777777777 FFFFFFFF */
You can't printf short values. They are converted to int before
they are passed to printf. Bitwise AND (&) with the appropriate
constant, such as 0xffff first.
< although a sizeof says that i is 2 bytes
< The major problem is that an assignment to a float gives an
< unexpected result (no compile or runtime error)
< f=0X40800000; /* should return 4.0 */
< f=0X80800000; /* should return tiny */
The hex constant is just an ordinary unsigned int and is converted
as usual. The usual way to do this, though non standard, is with
the use of pointers.
< For instance the latter returns 2.155872e+09, the former 2.155872e+09
< and BOTH THE SAME 00000000000 as octal and 41E01000 as hex (different
< from the one I assigned)
< In Java I tried
< int i ;
< System.out.format("i is: %11d %11o %8x %n", i,i,i);
< float f ;
< System.out.format("f is: %e %n", f );
Look at the FloatToIntBits and IntToFloatBits functions.
(I might have the names slightly wrong.) Also you might
like the DoubleToLongBits and LongToDoubleBits functions.
(oops, static methods.)
< Here format does not support the o and x descriptors for float argument.
< Anyhow I tested assignments for integer and they do work
< i=037777777776 ; /* -2 */
< i=0X7FFE ; /* 32766 */
< while assignment for real do not work (as in C)
< f=0X3F800000; /* should be 1.0 */
< f=0X40800000; /* should be 4.0 */
< f=0X80800000; /* should by tiny */
< (the compiler does not complain, there are no runtime exceptions, but
< the result is not what expected
Why is the result not expected? You are assigning an integer
constant to a float variable. Though as Java requires IEEE
floating point and supplies the conversion functions it should
work if done right.
< for instance the latter returns -2.139095e+09 and the one for 4.0
< returns 1.082130e+09
< I haven't tested assignment of hex or oct constants to strings in
< neither of the two latter languages (I guess Java will be using unicode,
< not plain ascii)
-- glen
> I am collecting a sort of phrase books with equivalent "things" in
> various languages.
<snip>
> The major problem is that an assignment to a float gives an unexpected
> result (no compile or runtime error)
>
> f=0X40800000; /* should return 4.0 */
> f=0X80800000; /* should return tiny */
You've had this explained, so I will just add that C99 does allow you
to specify a floating point constant in hexadecimal. They look like
this:
float x = 0x3.f8p-2f;
The exponent is decimal -- the trailing f simply marks this as a float
(rather than a double) and is not a digit in the exponent. All of the
letters that are used in these constants can be in either case.
<snip>
--
Ben.
The OP didn't use Float.intBitsToFloat(), but directly assigned the
int value to the float. Naturally that invoked the usual int-to-float
conversion, which was not what the OP wanted, but it is what the Java
language promises to do.
--
Lew
Ah, ok. "Pilot error."
It is also what some Fortran compilers are likely to do with the OP's
original nonstandard "Fortran" code. There appears to be an element of
commonality across the languages here. I'd say that the most significant
element of commonality is the unsupported nature of the OP's
expectations.
Actually, according to the JLS, this is very much expected. The
hexadecimal literals are, of course, integers, and assigning an integer
to a float converts the integer into the closest representation in the
float value set.
> I haven't tested assignment of hex or oct constants to strings in
> neither of the two latter languages (I guess Java will be using unicode,
> not plain ascii)
In Java, the conversion of constants would be via StringBuffer's
toString(int) method, which would just print out the number in nominal
decimal format. Strings are internally stored in Java as UTF-16, but
conversion to bytes is often handled as UTF-8 or the platform default
encoding, which is almost always backwards-compatible with ASCII (I
think pretty much everything but multiple-bit fixed-width encodings and
EBCDIC).
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
>while assignment for real do not work (as in C)
>
> f=0X3F800000; /* should be 1.0 */
Why SHOULD it work the same as C?
For heaven's sake read up on the syntax rather than trying to guess
it.
See http://mindprod.com/jgloss/literal.html
http://mindprod.com/jgloss/cast.html
http://mindprod.com/jgloss/floatingpoint.html especially
longBitsToDouble
--
Roedy Green Canadian Mind Products
http://mindprod.com
If everyone lived the way people do in Vancouver, we would need three more entire planets to support us.
~ Guy Dauncey
Keep in mind that LC's expected results for C are just as incorrect as
they are for java. Does the above code not work essentially the same
as in C? I'm no Java expert, but I thought that this was an area where
java is consistent with C.
<> > f=0X3F800000; /* should be 1.0 */
<>
<> Why SHOULD it work the same as C?
>
< Keep in mind that LC's expected results for C are just as incorrect as
< they are for java. Does the above code not work essentially the same
< as in C? I'm no Java expert, but I thought that this was an area where
< java is consistent with C.
As integer constants, yes, the results will be pretty much
the same in Java and C. As Java doesn't have the unsigned types
that C has, there might be some sign related effect.
Java has the conversion functions that allow one to copy bit
patterns into floating point variables. In C you can do it
using pointers to unsigned char, if you know the length.
Java requires IEEE floating point, in C you get whatever floating
point is used on your system, possibly with an unusual endianness.
(Especially VAX where integers are little endian, and floating
point is not big or little endian.)
-- glen
Because the language was designed to share the same syntax
as C for such things?
> For heaven's sake read up on the syntax rather than trying to guess
> it.
And what have you done about the syntax of C? It appears that you've
ascribed meaning to, and thence trusted, three of the words in a post
by someone who was demonstrably entirely ignorant about the subject
matter he was addressing. A foolish move.
Phil
--
Marijuana is indeed a dangerous drug.
It causes governments to wage war against their own people.
-- Dave Seaman (sci.math, 19 Mar 2009)
> I am now considering the indication of constants as hex, oct or binary
> constants. I have considered fortran, C, Java, IDL and (my)sql. I have a
> question on the first three.
[examples snipped]
Thanks to everybody for the replies, which I can summarize as follows (I
will reply separately on specific questions).
- some of the features I used are non-standard
- in some languages a format specification (or edit
descriptor,whatever you call it) implies
or requires a particular data type (and may cause an implicit
conversion). In particular in C "'%o' and "%X' format specifiers
require an unsigned int"
- in some languages (or all ? definitely C and Java) hex or oct
constants are integer. There may be means to store an hex constant
into a float like Float.intBitsToFloat in Java
- it is not obvious to find the relevant information in the
documentation :-(
> On Mon, 15 Jun 2009, LC's No-Spam Newsreading account wrote:
>
>> I am now considering the indication of constants as hex, oct or
>> binary constants. I have considered fortran, C, Java, IDL and
>> (my)sql. I have a question on the first three.
>
> [examples snipped]
>
> Thanks to everybody for the replies, which I can summarize as follows
> (I will reply separately on specific questions).
>
> - some of the features I used are non-standard
> - in some languages a format specification (or edit
> descriptor,whatever you call it) implies
> or requires a particular data type (and may cause an implicit
> conversion). In particular in C "'%o' and "%X' format specifiers
> require an unsigned int"
> - in some languages (or all ? definitely C and Java) hex or oct
> constants are integer. There may be means to store an hex constant
> into a float like Float.intBitsToFloat in Java
- C has hex floating point constants.
>
> - it is not obvious to find the relevant information in the
> documentation :-(
What is "the documenation"? What I mean is you may simply be looking
in the wrong place.
--
Ben.
>> j=z'7FFE' ! gives 32866
>> r=z'80800000' ! gives tiny
>> j=z'44434241' ! gives "ABCD"
> None of these are standard Fortran.
I must say I never used hex/oct/bin constants (hex for short in the
remainder of this post) in the past because they weren't standard. If I
needed to force a particular binary representation I used bit
manipulation (let's say that since at least 10 years with the demises of
the Vaxes, one can reasonably assume, but for the endianness,
2-complement integers and IEEE floating points).
But reading Metcalf, Reid and Cohen (Fortran 95/2003 explained) I got
the impression they were standardized NOW.
What is exactly non standard in my usage ?
- usage of hex constants in assignments instead of DATA ?
- usage of hex constants for non-integers ?
- usage of hex edit descriptor for non-integers ?
> Have you tried the compiler switch to warn about nonstandard forms? If
> you did so and the compiler failed to give you a message about these,
> then the compiler violates the standard.
It does (so far testing with ifort).
> The ones assigning directly to a real are particularly nonportable.
> Even among compilers that accept the nonstandard syntax, you will find
> differences in interpretation of this.
OK. Point taken.
I'd better revert to my old usages and consider hex constants as
something to avoid.
> It appears that you are not actually comparing the Fortran language to
> other languges, but instead comparing a particular Fortran compiler.
Well, unless one has access to The Standard Itself, the only way one can
gain experience is testing with specific compilers, and with the ones
one has at hand. In the past (with f77) I developed an idea of "the
common and reasonable extensions to the standard" working with HP, IBM,
VAX, Sun, DEC Alpha ... but that because I got exposed to such hardware
and OS. Nowadays our environment is essentially a Linux/Intel one.
> The '%o" and "%X" format specifiers require an unsigned int argument,
I thought they were "universal" like O and Z in Fortran.
>> i=32767 ; /* 32767 077777 7FFF */
>> i=-1; /* -00001 37777777777 FFFFFFFF */
>> although a sizeof says that i is 2 bytes
>
> 'i' is promoted to an int before being passed to printf(), and you
I wasn't aware of this. See above.
> printed it using a format specifier for an unsigned int. Why do you
> think that sizeof(short) has anything to do with the result that you
> get?
Expecting an universal edit descriptor, I expected that a 2-byte
quantity resulted in 4 hex digits.
>> f=0X40800000; /* should return 4.0 */
> Why would expect the result to be 4.0?
because that's the internal representation of the float 4.0 in IEEE
(just re-checked with my old Excel spreadsheet which gives the internal
representation of IEEE and VAX floats). I assumed that an "hex constant"
was just a bit pattern, with no type implied.
I realize now that, at least in C, hex constants are integer constants
(is this implicit or documented ?)
Correct so far.
> ... (and may cause an implicit
> conversion). ...
Incorrect, at least with regard to printf() in C. The implicit
conversions we told you about are the default argument promotions that
occur as the result of passing an unprototyped argument to a function,
they have no direct connection to the format specifiers. While there is
a prototype in <stdio.h> for printf(), only the first two arguments have
explicit types - the remaining objects are subject to only the default
argument promotions. Note, in particular, that the implicit conversion
may result is a type different from that specified by the corresponding
format specifier: that's what causes the problems.
> ... In particular in C "'%o' and "%X' format specifiers
> require an unsigned int"
> - in some languages (or all ? definitely C and Java) hex or oct
> constants are integer. There may be means to store an hex constant
> into a float like Float.intBitsToFloat in Java
>
> - it is not obvious to find the relevant information in the
> documentation :-(
I can't address the quality of the documentation for whichever
implementation of the C standard library that you're using. However, the
C standard itself says this pretty clearly: "If any argument is not the
correct type for the corresponding conversion specification, the
behavior is undefined." (7.19.6.1p9), and the documentation for each
conversion specification identifies what the "correct type" is.
Any decent elementary C text should tell you that initializing an object
with a expression causes the expression's value to be converted to the
object's type and stored in the object. I can't really figure out why
you expected different behavior, but I doubt that it's the fault of your
text.
>Expecting an universal edit descriptor, I expected that a 2-byte
>quantity resulted in 4 hex digits.
Not if you tell it explicitly you want 8...
> Even less likely to work than REAL. Again TRANSFER is a good
> solution. Though there is no guarantee that a default integer is four
> characters long.
It is in practice in my case, and in all the environments I can
realistically work. No longer the time of 36-bit machines ...
> < In Java I tried
> Look at the FloatToIntBits and IntToFloatBits functions.
f = Float.intBitsToFloat( 0x3f800000 );
as another poster suggested. Thanks to both !
> Why is the result not expected? You are assigning an integer
> constant to a float variable.
Well, my reference for Java is the tutorial on the java.sun.com site and
I've never found a CLEAR statement that an hex pattern is necessarily
typed as an integer. I assumed it to be an arbitrary bit pattern, which
could be reversed into any type of variable.
>> f=0X40800000; /* should return 4.0 */
>> f=0X80800000; /* should return tiny */
> float x = 0x3.f8p-2f;
I tried to play with this form, e.g.
f=0X1.ap0f; /* 1.625 */
f=0X1.ap1f; /* 3.25 */
f=0X1.ap-1f; /* 0.8125 */
But it is not obvious to me what the two parts are ... mantissa in hex
and exponent as power of 2 in decimal ... but are they the same that
constitute exactly the IEEE representation or can be scaled arbitrarily ?
> For heaven's sake read up on the syntax rather than trying to guess
> it.
I've bookmarked your links, but I did read what available in the
java.sun.com tutorial and the API documentation (well, to find something
in the API documentation you have to know what to look already).
As said in other posts, my (wrong) assumption was that an hex "string"
like 0X40800000 would be just an arbitrary bit pattern which can be
transferred into any variable type, not an integer constant. I've never
encountered explicitly such definition. NOW I know.
>> float f ;
>> f=somevalue ;
>> printf("%13.7g %11.11o %8.8X %d \n",f,f,f,sizeof(f)) ;
>
> The problems with the "%o" and "%X" format specifiers in this case are
> technically exactly the same as in the previous two cases. However,
Hmm... what's then the "standard" way to obtain an hex dump of a float
(in the way the Z format will do in Fortran), other than writing it to a
binary file and using od :-) ?
I tried the above using one of the following instead of "somevalue"
(with gcc)
f=1.0f ; /* gives 3FF00000 instead of 3F800000 */
f=2.0f ; /* gives 40000000 */
f=4.0f ; /* gives 40800000 instead of 40100000 */
f=8.0f ; /* gives 41000000 instead of 40200000 */
C FORTRAN
For 2.0 I obtain the same binary representation I obtain in Fortran, for
the other values (note all powers of 2) I obtain discrepant values. 'm
pretty sure (checked with my old Excel spreadsheet doing the bit-by-bit
display of a real in IEEE and VAX form) the Fortran value is the correct
one (IEEE).
Is this a side effect of some signed vs unsigned thing ?
I'd do something like this (warning, been too long since C for me):
union float_int {
float f;
int i;
} x;
x.f = 1.0f;
printf( "%08.8X", x.i );
> On Mon, 15 Jun 2009, Ben Bacarisse wrote:
>> LC's No-Spam Newsreading account <nos...@mi.iasf.cnr.it> writes:
>>
>
>>> f=0X40800000; /* should return 4.0 */
>>> f=0X80800000; /* should return tiny */
>
>> float x = 0x3.f8p-2f;
>
> I tried to play with this form, e.g.
>
> f=0X1.ap0f; /* 1.625 */
> f=0X1.ap1f; /* 3.25 */
> f=0X1.ap-1f; /* 0.8125 */
>
> But it is not obvious to me what the two parts are ... mantissa in hex
> and exponent as power of 2 in decimal ... but are they the same that
> constitute exactly the IEEE representation or can be scaled
> arbitrarily ?
The bit before the p just gives the value as a hexadecimal fraction;
the bit after the p gives the exponent. This is much more useful than
tying the notation to one specific representation of floating point
numbers. Here are your example numbers in binary rather than hex:
1.101 = 1+1/2+1/8 = 1.625
11.01 = 2+1+1/4 = 3.25
0.1101 = 1/2+1/4+1/16 = 0.8125
--
Ben.
> Well, my reference for Java is the tutorial on the java.sun.com site and
> I've never found a CLEAR statement that an hex pattern is necessarily
> typed as an integer. I assumed it to be an arbitrary bit pattern, which
> could be reversed into any type of variable.
You need a few more references. The tutorial is just that, a tutorial.
It doesn't cover everything. However it's not hard to type "Java
integer hex" into Google and get some additional tutorials, some of
which do talk about hex literal constants.
The ultimate source is the JLS:
<http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.1>
Scroll down about one page to where it says "HexNumeral" which is where
you can see that the "0x" format is for integers.
Floating point hex numbers are available too. Scroll down a bit more to
the section on floating point literals. (The important difference
between hex integers and hex floats is that hex floats have a decimal
point: 0xAA.55)
But those hex floats are still *NUMBERS*, not *BIT PATTERNS*. Use the
Float methods intToFloatBits and floatToIntBits to access floats as bit
patterns.
> On Mon, 15 Jun 2009, jameskuyper wrote:
>
>>> float f ;
>>> f=somevalue ;
>>> printf("%13.7g %11.11o %8.8X %d \n",f,f,f,sizeof(f)) ;
>>
>> The problems with the "%o" and "%X" format specifiers in this case are
>> technically exactly the same as in the previous two cases. However,
>
> Hmm... what's then the "standard" way to obtain an hex dump of a float
> (in the way the Z format will do in Fortran), other than writing it to
> a binary file and using od :-) ?
for (int b = 0; i < sizeof(float); i++)
printf("%02x", ((unsigned char *)&f)[i]);
but there is no shorthand for this because it is not needed much. Any
actual dump of the representation will have to interpreted depending
on the internal format being used.
People want hex output in order to find out exactly what value is in a
float without worrying about the effect of conversion to decimal. C
can do this more useful operation directly using the format %a (or %A).
Of course, if the machine uses decimal floating point, %f, %e and %g
give you the exact values and %a will make matters worse.
> I tried the above using one of the following instead of "somevalue"
> (with gcc)
>
> f=1.0f ; /* gives 3FF00000 instead of 3F800000 */
> f=2.0f ; /* gives 40000000 */
> f=4.0f ; /* gives 40800000 instead of 40100000 */
> f=8.0f ; /* gives 41000000 instead of 40200000 */
> C FORTRAN
>
> For 2.0 I obtain the same binary representation I obtain in Fortran,
> for the other values (note all powers of 2) I obtain discrepant
> values. 'm pretty sure (checked with my old Excel spreadsheet doing
> the bit-by-bit
> display of a real in IEEE and VAX form) the Fortran value is the
> correct one (IEEE).
>
> Is this a side effect of some signed vs unsigned thing ?
Output from a program that "breaks the rules" is unreliable. Your
code has undefined behaviour. One might speculate on what comes out,
but you'd be better off avoiding undefined behaviour.
--
Ben.
> - There may be means to store an hex constant
> into a float like Float.intBitsToFloat in Java
>
For Java, these MUST be present. It's required, at least for Java SE
(as opposed to Java ME, which I think is still back on the 1.0 API).
> - it is not obvious to find the relevant information in the
> documentation :-(
>
Google key words, click on and read each page linked on the first
results page. This usually works for me, and did for "java tutorial hex."
The union keyword for C is a bit trickier to find. However, making a
union of float and int is usually the first elementary example presented
when talking about union, so if you had read your text you would have
seen it. So the answer here is to read ALL the documentation, not just
some of it. And for C I think a book like Kerrigan and Ritchie is a
rather short read, not hard at all.
I tried this
#include <stdio.h>
void dump_val (unsigned char *p, size_t n)
{
size_t i;
for (i = 0; i < n; i++)
printf ("%.02x ", p[i] & 0xff);
printf ("\n");
}
void dump_double (double x)
{
unsigned char *p;
p = (unsigned char*)&x;
printf ("representation of %f is ", x);
dump_val (p, sizeof(x));}
int main (void)
{
dump_double (1.0);
dump_double (2.0);
dump_double (4.0);
dump_double (8.0);
return 0;
}
and got
representation of 1.000000 is 00 00 00 00 00 00 f0 3f
representation of 2.000000 is 00 00 00 00 00 00 00 40
representation of 4.000000 is 00 00 00 00 00 00 10 40
representation of 8.000000 is 00 00 00 00 00 00 20 40
are you sure about 1.0?
[note: an earlier version of this program posted here
just repeatedly printed the first byte]
--
Nick Keighley
and if a float won't fit in an int?
Did the documentation for those specifiers give you any justification
for such thinking? It should say something like the following: "The
unsigned int argument is converted to unsigned octal (o), unsigned
decimal (u), or unsigned hexadecimal notation (x or X)... "
(7.19.6.1p8). Note, in particular, that if the argument is not an
unsigned int, this description is meaningless, which is a strong hint
that the argument has to be an unsigned int.
...
>> 'i' is promoted to an int before being passed to printf(), and you
>
> I wasn't aware of this. See above.
>
>> printed it using a format specifier for an unsigned int. Why do you
>> think that sizeof(short) has anything to do with the result that you
>> get?
>
> Expecting an universal edit descriptor, I expected that a 2-byte
> quantity resulted in 4 hex digits.
I recommend learning a lot more about C, and in particular being more
careful to read the available documentation or textbooks, before forming
any more expectations about what C code will do. You're misinterpreting
some very elementary issues.
>>> f=0X40800000; /* should return 4.0 */
>
>> Why would expect the result to be 4.0?
>
> because that's the internal representation of the float 4.0 in IEEE
> (just re-checked with my old Excel spreadsheet which gives the internal
> representation of IEEE and VAX floats). ...
But did anyone tell you anything to suggest that the assignment operator
had any effect other than setting the left operand to represent as
closely as possible the save value as the right operand? In particular,
did anyone ever suggest to you that the assignment operator would set
the representation of the left operand, rather than the value it
represents, to match the right operand?
> ... I assumed that an "hex constant"
> was just a bit pattern, with no type implied.
No, a hex constant is just one of many different ways of writing an
integer constant. In C, an integer constant of 127 can be written as
127, 0x3F, 0177, '\x3f', or '\0177'. Any of the first three can be
followed by 'u', indicating unsigned, or by 'l', indicating a long int.
All of the letters given above (x, u, l, and the hex digits a, b, c, d,
e, and f) can be either upper or lower case.
> I realize now that, at least in C, hex constants are integer constants
> (is this implicit or documented ?)
It's documented very clearly in section 6.4.4 of the standard.
unsigned char *p = (unsigned char*)&f;
unsigned char *lim = p + sizeof f;
printf("%13.7g 0X", f);
while(p < limit)
printf("%02X", *p++);
printf("%zu\n", sizeof f);
Note: if you're using C90, replace that last line with:
printf("%lu\n", (unsigned long)sizeof f);
Note that this will not work as intended if UCHAR_MAX > 255. Writing the
code so that it will work properly for arbitrary values of UCHAR_MAX is
quite feasible, but it would add significantly to the complexity of the
code, which I think would only add to your confusion; since such systems
are rare, I kept the code simple by not dealing with them.
> I tried the above using one of the following instead of "somevalue"
> (with gcc)
>
> f=1.0f ; /* gives 3FF00000 instead of 3F800000 */
> f=2.0f ; /* gives 40000000 */
> f=4.0f ; /* gives 40800000 instead of 40100000 */
> f=8.0f ; /* gives 41000000 instead of 40200000 */
> C FORTRAN
>
> For 2.0 I obtain the same binary representation I obtain in Fortran, for
> the other values (note all powers of 2) I obtain discrepant values. 'm
> pretty sure (checked with my old Excel spreadsheet doing the bit-by-bit
> display of a real in IEEE and VAX form) the Fortran value is the correct
> one (IEEE).
>
> Is this a side effect of some signed vs unsigned thing ?
Since the printf() call that you wrote has undefined behavior, there's
really nothing that can meaningfully be said about why you got the
results that you got.
>
> and if a float won't fit in an int?
Goes 'splody. If you're up against platform dependencies (which you
will be in the real world), you might have to resort to #if
#if sizeof(int) == 4
#define INT4 int
#endif
#if sizeof(long) == 8
#define INT8 long
#endif
And lots more like that. These sorts of things are needed for dealing
with IO and external file formats, ime.
Then go:
union float_int {
FLOAT4 f;
INT4 i;
} x;
Which will meet the op's request for 4 byte values.
That code is problematic for several different reasons: it reads the
value of a different member of a union than the one last written, it
reads the value of an 'int' object that might contain a trap
representation, and it passes an int value to a printf() call when
corresponding specifier is "%X". If sizeof(int) > sizeof(float), all of
those problems just got worse.
Even if none of the above issues apply, if sizeof(int) < sizeof(float),
or if 'int' has any padding bits, this code will not print the entire
representation, and the result you get will depend upon the byte order
of 'int'. I say "byte order" rather than endianess because it's possible
that sizeof int > 2, in which case there's many more possibilities than
just those two. I once saw a list identifying 12 of the 24 possible byte
ordering for 4-byte integers as being in current use, though there's
only 4 that are at all common.
PL/I constants:
bit constant '1011100'b
bit data hex constant: '3ABC'B4
character hex constant '2E59'X
binary constant 10111001b
binary hex constant '48AB'XN
The first column contains the hex representations of single precision
floating-point, the second the hex representations of double precision
floating-point with the last eight hex digits chopped off (they are all 0).
I think that you obtained the first column from Fortran and the seconde
from C, contrary to what you state. And the second is expected from C,
as in printf the float argument is automatically converted to double.
--
dik t. winter, cwi, science park 123, 1098 xg amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
> On Mon, 15 Jun 2009, Richard Maine wrote:
> > LC's No-Spam Newsreading account <nos...@mi.iasf.cnr.it> wrote:
>
> >> j=z'7FFE' ! gives 32866
> >> r=z'80800000' ! gives tiny
> >> j=z'44434241' ! gives "ABCD"
>
> > None of these are standard Fortran.
> But reading Metcalf, Reid and Cohen (Fortran 95/2003 explained) I got
> the impression they were standardized NOW.
They are, but...
> What is exactly non standard in my usage ?
>
> - usage of hex constants in assignments instead of DATA ?
> - usage of hex constants for non-integers ?
> - usage of hex edit descriptor for non-integers ?
Yes. All 3 of those. F2003 allows a few other places, but they are still
pretty limitted. Other posts have mentioned the reasons. In particular,
f2003 allows them as arguments to the real and integer intrinsics. That
provides a standard way to use them in assignments and for reals.
> I'd better revert to my old usages and consider hex constants as
> something to avoid.
They are ok with the above limitations.
> > It appears that you are not actually comparing the Fortran language to
> > other languges, but instead comparing a particular Fortran compiler.
>
> Well, unless one has access to The Standard Itself, the only way one can
> gain experience is testing with specific compilers
That is a severe overstatement at best. While textbooks are not
definitive in cases of disagreement of interpretation, they are
excellent sources for most people - probably better than the standard
itself in that they are usually easier to read. You mention Metcalf,
Reid, and Cohen above. That's a fine source - certainly far better than
just testing with a compiler.
Testing with a specific compiler is simply a horrible way to evaluate
standard conformance. I cannot count the number of times that point has
been reiterated in this forum, usually when someone cites the fact that
their code compiled as evidence that it must be ok (and they are wrong).
There are many, many things that realistically cannot be diagnosed by a
compiler. Testing with a compiler is a useful "sanity check" to help see
if you might have overlooked something, but that is only a backup, not
the primary source.
At the very least, be sure to turn on the compiler's switches for
diagnosing standard conformance. The Intel compiler (and those in its
heritage) is particularly notable for accepting large numbers of
nonstandard features without warning by default. I consider this a
shortcoming of that mostly decent compiler. But the compiler does have a
switch for diagnosing the use of many of those nonstandard forms.
Without using that switch, I can't regard testing with the compiler as
much more than a joke in terms of verifying standard conformance. With
the switch, it is probably as good as most other compilers. I expected
that it would probably disgnose these particular errors. But as noted
above, a compiler can never be very good.
--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
> On Mon, 15 Jun 2009, jameskuyper wrote:
> > LC's No-Spam Newsreading account wrote:
>
> > The '%o" and "%X" format specifiers require an unsigned int argument,
>
> I thought they were "universal" like O and Z in Fortran.
You mean like the O and Z edit descriptor in Fortran are *NOT*? They
allow only integers in standard Fortran.
> I realize now that, at least in C, hex constants are integer constants
> (is this implicit or documented ?)
Again, just like in Fortran. Yes, this is documented.
> - it is not obvious to find the relevant information in the
> documentation :-(
I can't speak to whatever you are using as documentation for C, but you
mentioned MR&C as a source for Fortran. Dragging out my copy, most of
these issues look pretty clear in it to me.
The boz (binary, octal, and hex) literals are described in the section
on integer literal constants. The text says they are integers, in case
the section name wasn't enough clue. It then also says "The use of these
forms of constants is limitted to their appearance as implicit integers
in the data statement..." That seems pretty direct to me.
For the edit descriptors, B, O, and Z are all listed only in the section
on integer (pg 197) and described as for integers.
The one thing that I would agree makes some material a little hard to
find is the way that the book separates out the new f2003 material. I
quickly found the material on boz literals on page 15. That doesn't
cover the f2003 feature of allowing those forms in some intrinsics. For
that, you need to go to the chapter on "miscellaneous enhancements", in
particular 18.9, which is even high enough level to be in the table of
contents. That section also mentions a little aabout the reasons for the
limitations, while page 15 was pretty much "just the facts."
I'd suggest that the bigger thing that would make this material hard to
find would be failing to make it a habit to look. That seems to go along
with your comment elsewhere that "unless one has access to The Standard
Itself, the only way one can gain experience is testing with specific
compilers".
> The boz (binary, octal, and hex) literals are described in the section
> on integer literal constants. The text says they are integers, in case
> the section name wasn't enough clue. It then also says "The use of these
> forms of constants is limitted to their appearance as implicit integers
> in the data statement..." That seems pretty direct to me.
> For the edit descriptors, B, O, and Z are all listed only in the section
> on integer (pg 197) and described as for integers.
> The one thing that I would agree makes some material a little hard to
> find is the way that the book separates out the new f2003 material. I
> quickly found the material on boz literals on page 15. That doesn't
> cover the f2003 feature of allowing those forms in some intrinsics. For
> that, you need to go to the chapter on "miscellaneous enhancements", in
> particular 18.9, which is even high enough level to be in the table of
> contents. That section also mentions a little aabout the reasons for the
> limitations, while page 15 was pretty much "just the facts."
There seems to have been a sea change in F03 where boz-literal-constants
can be regarded as bit sequences as arguments to INT and REAL, as in
N1723.pdf, section 13.3.3. This usage seems more consistent with the
O.P.'s expectations.
C:\gfortran\clf\bit_sequence>type bit_sequence.f90
program test
implicit none
real x
x = real(z'3f800000',kind(x))
write(*,'(f0.1,1x,z8.8)') x, transfer(x,1)
end program test
C:\gfortran\clf\bit_sequence>gfortran -std=f2003
bit_sequence.f90 -obit_sequence
C:\gfortran\clf\bit_sequence>bit_sequence
1.0 3F800000
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
> LC's No-Spam Newsreading account wrote:
>> I thought they were "universal" like O and Z in Fortran.
> Did the documentation for those specifiers give you any justification for
> such thinking? It should say something like the following: "The unsigned
> int argument is converted to unsigned octal (o), unsigned
> decimal (u), or unsigned hexadecimal notation (x or X)... " (7.19.6.1p8).
> Note, in particular, that if the argument is not an unsigned int, this
> description is meaningless, which is a strong hint that the argument has
> to be an unsigned int.
It seems to me that the O.P. really wants what conversion to an
unsigned type would give him. Just look at what he expects for the
Fortran output. Given that, his biggest problem is not specifying
the length of the output correctly in the format string:
C:\gfortran\clf\bit_sequence>type fmt.c
#include <stdio.h>
int main()
{
short i;
i = -2;
printf("%hd %6.6ho %4.4hx\n", i, i, i);
printf("%d %6.6o %4.4x\n", i, i, i);
return 0;
}
C:\gfortran\clf\bit_sequence>gcc -std=c99 fmt.c -ofmt
C:\gfortran\clf\bit_sequence>fmt
-2 177776 fffe
-2 37777777776 fffffffe
For what it's worth, I've seen code like this:
float f;
int *p = (int*)&f;
not work. Apparently, it's a C aliasing thing; you can't depend on
pointers of one type to point to objects of another type (gcc has an
option to change this behavior). The union is a safer way to go.
Louis
A union is not safer. Storing an int to a union and accessing a float,
or vice versa, is not defined behavior.
The portable purpose of a union is to provide compact storage for a polymorphic
data representation, whereby all accesses to the union are by means of that
member which was most recently used to store to it (or another member which has
a compatible type).
This rather draconian restriction has been relaxed. As a result, it
is reasonable to use a union with an array of unsigned char:
union rep {
float f;
unsigned char rep[sizeof(float)];
};
if you don't like using explicit pointers.
--
Ben.
> As a result, it is reasonable to use a union with an array of
> unsigned char:
>
> union rep {
> float f;
> unsigned char rep[sizeof(float)];
> };
>
> if you don't like using explicit pointers.
I like to do this kind of thing with memcpy():
int reinterpret_float_as_int(float f)
{
int x;
assert(sizeof f == sizeof x);
memcpy(&x, &f, sizeof x);
return x;
}
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
> There seems to have been a sea change in F03 where boz-literal-constants
> can be regarded as bit sequences as arguments to INT and REAL,
That's the feature I alluded to earlier. I don't think I would call it a
"sea change" though. Boz-literal constants are still very restricted in
where they can appear. The new feature was a bit of a compromise in that
it does allow them outside of data statements (that limitation was
painfully restrictive), but it avoids the problems of just allowing them
in arbitrary places. The new places allowed are contexts where the
intended meaning is both unambiguous and reasonably "obvious".
There was a proposal to allow them much more liberally, but that didn't
get very far. It had the problem that there were pretty much
irresolvable conflicts between consistency and some existing extensions.
Putting them in the INT and REAL intrinsics avoided such conflicts.
There were not inconsistent existing extensions, and it allowed the
kinds of things people (such as the OP, but he is far from the only one)
want to be able to do. It does have the disadvantage of being a bit
verbose, but for that verbosity you get obviously unambiguous.
To me, a "sea change" would be allowing them anywhere and having the
interpretation determined by context.
Hmm. I suppose I'll set followups, though people can override if they
like. This particular bit seems to have minimal relevance to C or Java
other than perhaps the side note that it has some simillarities to what
appears to be allowed in them. The syntax is different, but it appears
that they also have a capability to explicitly specify that a bit
pattern is to be interpreted as a real.
Correct. However, that's not the case for unsigned char*; it's
perfectly safe to convert a pointer to any object into a pointer to
unsigned char*, and to use that pointer to access the first sizeof
(object) bytes after that pointer.
> ... Apparently, it's a C aliasing thing; you can't depend on
> pointers of one type to point to objects of another type ...
Correct. The anti-aliasing rules are intended to allow a C compiler to
generate code which, for example, assumes without bothering to check,
that writes through a pointer to float will not interact with reads
through a pointer to int.
> .. The union is a safer way to go.
The footnote to section 6.5.2.3p4 says "If the member used to access
the contents of a union object is not the same as the member last used
to store a value in the object, the appropriate part of the object
representation of the value is reinterpreted as an object
representation in the new type as described in 6.2.6 (a process
sometimes called "type punning"). This might be a trap
representation." That last sentence is the killer.
I thought that t O and Z still didn't work with non-integer
(REAL, COMPLEX, and CHARACTER) data. I would expect TRANSFER to
work, transfering the bits to the appropriate integer.
-- glen
<> The problems with the "%o" and "%X" format specifiers in this case are
<> technically exactly the same as in the previous two cases. However,
< Hmm... what's then the "standard" way to obtain an hex dump of a float
< (in the way the Z format will do in Fortran), other than writing it to a
< binary file and using od :-) ?
Copy to the appropriate sized integer using memcpy() after
casting pointers to (unsigned char*).
< I tried the above using one of the following instead of "somevalue"
< (with gcc)
< f=1.0f ; /* gives 3FF00000 instead of 3F800000 */
< f=2.0f ; /* gives 40000000 */
< f=4.0f ; /* gives 40800000 instead of 40100000 */
< f=8.0f ; /* gives 41000000 instead of 40200000 */
< C FORTRAN
I don't see how you got most of those. Note that you can't
pass (float) values to printf, as they get converted to double
along the way. You should print them with %8.8Lx, with the
assumption that (double) and (long long) are the same size.
X'3FF0000000000000' (with the appropriate endianness) is
right for IEEE double.
do i=0,10
write(*,'(Z8.8)') TRANSFER(2.0**i,1)
enddo
end
will print out the single precision powers of 2.0 in Fortran.
#include <stdio.h>
#include <math.h>
int main() {
float f;
int i,j;
for(i=0;i<=10;i++) {
f=pow(2.0,i);
memcpy((unsigned char*)&j,(unsigned char*)&f,sizeof(j));
printf("%8.8x\n",j);
}
}
Will, I believe, in standard C with the assumption that
sizeof(int)==sizeof(float).
< For 2.0 I obtain the same binary representation I obtain in Fortran, for
< the other values (note all powers of 2) I obtain discrepant values. 'm
< pretty sure (checked with my old Excel spreadsheet doing the bit-by-bit
< display of a real in IEEE and VAX form) the Fortran value is the correct
< one (IEEE).
< Is this a side effect of some signed vs unsigned thing ?
No, it is (float) vs. (double).
-- glen
> In comp.lang.fortran Richard Maine <nos...@see.signature> wrote:
> <>
> <> - usage of hex constants in assignments instead of DATA ?
> <> - usage of hex constants for non-integers ?
> <> - usage of hex edit descriptor for non-integers ?
>
> < Yes. All 3 of those. F2003 allows a few other places, but they are still
> < pretty limitted. Other posts have mentioned the reasons. In particular,
> < f2003 allows them as arguments to the real and integer intrinsics. That
> < provides a standard way to use them in assignments and for reals.
>
> I thought that t O and Z still didn't work with non-integer
> (REAL, COMPLEX, and CHARACTER) data.
They don't. I think you misunderstood my response, perhaps from having
snipped slightly too much.
The above was a list of things that were nonstandard about the OP's
code. I was not saying that they were things that changed in f2003.
Indeed, nothing of this in the OP's code is any more standard in f2003
than f95. F2003 does allow hex literals in a few other contexts, but not
in quite the way done by the OP.
> I would expect TRANSFER to
> work, transfering the bits to the appropriate integer.
Me too.
> In comp.lang.fortran LC's No-Spam Newsreading account <nos...@mi.iasf.cnr.it> wrote:
<snip>
> < Hmm... what's then the "standard" way to obtain an hex dump of a float
> < (in the way the Z format will do in Fortran), other than writing it to a
> < binary file and using od :-) ?
>
> Copy to the appropriate sized integer using memcpy() after
> casting pointers to (unsigned char*).
There is no need to cast since (modern) memcpy takes void * arguments
and the conversion is implicit as in Ben Pfaff's code example
elsewhere.
<snip>
> #include <stdio.h>
> #include <math.h>
> int main() {
> float f;
> int i,j;
> for(i=0;i<=10;i++) {
> f=pow(2.0,i);
> memcpy((unsigned char*)&j,(unsigned char*)&f,sizeof(j));
You can omit the casts and the ()s round j. Of course you don't have
to, I am just saying you can in order to get a cleaner example:
memcpy((&j, &f, sizeof j);
> printf("%8.8x\n",j);
> }
> }
<snip>
--
Ben.
> > and if a float won't fit in an int?
>
> Goes 'splody.
que?
> If you're up against platform dependencies (which you
> will be in the real world), you might have to resort to #if
the trouble is the "union hack" invokes Undefined Behaviour.
> #if sizeof(int) == 4
> #define INT4 int
> #endif
>
> #if sizeof(long) == 8
> #define INT8 long
> #endif
puke. I *hate* code like this
> And lots more like that. These sorts of things are needed for dealing
> with IO and external file formats, ime.
no they aren't. Define your external interfaces in terms of streams
of bytes (or octets if you want to be really cool) and write code
to read and write them into structures.
> Then go:
>
> union float_int {
> FLOAT4 f;
> INT4 i;
> } x;
>
> Which will meet the op's request for 4 byte values.
it's possible float won't fit in *any* integer type
> > unsigned char *p = (unsigned char*)&f;
> > unsigned char *lim = p + sizeof f;
>
> For what it's worth, I've seen code like this:
>
> float f;
> int *p = (int*)&f;
>
> not work.
so don't do it.
> Apparently, it's a C aliasing thing; you can't depend on
> pointers of one type to point to objects of another type
With the exception of unsigned char. An array of unsigned char
can be overlaid on any other type. No traps or other undefined
behviour. It's the C way of getting at the representation of
an object. Which is probably what the OP wants. I already posted
code to do this.
> (gcc has an option to change this behavior).
gcc is borken
> The union is a safer way to go.
noooo!
--
Nick Keighley
"That's right!" shouted Vroomfondel "we demand rigidly defined
areas of doubt and uncertainty!"
> "LC's No-Spam Newsreading account" <nos...@mi.iasf.cnr.it> wrote in message
> news:alpine.LSU.2.00.0...@cbfrvqba.ynzoengr.vans.vg...
<snip: wrongly assuming, among other things, that C assignment takes
the bitpattern of a hex constant to a floating-point representation>
> > f=0X40800000; /* should return 4.0 */
> > f=0X80800000; /* should return tiny */
>
> > For instance the latter returns 2.155872e+09, the former 2.155872e+09 and
> > BOTH THE SAME 00000000000 as octal and 41E01000 as hex (different from the
> > one I assigned)
>
> C defines hex constants as being unsigned ints, maybe unsigned long ints,
Nit: C integer constants, unless suffixed L or LL, are the 'lowest'
type at least as high as int sufficient to contain the value.
Unless suffixed U, decimal constants mostly stay signed:
C89: signed int, signed long, unsigned long /* exception */
C99: signed int, signed long, signed long long
but hex or octal try BOTH signed and unsigned:
C89: signed int, unsigned int, signed long, unsigned long
C99: same then signed long long, unsigned long long
Thus a 'full width' hex constant, like 0xF00D0EC0 on a 32-bit system,
will come out unsigned int, but not all values will.
> I'm not clear on the fine points, but you should definitely get the big
> numbers you are getting. I haven't thought about the octal and hex
> outputs you report above. That's a different problem.