MicroBlaze floating point precision issues

Hello, group.

I'm having a heck of a time trying to figure out why my MicroBlaze implementation is presenting *supposedly* single-precision floating point values as double-precision values truncated to 32 bits.

Here's what I mean:

float test = 22; // for example

printf("test = 0x%08x\r\n",test); // prints "test = 0x40360000" printf("test = %d\r\n",test); // prints "test = 1077280768" printf("test = %f\r\n",test); // prints "test = 22.000000" or some precision

22 in single-point floating point (hex) is 0x41B00000, and in double- precision is 0x4036000000000000. So, truncate the double-precision value and you have what's printed to the screen. I'm completely baffled. Am I missing something? A gcc flag? How is this even possible for a single-precision instruction set?
Reply to
JD Newcomb
Loading thread data ...

If that literally is your test code, GCC might be being a bit too clever for you and effectively hard coding the literal '22' as the arg to the printf statements.

Try using

float test = 22.0f;

as the initial assignment for starters. To force single precision constants you need the 'f' suffix, otherwise you burn tragic number of cycles doing wasteful double to float conversions.

Also, perhaps specify optimisation level -O0 to gcc, see if that gets you anywhere.

Regards,

John

Reply to
John Williams

Well, the above wasn't the code that got me investigating the problem in the first place, but the results are the same.

I'm not using constants in my code that pertains to this particular issue. I have a function that returns an int, and I typecast it to a float and store it in the float variable:

float foo;

foo = (float) bar(&tmp); // tmp is some 32-bit ASCII-like value that's converted to an integer value... don't worry about it.

bar() in this case would return 22 as an int, and printing the variable foo results in the same printed statement as my test code above.

No optimizations also get me the same result. Any other ideas? Compiler flags I'm not seeing? The other question is: is this even wrong? I mean, I say it is because calculating the values out by hand using the IEEE 754 standard shows that the results are wrong. But using a value like 450.123f in the test code above printed as the 32- bit truncated double-precision value as 0x40776000 (single-precision is actually 0x43BB0000). Assuming that the truncation would reduce its precision, the floating value printed out as 450.122986. [shrug] Maybe it is right.

Reply to
JD Newcomb

If you use a "%x" or "%d" argument, printf() will only print a 32-bit integer, no matter what you pass as the argument. Any additional bits in the argument will just be ignored.

If you want to find out how many bytes are used in the implementation, try:

printf( "float: %d, double %d\n", sizeof(float), sizeof(double) );

If sizeof() returns a value greater than 4 bytes, you may want to try printing it as a 64 bit integer argument, using:

printf( "test %llx\n", test );

Note that this isn't guaranteed to produce any meaningful results.

Reply to
Arlet Ottens

That is C.

C always converts (float) to (double) before passing it to a varargs function. %f expects a double, not a float, as it will always be converted before the call.

try: printf("test = 0x%08x\r\n",*(int*)&test);

(assumes sizeof(float)==sizeof(int), but you were already assuming that.)

-- glen

Reply to
glen herrmannsfeldt

Thanks Arlett. The Xilinx xil_printf() doesn't handle floats, so I was forced to use hex. The 08x will force %x to only print 32 bits anyway, which is what I want.

Glen, this conversion on a single-precision processor like the MicroBlaze is emulated to be double-precision, correct? This seems, to me, the only way that it can be done on such a processor. But I am not

100% sure about that. And floats and ints on the MIcroBlaze are the same size (4 bytes). So, the value in memory might be correct, though the value printed is not. Yay for unnecessary conversions.

Your test proved correct. I've also used a direct read of the memory address in a similar way using the xio.h functions, which prints the same correct value. Thanks for your help, guys.

Reply to
JD Newcomb

(I wrote)

(snip)

Before ANSI C, K&R C did everything in double precision, except that it had the ability to store and fetch from single precision (float) variables. ANSI C added float constants, and the ability to pass them to non-varargs routines with a prototype in scope. Routines like printf always get a double. For most people, the extra overhead wasn't that big.

-- glen

Reply to
glen herrmannsfeldt

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.