EmbDev.net

Forum: ARM programming with GCC/GNU tools Floating Point in ARM7


Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
I want to convert a floating point to an integer, store the value in int
format, send the value over some interface, and convert the value again
to the floating point (WITHOUT MISSING THE ORIGINAL FLOATING POINT
VALUE). For example:

float a = 99.99;
unsigned int b = ToInt(a);

// I'll get b= 0x42C7FAE1 ;
// See http://www.h-schmidt.net/FloatApplet/IEEE754de.html

And I will be able to do the other way around.
unsigned int c = ToFloat(b);

// I'll get c = 99.99 again. Not 100 or 99.

For that I have these functions that will do the convertion:

unsigned int ToInt(float floatValue)
{
   float* pf = &floatValue;
   void* pv = (void*) pf;
   return (*((unsigned int*)pv));
}

float ToFloat(unsigned int u)
{
   unsigned int* pu = &u;
   return (*((float*)pu));
}

I've tested the code in my PC and it works. Just it dosn't work for ARM7
running NutOS. My codes are compiled very well without warnings and
errors.
However invalid values are resulted.
Do I need the Floating Point support for NutOS or some more libraries to
be included??
If anyone knows how to do it, please inform me.

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
Lidya Kosasih wrote:
> However invalid values are resulted.

How are you observing these 'invalid' values? If you are making the
observation at the receiving end and that is not another ARM device,
then you cannot be sure that both ends use the same floating point
representation. Even if they both use IEEE-754, that standard does not
define a byte order.

Issues regarding floating point and RTOS's were discussed
here:http://en.mikrocontroller.net/topic/125521. But I understand that
Nut/OS uses only non-preemptive cooperative multi-threading, so the
issues do not apply, I cannot imagine that this is the problem.

Note that you are not actually 'converting' anything here - the bit
pattern does not change. All you are changing is the interpretation of
the bit pattern. So if you are getting 'invalid' results, then the
problem is elsewhere I think. Apart from the possibility I mentioned
above, there are many ways in which the way you are observing the
results that might cause a problem.

In the absence of any more useful advice at this stage, some other
observations:

Your implementation of ToInt() the second line and both intermediate
variables are redundant:

unsigned int ToInt(float floatValue)
{
   return (*((unsigned int*)&floatValue));
}

Equally ToFloat can be simplified:

float ToFloat(unsigned int u)
{
   return (*((float*)&u));
}



Clifford

Author: Alexey Shusharin (alexey)
Posted on:

Rate this post
0 useful
not useful
Lidya Kosasih wrote:
> unsigned int c = ToFloat(b);
>
> // I'll get c = 99.99 again. Not 100 or 99.

I think variable c should be float instead of unsigned int:

float c = ToFloat(b);

Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
Alexey Shusharin wrote:
> Lidya Kosasih wrote:
>> unsigned int c = ToFloat(b);
>>
>> // I'll get c = 99.99 again. Not 100 or 99.
>
> I think variable c should be float instead of unsigned int:
>
> float c = ToFloat(b);

I wrote it wrong here.. It must be float c.
But it is written correctly in my source code. 
So, this wasn't the problem.

Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
Clifford Slocombe wrote:
> Lidya Kosasih wrote:
>> However invalid values are resulted.
>
> How are you observing these 'invalid' values? If you are making the
> observation at the receiving end and that is not another ARM device,
> then you cannot be sure that both ends use the same floating point
> representation. Even if they both use IEEE-754, that standard does not
> define a byte order.

I observe it directly by debugging the result from my PC via a serial
interface and also via USB interface. I am sure the problem is not in
the byte order.

>
> Issues regarding floating point and RTOS's were discussed
> here:http://en.mikrocontroller.net/topic/125521. But I understand that
> Nut/OS uses only non-preemptive cooperative multi-threading, so the
> issues do not apply, I cannot imagine that this is the problem.
>
> Note that you are not actually 'converting' anything here - the bit
> pattern does not change. All you are changing is the interpretation of
> the bit pattern. So if you are getting 'invalid' results, then the
> problem is elsewhere I think. Apart from the possibility I mentioned
> above, there are many ways in which the way you are observing the
> results that might cause a problem.

Well, I didn't understand why it happened. Probably I need to check it
in more detail.
Does it related to some libraries that I must included???

>
> In the absence of any more useful advice at this stage, some other
> observations:
>
> Your implementation of ToInt() the second line and both intermediate
> variables are redundant:
>
> unsigned int ToInt(float floatValue)
> {
>    return (*((unsigned int*)&floatValue));
> }
>
> Equally ToFloat can be simplified:
>
> float ToFloat(unsigned int u)
> {
>    return (*((float*)&u));
> }
>

Hmm thanks for the advice

>
> Clifford

Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
Well, I just find out that the function may give different result for
the same input. For example:

float c = ToFloat(99.99);

c could be 0x

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
Lidya Kosasih wrote:
>
> c could be 0x
Could be what?

