unsigned char u;
float f;
u = (unsigned char) f;
---------------------------------------------------------------------------------------------------
c:/wavr10/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/
avr35\libc.a(fp_powsodd.o): In function `__fp_powsodd':
(.text.avr-libc.fplib+0x10): relocation truncated to fit:
R_AVR_13_PCREL against symbol `__mulsf3' defined in .text section in
c:/wavr10/bin/../lib/gcc/avr/4.3.3/avr35\libgcc.a(_mul_sf.o)
c:/wavr10/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/
avr35\libc.a(fp_powsodd.o): In function `__fp_powsodd':
(.text.avr-libc.fplib+0x20): relocation truncated to fit:
R_AVR_13_PCREL against symbol `__mulsf3' defined in .text section in
c:/wavr10/bin/../lib/gcc/avr/4.3.3/avr35\libgcc.a(_mul_sf.o)
"relocation truncated to fit" sure sounds ominous.
Altavista-ing that phrase pops up with a discussion on an Intel board of
32-bit vs. 64-bit immediate addressing, and the comment "If you're
seeing this and you're not hand-coding, you probably want to check out
the -mmodel argument to gcc."
So it appears that it's not really doing anything serious other than
completely screwing up your addressing.
--
Tim Wescott
Control system and signal processing consulting
www.wescottdesign.com
> unsigned char u;
> float f;
>
> u = (unsigned char) f;
In what kind of situation you need to cast a float to that unsigned
char ???
If you want to extract the integer part of the float, let me tell you
that this way is a bit silly.
Question yourself before asking to C.
Habib
f is result of k1 * sine x + k2 * cosine y.
How would you extract the integer part without casting? I thought
that's the job of the compiler.
Approach it a little at a time:
Try casting to a (signed) int first.
If that works, then unsigned (assuming your value truly
is "non negative").
Finally, shrink it to a char.
Sometimes compilers get upset if you do things that
it doesn't expect.
You might also experiment with real doubles to see if
there are any subtle differences.
Well, technically, there are a lot of ways you *could*
do it -- but most are not as efficient as a simple cast.
Remember that a cast *discards* the fractional part
(i.e., doesn't round). Also, the cast will misbehave if
the argument doesn't fit in the data type.
Noop, this does not work either:
int i;
unsigned char u;
i = (int) f;
u = (unsigned char) i;
---------------------------------------------------
All these ops works on x86 gcc. I guess AVR is not ready for floating
points. Any one got FP apps working for AVR? For me, I am ready to
ARM, as soon as my LPC (ARM Cortex M0) kit arrival.
>
> f is result of k1 * sine x + k2 * cosine y.
>
> How would you extract the integer part without casting? I thought
> that's the job of the compiler.
Sure that's the compiler job, so please cast a float to an integer
(signed int). Remember char are not meant to be used for math.
Keep It Simple.
Habib
The cast isn't necessary but it may give a hint to the compiler that
what you've written is what you've intended. In a simple assignment, the
operator itself causes the type of the right operand to be converted to
the type of the left and the resulting value to then be stored in the
object indicated by the left operand. Absent the cast, you're likely to
get an "Are you sure you meant to do this?" type of warning.
When a real (e.g., not a NAN or otherwise) floating point type is
converted to an integer type, the fractional part is simply discarded
(no rounding, truncate towards zero). You will hit undefined behavior,
though, if the resulting integral value can't be represented in the
intended integer type.
So, "u = f;" is perfectly legal, no cast required, but f would have to
be in the open interval (-1, UCHAR_MAX + 1) to avoid undefined behavior.
An explicit cast doesn't hurt and also lets the maintenance programmer
know that yes, this is what I meant to do.
--
Rich Webb Norfolk, VA
But the real world (as least in my case) is unsigned char (8 bits).
Now, the strange thing is:
i = (int) f; works
or
u = (unsigned char) i; works
but not together
i = (int) f;
u = (unsigned char) i;
Unless my apps is very unique (USB CDC A2D), I have to conclude that
AVR is not ready for it.
linnix wrote:
> All these ops works on x86 gcc. I guess AVR is not ready for floating
> points. Any one got FP apps working for AVR?
I do heavy floating point computations with AVR (IAR workbench
compiler), and it works nicely. BTW, the math on the AVR at 20MHz is
somewhat 3 times faster then the same math on 40MHz PIC18.
My experience is not all compilers provide for every possible cast
between the standard types; I have seen bugs in float <-> int
conversions also. But you can always do a function for explicit conversion.
Vladimir Vassilevsky
DSP and Mixed Signal Design Consultant
http://www.abvolt.com
Then I guess it's a avr-gcc porting problem. I'll check if arm-gcc
works or not.
>On Mar 18, 12:05 pm, D Yuniskis <not.going.to...@seen.com> wrote:
>> linnix wrote:
>> > In response to another thread, I am still getting these problems with
>> > WinAVR 2010. I think the linker is hitting some AVR limits. There
>> > are similar reports on the web as well.
>> > -------------------------------------------------------------------------------------------------
>>
>> > unsigned char u;
>> > float f;
>>
>> > u = (unsigned char) f;
>>
>> Approach it a little at a time:
>> Try casting to a (signed) int first.
>> If that works, then unsigned (assuming your value truly
>> is "non negative").
>> Finally, shrink it to a char.
>
>Noop, this does not work either:
>
> int i;
> unsigned char u;
>
> i = (int) f;
> u = (unsigned char) i;
>---------------------------------------------------
>
>All these ops works on x86 gcc. I guess AVR is not ready for floating
>points. Any one got FP apps working for AVR?
Try ICC's AVR compiler. There's a free trial that decays to a code-size
limited version after 45 days. Imagecraft produces compilers for quite a
few microcontrollers but their AVR offering is far and away their most
popular.
I tried your test above and it compiles cleanly. Don't have an AVR dev
board or breadboard set up right now but I'll give it a run this
evening. I expect it to work as per spec, though.
> On Mar 18, 12:19 pm, Habib Bouaziz-Viallet <h.bouazizvial...@free.fr>
> wrote:
>> Le Thu, 18 Mar 2010 12:39:32 -0700, linnix a écrit :
>>
>>
>>
>> > f is result of k1 * sine x + k2 * cosine y.
>>
...
>
> Unless my apps is very unique (USB CDC A2D), I have to conclude that AVR
> is not ready for it.
oh no you cannot conclude that AVR or avr-gcc or AVR and avr-gcc are not
ready for doing math, no you cannot !
Habib
Try lowering the optimization level (and hope that whoever wrote it was
paying attention).
Or make a function
int cast_float_to_int_boy_gcc_is_stupid(float f)
{
return (int) f;
}
in extreme cases you may need to put it in a separate file to _really_
confound an over-eager optimizer.
If you insert some printfs (or just single-step a debugger), what does it
produce for i and u (assuming, say, f was... 123.456 to begin with?)?
>Unless my apps is very unique (USB CDC A2D), I have to conclude that
>AVR is not ready for it.
Just the compiler. :-)
Now it works if I remove some other functions. I guess I am hitting
some kinds of compiler limits.
>
> If you insert some printfs (or just single-step a debugger), what does it
> produce for i and u (assuming, say, f was... 123.456 to begin with?)?
Yes, I got correct result of 123.
>
> >Unless my apps is very unique (USB CDC A2D), I have to conclude that
> >AVR is not ready for it.
>
> Just the compiler. :-)
Yes, it is taking too much time for me. I'll try other options.
>On Mar 18, 12:05=A0pm, D Yuniskis <not.going.to...@seen.com> wrote:
>> linnix wrote:
>> > In response to another thread, I am still getting these problems with
>> > WinAVR 2010. =A0I think the linker is hitting some AVR limits. =A0There
>> > are similar reports on the web as well.
>> > -----------------------------------------------------------------------=
>--------------------------
>>
>> > unsigned char u;
>> > float f;
>>
>> > u =3D (unsigned char) f;
>>
>> Approach it a little at a time:
>> Try casting to a (signed) int first.
>> If that works, then unsigned (assuming your value truly
>> is "non negative").
>> Finally, shrink it to a char.
>
>Noop, this does not work either:
>
> int i;
> unsigned char u;
>
> i =3D (int) f;
> u =3D (unsigned char) i;
>---------------------------------------------------
>
>All these ops works on x86 gcc. I guess AVR is not ready for floating
>points.
That is a bit too harsh. This may be an optimisation problem or a
problem in the libraries. Check the assembler to see what is going on.
Try to compile with -O0 to turn off all optimisation first and try
again.
--
Failure does not prove something is impossible, failure simply
indicates you are not using the right tools...
nico@nctdevpuntnl (punt=.)
--------------------------------------------------------------
Are you sure you're not just flat out running out of room?
>All these ops works on x86 gcc. I guess AVR is not ready for floating
>points. Any one got FP apps working for AVR? For me, I am ready to
>ARM, as soon as my LPC (ARM Cortex M0) kit arrival.
Are you doing fft? (sin cos).
I just tried integer fft in C, made 2 versions,
one with an 8 bit sine lookup table, and one with a 16 bit table.
Fiddled it so all values fit in a 16 bit integer... can do integer math.
Now I can port it to PIC.... in asm.
The difference is noticable when compared to floating point,
but on a 64 bit high display the 'noise' reduces to very little.
I mean you need to divide a lot... to fit the maximum...
So it all depends,
I think my integer fft is good, worth some money too.
Should be plenty of Flash and SRAM left.
avr-gcc.exe -I"./.." -I"../conf" -I"../../.." -I"../../../../common" -
mmcu=atmega32u2 -Wall -gdwarf-2 -Os -fsigned-char -ffunction-sections -
MD -MP -MT default/usb_task.o -MF default/dep/usb_task.o.d -c
usb_task.c -o default/usb_task.o
Linking
avr-gcc.exe -mmcu=atmega32u2 -Wl,-Map=udip.map,--cref,--gc-sections,--
relax default/main.o default/cdc_task.o default/uart_usb_lib.o default/
usb_descriptors.o default/usb_specific_request.o default/wdt_drv.o
default/uart_lib.o default/usb_drv.o default/scheduler.o default/
usb_device_task.o default/usb_standard_request.o default/usb_task.o
-o udip.elf
Create hex file
AVR Memory Usage
----------------
Device: atmega32u2
Program: 7664 bytes (23.4% Full)
(.text + .data + .bootloader)
Data: 877 bytes (85.6% Full)
(.data + .bss + .noinit)
I can probably rewrite it in fixed point if necessary. But the target
will be ARM anyway, I am just trying it out before the target is
ready.
u = (unsigned int) f;
or
u = (unsigned int) floor(f);
or
u = (unsigned int) ceil(f);
or
{
float ipart, fpart;
fpart = modf( f, &ipart );
u = (unsigned int) ipart;
}
or
:
It's not the casting, it's what you are casting to. A char type can't
(necessarily) hold the range of possible values. It's dangerous to
use a char unless you know the value can't exceed 255 (which you may).
WRT the relocation errors you began this thread with, I believe those
are an indication that a call/branch is out of range. This can happen
on machines that use a branch-to-subroutine type instruction when the
image gets large. Sometimes you can get around it using an indirect
call through a pointer.
George
This has nothing to do with the AVR. Looks like an optimisation bug to me.
doesn't GCC support some pragmas to exclude code from optimisation? Apart
from that, as others have said, u = f should have worked too when the
integer part of f is in the range of 0-255.
Meindert
Normally, comp.arch.embedded is a helpful place, but some of the
"answers" is this thread are ridiculous! People are leaping to
conclusions like "the avr can't do floating point", "gcc can convert a
floating point to an int, but not to a char", "try disabling
optimisations", etc.
It seems no one has asked any /relevant/ questions the would have helped
you out.
Have you got a minimal code snippet that illustrates the problem, and is
valid and compilable C code? In this case, you would probably have
something like:
// Use "volatile" so the code won't be optimised away
volatile unsigned char u;
volatile float f;
int main(void) {
u = (unsigned char) f;
return 0;
}
Working out a minimal code snippet is extremely helpful in isolating the
problem, and essential for other people to give more than hand-waving help.
Secondly, we need to know your command line switches. A common source
of problems is incorrect switches (such as for those choosing the avr
variant).
We also need to know the versions of the tools.
While avr-gcc has very few known issues that could result in wrong code
or compile failures, I don't think any compiler claims guarantees of
perfection - avr-gcc developers are entirely open about bugs, and very
interested to hear if this does turn out to be a compiler bug. But in
practice, it's rare that a user's problem is the result of a compiler
bug rather than a misunderstanding or error in the user's code or
command line.
You will get excellent support for avr-gcc on the avr-gcc mailing list -
people there will try to help out with your actual problem rather than
telling you your code is "silly", or that you should buy a different
compiler and/or microcontroller. Of course, the first thing you will be
asked there is the same questions I asked above.
If you don't want to join the mailing list, you can also use the gmane
mailing list to newsgroup gateway - you can see it as newsgroup
"gmane.comp.hardware.avr.gcc" on news.gmane.org.
mvh.,
David
Perhaps its time to consider the advantages of paid for tools over free/open
source ? I stopped using AVR-GCC a long time ago after comparing the machine
code it produced with IAR's. I thought things might have improved but
perhaps not - IAR works for Vlad on AVR but GCC screws up for the OP.
Are you listening Chris Hills ?
Michael Kellett
Why not verifying this with
avr-gcc -S yourfile.c
and read the assembler yourfile.s ...
What makes you think guys down here make ridiculous answers when
obviously the initial question is not clearly exposed.
Habib
...
> David
gcc does not promote the "(unsigned char) f" to an int - it would only
do that if you were doing maths on the value.
The function used for this conversion is "__fixunssfsi", which converts
a float into and unsigned int. gcc then converts this into an unsigned
char (by simply taking the lower 8-bit register). But that's not
"promotion", and it is a perfectly correct implementation.
You can be pretty confident that gcc gets the promotions and
interpretations of the code correct. While the avr port is a relatively
"small" compiler, the gcc front-end that interprets the C code is the
same for all gcc ports.
But it is certainly possible that issues appear when the value is used -
that's why the original poster has to provide a minimal code snippet
that shows the problem.
> Why not verifying this with
> avr-gcc -S yourfile.c
>
> and read the assembler yourfile.s ...
>
I have done exactly that, using the command line:
D:\Micros\WinAVR-20100110\bin\avr-gcc -mmcu=atmega128 -Os -std=gnu99
-Wa,-ahlsd=test.avr.20100110.lst -fverbose-asm test.c -o test.elf
(Obviously the path to avr-gcc will vary).
The relevant assembly code is:
64 .global main
66 main:
67 /* prologue: function */
68 /* frame size = 0 */
69 0022 6091 0000 lds r22,f ; f.0, f
70 0026 7091 0000 lds r23,(f)+1 ; f.0, f
71 002a 8091 0000 lds r24,(f)+2 ; f.0, f
72 002e 9091 0000 lds r25,(f)+3 ; f.0, f
73 0032 0E94 0000 call __fixunssfsi ;
74 0036 6093 0000 sts u,r22 ; u, tmp44
75 003a 80E0 ldi r24,lo8(0) ; ,
76 003c 90E0 ldi r25,hi8(0) ; ,
77 /* epilogue start */
78 003e 0895 ret
And the elf output is properly linked against the required libraries
(automatically - you don't need to specify the library on the command line).
But all I can do here is show that avr-gcc has no problems compiling and
linking this code snippet correctly. To help the O/P, we need a snippet
that fails for him, not one that works for me. Once he posts that
snippet and the command line, people can really start to help him out
rather than making wild hand-waving suggestions.
> What makes you think guys down here make ridiculous answers when
> obviously the initial question is not clearly exposed.
>
That's kind of the point, really. The OP hasn't given enough
information to be able to diagnose his problem and help him out. But
instead of asking for more information, people here have given a variety
of useless information and suggestions. Not all the answers have been
bad - suggestions to break it into steps and to look at the size of the
code are good ideas. But none have asked him for the information that's
needed.
If I were to post a question in a car newsgroup saying my Volkswagon is
making a funny noise, I would expect to be asked to describe the noise,
or to say if it was constant or comes and goes, or asked what year and
model I have. I would not expect to be told that if I want a noise-free
drive I should buy a Ferrari, or that someone else's bus makes a
different noise.
I said that extracting the integer part of the float is ok when casting
a float to an int.
When you make a cast from a float to an unsigned int it would result a
zero if the float is negative (not quite sure either ... just conjecture)
BTW i don't know what would be the result if the target has a FPU (like
our big bunch desktop machines) ... :-)
Volkwagon have funny noises even fresh out of the factory ... (Just a joke)
Habib.
I don't think I'm following your argument here.
> I said that extracting the integer part of the float is ok when casting
> a float to an int.
>
> When you make a cast from a float to an unsigned int it would result a
> zero if the float is negative (not quite sure either ... just conjecture)
>
An "unsigned char" is just a silly name for an uint8_t - an unsigned
integer in the range 0 .. 255. Why do you see this as any different
from converting the float to an integer in the range -32768..+32767 ? I
presume the OP has made sure that the float in question is within a
reasonable range for the conversion - otherwise his data will be invalid
(though the program will still compile, link and run) - I don't know how
overflows and underflows are handled by the cast-to-integer operations.
To take a simple example, you might want a make a pwm sine wave by:
uint8_t pwmPercent;
pwmPercent = 100 * ((sinf(omega * time) + 1) / 2);
This is doing floating point calculations and then casting it to an
"unsigned char". The results would be exactly the same if pwmPercent
were an "int".
> BTW i don't know what would be the result if the target has a FPU (like
> our big bunch desktop machines) ... :-)
>
It should be the same (to within rounding errors). avr-gcc, like most
compilers, implements basic IEEE floating point standards. As far as I
know, it doesn't implement NaNs, signed zeros, and other wierdo floating
point stuff, just like most other compilers and most hardware FPUs.
I would use round(), trunc(), ceil() or floor() as each could better fit.
--
Cesar Rabak
GNU/Linux User 52247.
Get counted: http://counter.li.org/
Habib Bouaziz-Viallet wrote:
> David Brown a écrit :
>> On 19/03/2010 10:34, Habib Bouaziz-Viallet wrote:
>>> In that case i'm quite sure gcc promote internally the (unsigned char)f
>>> to an int.
You're sure of something incorrect there.
> That is exactly the point. Why in the earth someone would need to
> convert a float (doing sine and cosine) to a unsigned char ???
That's none of your business. It's perfectly allowed C code, so the
compiler _must_ support it.
> When you make a cast from a float to an unsigned int it would result a
> zero if the float is negative (not quite sure either ... just conjecture)
Well, wrong again. Values from 0 (inclusive) to -1 (exclusive) convert
to zero, all other negative values cause undefined behaviour.
> BTW i don't know what would be the result if the target has a FPU (like
> our big bunch desktop machines) ... :-)
That has nothing to do with it, in principle.
Did you use the proper -mmcu= option on the GCC command line?
The errors point thet the compiler has generated code for
13 bit addresses (8 kiB memory), and the code exceeds the
13 bit address range.
--
Tauno Voipio
tauno voipio (at) iki fi
Yes, -mmcu=atmega32u2
>
> The errors point thet the compiler has generated code for
> 13 bit addresses (8 kiB memory), and the code exceeds the
> 13 bit address range.
That's why its confusing. Non-existence is also out of range.
I can get around it with including the source or binary for the
fp_powodd function.
>> gcc does not promote the "(unsigned char) f" to an int - it would only
>> do that if you were doing maths on the value.
> That is exactly the point. Why in the earth someone would need to
> convert a float (doing sine and cosine) to a unsigned char ???
Presumably because 1) they know the result will be within the range
0-255, and 2) the AVR is an 8-bit CPU, and operating on 8-bit integer
values is a _lot_ faster than operating on 16-bit or 32-bit integer
values.
> I said that extracting the integer part of the float is ok when
> casting a float to an int.
That's what the OP was doing: casting the float to an 8-bit unsigned
integer.
> When you make a cast from a float to an unsigned int it would result
> a zero if the float is negative (not quite sure either ... just
> conjecture)
No, that's not how it works.
> BTW i don't know what would be the result if the target has a FPU
> (like our big bunch desktop machines) ... :-)
The result would be the same.
--
Grant
Please compile this (gcc -o test -c test -lm) and tell me what you see.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.14
int
main(void)
{
float value=0;
while(value<10)
{
printf("%f\n", 10*sinf(2*PI*value));
printf("%d\n\n", (unsigned char)(10*sinf(2*PI*value)) );
value+=0.1;
}
return(EXIT_SUCCESS);
}
I knew this was not a related compiler issue or what else (on this i
agree with David), finally i give up because this thread is a serie of
non-sense.
>
>> BTW i don't know what would be the result if the target has a FPU
>> (like our big bunch desktop machines) ... :-)
>
> The result would be the same.
>
Habib
As you have said yourself, it sounds like this could be an issue with
the linker setup for this particular chip - it's nothing to do with the
compiler as such. But you will get far more helpful answers from the
avr-gcc mailing list - there is no need for workarounds like this until
you have confirmed that it is a bug and not something else.
If it /is/ a bug in the linker setup, then the avr-gcc team would very
much like to hear about it - that way it can be fixed for everyone.
And if a workaround of some sort is needed, then there may be better or
more convenient alternatives - your fix here may be relying on the luck
of the link order, and you could get the same problem later with
something else.
Other possibilities are to use different -mmcu flags for compilation and
linking - use "-mmcu=atmega32u2" during compilation (that ensures you
get the right IO headers, etc.), and a different 32K micro when linking
(to work around this possible bug in the atmega32u2 link setup). I've
done similar things in the past to work with devices that were not yet
supported.
Every C compiler I've seen does not require a cast to get the integer
part of a float.
The compile just generates magical code in the background for it
myinteger = myfloat;
Or course, this implies that the C compiler is loading it's default
RTL so that it knows how to handle floats, since AVR's to my knowledge,
do not have float operations in the cpu..(FPU) etc..
>>> I said that extracting the integer part of the float is ok when
>>> casting a float to an int.
>>
>> That's what the OP was doing: casting the float to an 8-bit unsigned
>> integer.
>>
>>> When you make a cast from a float to an unsigned int it would result
>>> a zero if the float is negative (not quite sure either ... just
>>> conjecture)
>>
>> No, that's not how it works.
>
> No ?
>
> Please compile this (gcc -o test -c test -lm) and tell me what you
> see.
You said that negative float values convert to an unsigned value of 0.
Here's what your sample programs shows:
-5.627771
251
-9.410577
247
-9.602361
247
-6.129940
250
Negative float values do not convert to unsigned values of 0. IOW, it
doesn't work the way you said it did, and the example program you
posted proves it.
> I knew this was not a related compiler issue or what else (on this i
> agree with David), finally i give up because this thread is a serie
> of non-sense.
I agree that the OP's problem had nothing to do with float/int
conversion. The OP's problem is that he ran out of code space.
--
Grant
>On Mar 18, 12:19 pm, Habib Bouaziz-Viallet <h.bouazizvial...@free.fr>
>wrote:
>> Le Thu, 18 Mar 2010 12:39:32 -0700, linnix a écrit :
>>
>>
>>
>> > f is result of k1 * sine x + k2 * cosine y.
>>
>> > How would you extract the integer part without casting? I thought
>> > that's the job of the compiler.
>>
>> Sure that's the compiler job, so please cast a float to an integer
>> (signed int). Remember char are not meant to be used for math.
>
>But the real world (as least in my case) is unsigned char (8 bits).
>
>Now, the strange thing is:
>
> i = (int) f; works
>or
> u = (unsigned char) i; works
>
>but not together
> i = (int) f;
> u = (unsigned char) i;
Why are you casting from signed to unsigned?
>
>Unless my apps is very unique (USB CDC A2D), I have to conclude that
>AVR is not ready for it.
>
Someone else suggested it as a two step castings, but it was not
really the problem any way.
It works on any integer. Unsigned char's are supposed to work modulo
their range.
Now I think
u = (unsigned char) f;
is brain damaged.
This tells the compiler to convert the float converted to an integer,
then take it modulo 256.
The OP should have had:
{
int i;
i = f
}
He would have discovered that his code was shorter and faster than his
determined attempt to confuse the compiler.
(Admitting that the compiler should never get confused.)
>
>Meindert
Groetjes Albert
--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst
>> Apart from that, as others have said, u = f should have worked too
>> when the integer part of f is in the range of 0-255.
> It works on any integer.
No, it doesn't. That's been clarified days ago in this thread.
> Unsigned char's are supposed to work modulo
> their range.
Yes, but that only applies once you _have_ an unsigned char. The
problem under consideration doesn't have one --- it's trying to build one.
> Now I think
> u = (unsigned char) f;
> is brain damaged.
You think incorrectly, there.
> This tells the compiler to convert the float converted to an integer,
> then take it modulo 256.
No, it doesn't. It instructs the compiler to generate code that does
exactly what the code says: convert the float to an unsigned char.
That's another thing that has been clarified days ago.
Yes, and we will scale f to fit within 255 first. We are only
interested in relative magnitude of an array.
> > It works on any integer.
>
> No, it doesn't. That's been clarified days ago in this thread.
>
> > Unsigned char's are supposed to work modulo
> > their range.
>
> Yes, but that only applies once you _have_ an unsigned char. The
> problem under consideration doesn't have one --- it's trying to build one.
>
> > Now I think
> > u = (unsigned char) f;
> > is brain damaged.
>
> You think incorrectly, there.
The compiler is smart enough to understand "u = f or i = f" as well.
The casting is for human reading the code. It may be unnecessary, but
not brain damaged.
>
> > This tells the compiler to convert the float converted to an integer,
> > then take it modulo 256.
>
> No, it doesn't. It instructs the compiler to generate code that does
> exactly what the code says: convert the float to an unsigned char.
> That's another thing that has been clarified days ago.
It is mainly for storage. Unsigned char (8 bits) takes less space than
float (16 bits) or double (32 bits). We don't really care how the
compiler does it, but storage is important for a 1K SRAM chip.
Last time I knew, that just cast the object into what you want, but it's
not going to magically convert a FLOAT to a unsigned char..
Its only going to instruct the compiler that the contents of memory the
"F" occupies is a unsigned char and simply moves the data from that
from ever it is in memory to "u"
simply speaking..
u = f; isn't the same as u = (unsigned char) f; where I come from..
And the last time I knew, AVR's do not have native support for
floating point math. UNless I've been out of the loop here?
Instead, the compiler should be loading a default RTL that contains
low level code to give you that results.. This of course is compiler
linked and thus, makes it look natural to you, the coder.
And if the C compiler is standardized like most other compilers..
u = (unsigned char) f; simply tells the compiler to treat the object
of "F" as if it was a char instead. No conversion is taking
place here.
As far as how the floats are implemented for the binary format of
this compiler will dictate what value of data will be returned..
I can only assume it may support the Mantissa and other elements of a
floating point number, in which case, the above will not work as you may
think..
But who am I, I don't know anything..
stick with the "u = f;" and the compiler should be happy with that and
call one of it's floattointeger conversion TRL functions.. But If you
want to know how the float if constructed to represent a floating point
number, I guess you could hack it with the cast. I think only the
authors of the compiler would understand it's meanings..
> Last time I knew, that just cast the object into what you want, but it's
> not going to magically convert a FLOAT to a unsigned char..
That's exactly what a cast does. (Though there's nothing magical
about the conversion -- it's a well-defined operation.)
> Its only going to instruct the compiler that the contents of memory the
> "F" occupies is a unsigned char and simply moves the data from that
> from ever it is in memory to "u"
No, it isn't. It instructs the compiler to do the conversion.
> simply speaking..
> u = f; isn't the same as u = (unsigned char) f; where I come from..
I'm not sure where you come from. Here on Earth, when using the C
language, it's exactly the same.
Here's an example program:
extern volatile unsigned char u1,u2;
extern volatile float f;
void foo1(void)
{
u1 = f;
}
void foo2(void)
{
u2 = (unsigned char)f;
}
And here's the generated code using gcc for IA32. Note that the code
generated for the two cases is identical:
.file "testit.c"
.text
.p2align 4,,15
.globl foo1
.type foo1, @function
foo1:
subl $8, %esp
fnstcw 6(%esp)
flds f
movzwl 6(%esp), %eax
movb $12, %ah
movw %ax, 4(%esp)
fldcw 4(%esp)
fistps 2(%esp)
fldcw 6(%esp)
movzwl 2(%esp), %eax
movb %al, u1
addl $8, %esp
ret
.size foo1, .-foo1
.p2align 4,,15
.globl foo2
.type foo2, @function
foo2:
subl $8, %esp
fnstcw 6(%esp)
flds f
movzwl 6(%esp), %eax
movb $12, %ah
movw %ax, 4(%esp)
fldcw 4(%esp)
fistps 2(%esp)
fldcw 6(%esp)
movzwl 2(%esp), %eax
movb %al, u2
addl $8, %esp
ret
.size foo2, .-foo2
.ident "GCC: (Gentoo 4.3.4 p1.0, pie-10.1.5) 4.3.4"
.section .note.GNU-stack,"",@progbits
> And the last time I knew, AVR's do not have native support for
> floating point math. UNless I've been out of the loop here?
Doesn't matter.
> Instead, the compiler should be loading a default RTL that contains
> low level code to give you that results.. This of course is compiler
> linked and thus, makes it look natural to you, the coder.
No idea what your point is.
> And if the C compiler is standardized like most other compilers..
>
> u = (unsigned char) f; simply tells the compiler to treat the object
> of "F" as if it was a char instead. No conversion is taking
> place here.
Yes, a conversion _is_ taking place here. That's what a cast _is_:
it's an explicit conversion operation.
> As far as how the floats are implemented for the binary format of
> this compiler will dictate what value of data will be returned..
No, it won't. It will take the integer portion of the float value and
store that value (modulo 256) into the unsigned char.
> I can only assume it may support the Mantissa and other elements
> of a floating point number, in which case, the above will not work as
> you may think..
> But who am I, I don't know anything..
I wouldn't say you don't know anything, but you don't seem to know
what a typecast does in a C program.
> stick with the "u = f;" and the compiler should be happy with that
> and call one of it's floattointeger conversion TRL functions.. But If
> you want to know how the float if constructed to represent a floating
> point number, I guess you could hack it with the cast. I think only
> the authors of the compiler would understand it's meanings..
A typecast doesn't to at all what you think it does.
--
Grant
And here is the AVR version for foo1, foo2 is identical except for the
labels. Trust me.
.global foo1
.type foo1, @function
foo1:
push r29
push r28
in r28,__SP_L__
in r29,__SP_H__
/* prologue: function */
/* frame size = 0 */
lds r24,f
lds r25,(f)+1
lds r26,(f)+2
lds r27,(f)+3
movw r22,r24
movw r24,r26
call __fixunssfsi
movw r26,r24
movw r24,r22
sts u1,r24
/* epilogue start */
pop r28
pop r29
ret
You are getting this entirely wrong. When you assign an expression of
one type to a lvalue of another type, there is always a cast. These two
assignments are always the same:
x = exp;
x = (typeof(x)) exp;
The OP wrote out the cast explicitly to make his code clearer - that's
good programming practice.
You are mixing this up with pointer casts. Casting a float to an int
(of any size and signedness) causes a proper conversion. But casting a
pointer to a float to a pointer to an int accesses the memory contents
without any interpretation. To get the effect you are worried about
here, you must write :
u = *((unsigned char *) &f);
But of course that's not what the OP wanted, so it's not what he wrote.
> And the last time I knew, AVR's do not have native support for floating
> point math. UNless I've been out of the loop here?
> Instead, the compiler should be loading a default RTL that contains low
> level code to give you that results.. This of course is compiler linked
> and thus, makes it look natural to you, the coder.
>
It doesn't make any difference whether floating point is implemented in
a hardware FPU or with software functions. The compiler (and library)
give you the same functionality for floats and doubles regardless of the
underlying implementation.
Clearly the implementation makes a difference for speed. It /may/ make
a difference if your code relies on the underlying format and your
toolset uses a non-IEEE format. But that would be a weird piece of
source code, and an unusual compiler - most compilers, including
avr-gcc, use IEEE format for their software floating point. It /may/
also make a difference if you are looking for IEEE corner-case
functionality - NaNs, signed zeros, rounding modes, etc. But again,
that's not the case in most software.
> And if the C compiler is standardized like most other compilers..
>
avr-gcc is as standard as it gets - but what you are describing is /not/
standard C behaviour.
> u = (unsigned char) f; simply tells the compiler to treat the object
> of "F" as if it was a char instead. No conversion is taking
> place here.
> As far as how the floats are implemented for the binary format of this
> compiler will dictate what value of data will be returned..
>
> I can only assume it may support the Mantissa and other elements of a
> floating point number, in which case, the above will not work as you may
> think..
> But who am I, I don't know anything..
>
I'm not going to generalise, but you are certainly getting this one wrong.
I stand corrected.
iso 9899-1990 c-standard
6.2.1.3
When a value of floating type is converted to an integral type
the fractional part is discarded. If the value of the integral part
cannot be represented by the integral type, the behaviour is undefined.
So undefined would be invoked outside 0.00000-255.99999999999999999
I have seen block scaled integer FFT that had almost no artifacts. I
wish i could remember where i saw it. I think it must be related to
some VAX or PDP-11 integer FFT code that i have seen. Must have been
25 to 30 years ago.
<snip>
>
> It is mainly for storage. Unsigned char (8 bits) takes less space than
> float (16 bits) or double (32 bits). We don't really care how the
> compiler does it, but storage is important for a 1K SRAM chip.
>
Really? I've never run across a 16 bit float. Every compiler I've worked
with uses 32 bits for float (sign, 8 bit exp, 23 bit mantissa w/ implied
MSB) and 64 bits for double. It's been a long time since I read IEEE-754
and it wouldn't surprise me that it allowed for other formats, I've just
never seen them.
Bob
Yes, my mistake. As you can see in the example, it transferred 4
bytes.
No, I don't think so.
> I've never run across a 16 bit float.
The last time I used avr-gcc a float was 32 bits. I seriously doubt
that's changed in the past year or two.
> Every compiler I've worked with uses 32 bits for float (sign, 8 bit
> exp, 23 bit mantissa w/ implied MSB) and 64 bits for double.
Gcc on some platforms has a option to make doubles 32 bits also.
> It's been a long time since I read IEEE-754 and it wouldn't surprise
> me that it allowed for other formats, I've just never seen them.
IIRC, it only specifies the two formats (32 bits and 64 bits).
--
Grant Edwards grant.b.edwards Yow! Your CHEEKS sit like
at twin NECTARINES above
gmail.com a MOUTH that knows no
BOUNDS --
Bob wrote:
> I've never run across a 16 bit float. Every compiler I've worked
> with uses 32 bits for float (sign, 8 bit exp, 23 bit mantissa w/ implied
> MSB) and 64 bits for double.
SHARC DSP from Analog Devices supports 16-bit float in the hardware; it
is supported by tools as well.
> It's been a long time since I read IEEE-754
> and it wouldn't surprise me that it allowed for other formats, I've just
> never seen them.
Me uses self made 24-bit float class (16 bit mantessa + 8 bit exponent)
routinely; it is very handy when you work with 8-bit or 16-bit integer
machine.
Vladimir Vassilevsky
DSP and Mixed Signal Design Consultant
http://www.abvolt.com
>> It is mainly for storage. Unsigned char (8 bits) takes less space than
>> float (16 bits) or double (32 bits). We don't really care how the
>> compiler does it, but storage is important for a 1K SRAM chip.
> Last time I knew, that just cast the object into what you want, but it's
> not going to magically convert a FLOAT to a unsigned char..
Well, that only prove it's imperative that you get away from last time
you knew, into the real time we're in, and find better things to know.
You remember pretty much the opposite of the truth.
> Its only going to instruct the compiler that the contents of memory the
> "F" occupies is a unsigned char and simply moves the data from that
> from ever it is in memory to "u"
No. There's a statement involving a cast that would do that, but it's
_not_ the statement we've been discussing here.
> simply speaking..
> u = f; isn't the same as u = (unsigned char) f; where I come from..
Then you need to come from a different place.
> u = (unsigned char) f; simply tells the compiler to treat the object
> of "F" as if it was a char instead. No conversion is taking
> place here.
Wrong.
> As far as how the floats are implemented for the binary format of
> this compiler will dictate what value of data will be returned..
No, it won't. The platform's floating point format is almost always
irrelevant to the resulting value of this expression. Typically the
_only_ things relevant are the range of unsigned char, and the decision
made by the compiler implementor (or platform ABI) about what kind of
undefined behaviour to exhibit if the float's value is outside that range.
>Bob wrote:
>
>> I've never run across a 16 bit float. Every compiler I've worked
>> with uses 32 bits for float (sign, 8 bit exp, 23 bit mantissa w/ implied
>> MSB) and 64 bits for double.
>
>SHARC DSP from Analog Devices supports 16-bit float in the hardware; it
>is supported by tools as well.
Not exactly. The SHARC fpu operates on 32 or 40 bit data. A 16-bit
packed storage format is supported by the ISA using FPACK/FUNPACK
instructions which are special shifter operations.
The shifter can't access memory - only the register file - so you need
to load before unpacking and pack before storing. In the worst case -
an isolated operation on packed operands producing a packed result -
the (un)packing can add 80% overhead to the FPU operation. However,
because the SHARC is multiple issue and the shifter works in parallel
with the FPU, the overhead of (un)packing multiple values can be
amortized over longer FPU sequences.
>> It's been a long time since I read IEEE-754
>> and it wouldn't surprise me that it allowed for other formats, I've just
>> never seen them.
FWIW: IEEE 754-2008 now defines a standard 16-bit binary float format.
(see http://en.wikipedia.org/wiki/IEEE_754-2008)
>Me uses self made 24-bit float class (16 bit mantessa + 8 bit exponent)
> routinely; it is very handy when you work with 8-bit or 16-bit integer
>machine.
I recall some software FP libraries offering 16-bit floating point
operations back in the days when FP coprocessors were expensive
luxuries.
George
Well I may have had a brain scrub on that one, I'll admit to that how ever.
This will produced what I was talking about.
u2 = *(unsigned int *) &f;
I would be very surprised if the gcc-AVR compiler could handle that..
>> A typecast doesn't to at all what you think it does.
>
> Well I may have had a brain scrub on that one, I'll admit to that how ever.
> This will produced what I was talking about.
Yep.
> u2 = *(unsigned int *) &f;
>
> I would be very surprised if the gcc-AVR compiler could handle that..
I've used the gcc-avr compiler, and it will handle that just fine.
--
Grant
>Well I may have had a brain scrub on that one, I'll admit to that how ever.
> This will produced what I was talking about.
>
> u2 = *(unsigned int *) &f;
Yeah, that's the sort of construct that has the effect you were
thinking about. It's incredibly non-portable, ill-defined, and "How
lucky do you feel today?"
If you do it the other way (e.g.)
f2 = *(unsigned float *) &u2;
thing could be even worse, due to misalignment issues. Segfaults are
entirely possible on many architectures.
--
Dave Platt <dpl...@radagast.org> AE6EO
Friends of Jade Warrior home page: http://www.radagast.org/jade-warrior
I do _not_ wish to receive unsolicited commercial email, and I will
boycott any company which has the gall to send me such ads!
I am not sure if such statements are well-defined in terms of C
standards, but they are well-defined in practice. You are reading the
underlying memory pattern for the float. It's going to be dependent on
the compiler/library combination for the format (though almost all
compilers, including avr-gcc, use IEEE format), the endianness, and
possibly alignment issues of the particular cpu.
But it is certainly valid and consistent to use pointer casts like this.
If you've ever used memcpy to copy a struct containing floats, you've
effectively done this already. And you'll see code like that in the
library implementation of software floating point routines - that's how
the floating point data is broken up and interpreted to carry out the
calculations in integer operations.
> If you do it the other way (e.g.)
>
> f2 = *(unsigned float *) &u2;
>
> thing could be even worse, due to misalignment issues. Segfaults are
> entirely possible on many architectures.
>
I haven't seen an "unsigned float" before - guess that's a typo.
But yes, you always have to look out for alignment issues when mixing
pointers to objects of different sizes. Of course, on an 8-bit avr,
everything is aligned!
What are you expecting when you say "handle that"?
If you are expecting the standard C behaviour - that u2 will get part of
the underlying memory pattern of the float - then avr-gcc will handle it
perfectly well, just like any other C compiler.
But if you are equally wrong about this sort of cast as you were with
non-pointer casts, and think the compiler should do a floating-point to
integer conversion, then you will be disappointed - that's not how C
works, and therefore not how avr-gcc works.