(arm-elf-gcc and friends) Bug in floating point conversion/formatting ... ?

Lately I have had a lot of trouble with the behaviour in a program I'm working on. Finally now I'm able to reproduce some weird behaviour wrt. floating point conversion. See the code snippet below which is the true code. The "0" prefix comes from the send_n function.

I am running the arm-elf-gcc toolchain, uC is an Atmel AT91R40807:

arm-elf-gcc ver 2.96 arm-elf-as arm-elf-ld arm-elf-objcopy ver 2.10

(Sorry, I don't know which library versions I use, and also don't know how to find it out. Please advise.)

When I run the code below the following gets printed

0 Check : 39.37 0 Check : 39.374996 0 Check : 30.00 0 Check : 39.375000 0 Check : 39.38 0 Check : 39.375004

If I change the formatting from %7.2f to %7.3f everything works like a charm, and the following is printed on the serial terminal

0 Check : 39.375 0 Check : 39.374996 0 Check : 39.375 0 Check : 39.375000 0 Check : 39.375 0 Check : 39.375004

I have had no luck googling for a solution/explanation, but of course, I might have been looking in the wrong direction.

All and any suggestions are welcome. Also, please don't hesitate to ask for further information.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void showfloatbug(int n) { union longfloat { float flow; unsigned long l; } u;

u.l = 0x421d7fff; snprintf(dbuf,sizeof(dbuf)," Check : %7.2f",u.flow); send_n(n,dbuf); snprintf(dbuf,sizeof(dbuf)," Check : %f",u.flow); send_n(n,dbuf);

u.l = 0x421d8000; snprintf(dbuf,sizeof(dbuf)," Check : %7.2f",u.flow); send_n(n,dbuf); snprintf(dbuf,sizeof(dbuf)," Check : %f",u.flow); send_n(n,dbuf);

u.l = 0x421d8001; snprintf(dbuf,sizeof(dbuf)," Check : %7.2f",u.flow); send_n(n,dbuf); snprintf(dbuf,sizeof(dbuf)," Check : %f",u.flow); send_n(n,dbuf); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

BR,

--
Torbjørn Heltne
AM Elektronikk AS
Reply to
Torbjørn Heltne
Loading thread data ...

I just want to point out where the problem is visible, in the 3rd "Check" line here, where 30.00 is printed instead of 39.38.

TIA,

-- Torbjørn Heltne AM Elektronikk AS

Reply to
Torbjørn Heltne

This is a library problem - the print formatter conversion is there. As you're feeding in the float patterns in hex, the compiler has little to do with them. To be sure, check the generated assembly code with the -S switch to the GCC.

Your compiler is pretty old - the ARM code generation was completely rebuilt for GCC 3.x, please update if possible. The ELF support on

2.96 was kludged on to provide a minimal support for ARM-based Linux versions.

Also, version 2.96 is *not* a genuine GCC version at all, it is a Red Hat special known to have problems. For details, have a look at the GNU pages .

HTH

Tauno Voipio tauno voipio @ iki fi

Reply to
Tauno Voipio

... snip ...

While it is not impossible that a system bug exists, your code is doubly flawed. First, you cannot legally extract a value from a union in a different form from that you put in.

I am ignoring the undefined send() and dbuf above, I assume they have some meaning to you. I am also ignoring the lack of suitable #includes to define snprintf, etc.

The legitimate way to access the bytes of something is via an unsigned char * pointer. The reverse mechanism MAY work, in fact usually will, but is not guaranteed.

char getbyte(void *thingptr, int which) { unsigned char *p = thingptr;

return p[which]; }

Something that may well be happening to you is that floats and integers are stored in different registers, have different internal lengths, etc. You are not accessing what you think you are. You can also create:

void putbyte(void *thingptr, int which, const unsigned char ch) { unsigned char *p = thingptr;

p[which] = ch; }

Now you could have your system above:

int i, lgh; unsigned long l; float f;

l = 0L; f = 39.37;

for (i = 0; i < sizeof f; i++) putbyte(&f, i, (l >> (i * 8)) & 0xff);

where the 8 and 0xff are only valid if CHAR_BIT is 8. This also has the (not guaranteed) assumption that sizeof(long) == sizeof(float). It should avoid peculiarities to do with actual implementation details. Note the &f to start with a pointer. The use of void* types will assure the correct transformations.

The main point is: Don't take shortcuts around the standard. If fully standards compliant code fails, you have a right to complain, but not before.

--
Chuck F (cbfalconer@yahoo.com) (cbfalconer@worldnet.att.net)
   Available for consulting/temporary embedded and systems.
 Click to see the full signature
Reply to
CBFalconer

(Something that I realize is pretty easy to misunderstand) :-)

Let me re-visualize the actual problem this way:

~~~~~~ char dbuf[81];

void showfloatbug(int n) { float f = 39.375; sprintf(dbuf," Check : %7.2f",f); /*Some code here to send dbuf on the serial port*/ sprintf(dbuf," Check : %7.3f",f); /*Some code here to send dbuf on the serial port*/ } ~~~~~~

This is printed on my terminal:

Check : 30.00 Check : 39.375

--
Torbjørn Heltne
AM Elektronikk AS
Reply to
Torbjørn Heltne

I realize that my original posting was not to the point(!) describing the problem I'm facing. Sorry about that. I just posted an updated description which I hope is a little bit better.

--
Torbjørn Heltne
AM Elektronikk AS
Reply to
Torbjørn Heltne

I just wrote in my reply to CBFalconer that my original posting was somewhat ...unclear. Please take a look at my updated posting.

True. The toolchain I use is a bit old.

--
Torbjørn Heltne
AM Elektronikk AS
Reply to
Torbjørn Heltne

Torbj=F8rn Heltne schrieb:

Hello,

it looks like a bug in the used library. You could try the types e or g instead of f, but the same bug might be=20 involved there too. sprintf(dbuf," Check : %7.2e",f); sprintf(dbuf," Check : %7.2g",f);

Bye

Reply to
Uwe Hercksen

We are still pointing to an obvious bug in the run-time print formatter in the library.

Tauno Voipio tauno voipio @ iki fi

PS. If you ever can, get rid of the GCC version 2.96.

TV

Reply to
Tauno Voipio

Hello,

i just tried it out on LPC2106 with arm-elf-gcc version 3.3.2 and it gives me the following result: (slighty modified your code, haven't used it in a subroutine, but shouldn't matter)

Check : 39.38 Check : 39.375

So it look like to work !

Greetings,

Martin

"Torbjørn Heltne" schrieb im Newsbeitrag news: snipped-for-privacy@news.broadpark.no...

Reply to
Martin Maurer

I have received a lot of useful input. Thank you to all!

I have now set up a newer toolchain by following these instructions:

The printf(....) problems I described are history.

BR,

--
Torbjørn Heltne
AM Elektronikk AS
Reply to
Torbjørn Heltne

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.