It is true that if 99.99 cannot be precisely represented in IEEE-754
(and it probably cannot) that different implementations may produce a
different bit patterns for the same value. The only real test is to
reinterpret the value back to float and see if the value is identical.
If the re-interpretation is reversible you have by definition got the
correct bit pattern.

You need to compare the integer value not with the PC implementation but
with the bit pattern of the float value. So for the code:

float f = 99.99 ;
unsigned int u = ToInt( f ) ;

in the debugger watch the value f and u but set the display mode to HEX.
Alternatively do a memory dump at &f and &u to see both values'
representation in memory.

Failing all that if you are not sure about how to get teh debugger to
show you all that use:

printf( "%8.8X\n", *((unsigned*)&f) ) ;
printf( "%8.8X\n", u ) ;

Clifford

Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
Clifford Slocombe wrote:
> Lidya Kosasih wrote:
>>
>> c could be 0x
> Could be what?
>
> It is true that if 99.99 cannot be precisely represented in IEEE-754
> (and it probably cannot) that different implementations may produce a
> different bit patterns for the same value. The only real test is to
> reinterpret the value back to float and see if the value is identical.
> If the re-interpretation is reversible you have by definition got the
> correct bit pattern.
>
> You need to compare the integer value not with the PC implementation but
> with the bit pattern of the float value. So for the code:
>
> float f = 99.99 ;
> unsigned int u = ToInt( f ) ;
>
> in the debugger watch the value f and u but set the display mode to HEX.
> Alternatively do a memory dump at &f and &u to see both values'
> representation in memory.
>
> Failing all that if you are not sure about how to get teh debugger to
> show you all that use:
>
> printf( "%8.8X\n", *((unsigned*)&f) ) ;
> printf( "%8.8X\n", u ) ;

The debugging shows the first result correctly but the second one is
incorrect.
Although ToInt return code is exactly the same.
...
return *((unsigned*)&f);
...

After I  tried to write it as a macro
 #define TO_INT(f) {*((unsigned*)&f)};
...

   float f = 99.99 ;
   unsigned int u = TO_INT(f) ;

   pump_printf( "%8.8X\n", *((unsigned*)&f) ) ;

   pump_printf( "%8.8X\n", u ) ;

now both debugging results are incorrect.

>
> Clifford

Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
I tried to put the casted value into an unsigned int variable also.
The debugging result shows incurrect results too.

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
You have mentioned "debugging results are incorrect" several times, but
it would be helpful if you actually posted the results too!

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
... Your TO_INT() macro is also ill-formed.

#define TO_INT(f) (*((unsigned*)&(f)))

No {...} and no ; - otherwise it won't work in expressions where the
function form would have. And also () around f to ensure correct
evaluation order of expressions.

As it is it is still a bad macro, because (f) may resolve to an
expression that has no address, like TO_INT( 99.99 ) for example.

However none of that explains your problem.

At this stage it would be best if you posted the exact code you are
testing this with - i.e. complete, compilable and linkable. together
with the results you are getting preferably using test code output
rather than a description of the debugger output; that would require us
to trust that you are using the debugger correctly, which you probably
are, but it is better to have hard evidence.


Clifford

Author: Lidya Kosasih (bluetude)
Posted on:

Rate this post
0 useful
not useful
Clifford Slocombe wrote:
> ... Your TO_INT() macro is also ill-formed.
>
> #define TO_INT(f) (*((unsigned*)&(f)))
>
> No {...} and no ; - otherwise it won't work in expressions where the
> function form would have. And also () around f to ensure correct
> evaluation order of expressions.
>
> As it is it is still a bad macro, because (f) may resolve to an
> expression that has no address, like TO_INT( 99.99 ) for example.
>
> However none of that explains your problem.
>
> At this stage it would be best if you posted the exact code you are
> testing this with - i.e. complete, compilable and linkable. together
> with the results you are getting preferably using test code output
> rather than a description of the debugger output; that would require us
> to trust that you are using the debugger correctly, which you probably
> are, but it is better to have hard evidence.
>
>
> Clifford

I got the problem. It was in the compiler. Since I use NutOS, the NutOS
makefile has turn on the optimization with the -oS parameter. Changing
it to
-o3 make it works. However, when I call it from a thread, the same
problem occurs again.

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
Lidya Kosasih wrote:
> -o3 make it works. However, when I call it from a thread, the same
> problem occurs again.

As I suggested the code is not safe in the presence of optimisation. Use
a hardware timer. Actually surely NutOS provides timing services built
in? Actually I know it does, I just looked - NutSleep().

The whole point of a cooperative scheduler is to yield the processor
whenever a thread is not doing anything. A "busy-wait" timing loop is
not 'cooperative', it stops anything from doing anything - it blocks the
scheduler, so you may as well not be using NutOS in teh first place!

Clifford

Author: Clifford Slocombe (clifford)
Posted on:

Rate this post
0 useful
not useful
Oops, sorry. I thought I was answering a different thread!

I cannot see how NutOS or optimisation could be an issue here.

Clifford

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.