Good day,
Just about finished a project and got to do the floating point stuff now, but stuck on a snag with math.h,
my function is to turn a level into a volume for a circular water tank:
/** @brief Hardware abstraction for volume @details Using the level() function to determine the volume based on the profile of the tank. Based on a piecwise defined function for (I) level < radius and (II) level >= radius. with theta = (I) 2*acos( (r-h)/r) , (II) 2*acos( (2r-h)/r ) area = (I) r^2(theta - sin(theta))/2, (II) pi*r^2-r^2(theta - sin(theta))/2 @param Level in mm @retval water_volume in milli litres */ uint16_t volume( uint16_t level ){ double theta; double volume; if ( level >= (TANK_RADIUS/2) ) { theta = 2*acos( (TANK_RADIUS - level )/TANK_RADIUS); volume = TANK_LENGTH*( TANK_RADIUS*TANK_RADIUS*(theta - sin(theta))/2); } else if (level <= TANK_RADIUS) { theta = 2*acos( (2*TANK_RADIUS - level )/TANK_RADIUS); volume = TANK_LENGTH*(TANK_RADIUS*TANK_RADIUS*(M_PI - (theta - sin(theta))/2)); } else { //level is greater than what it should be so return NOTHING or ... max! volume = TANK_LENGTH*TANK_RADIUS*TANK_RADIUS*M_PI; } return (uint16_t)(volume+0.5); }
with makefile flags and stuff:
CFLAGS = -c -g -Os -Wall -w -ffunction-sections -fdata-sections -mmcu=$(MCU) \ -DF_CPU=$(F_CPU)L CPPFLAGS = $(CFLAGS) -fno-exceptions LDFLAGS = -Os -Wl,--gc-sections -mmcu=$(MCU) -lm HEXFLAGS = -O ihex -R .eeprom
gives this error on compilation:
- linking .build/project.elf (gcc)
/usr/lib/gcc/avr/4.7.2/../../../avr/lib/avr5/libc.a(fp_arccos.o):../../../libm/fplib/fp_arccos.S:76: relocation truncated to fit: R_AVR_13_PCREL against symbol `__subsf3' defined in .text section in /usr/lib/gcc/avr/4.7.2/avr5/libgcc.a(_addsub_sf.o)
/usr/lib/gcc/avr/4.7.2/../../../avr/lib/avr5/libc.a(fp_powsodd.o):../../../libm/fplib/fp_powsodd.S:59: relocation truncated to fit: R_AVR_13_PCREL against symbol `__mulsf3' defined in .text section in /usr/lib/gcc/avr/4.7.2/avr5/libgcc.a(_mul_sf.o)
/usr/lib/gcc/avr/4.7.2/../../../avr/lib/avr5/libc.a(fp_powsodd.o):../../../libm/fplib/fp_powsodd.S:69: relocation truncated to fit: R_AVR_13_PCREL against symbol `__mulsf3' defined in .text section in /usr/lib/gcc/avr/4.7.2/avr5/libgcc.a(_mul_sf.o)
collect2: error: ld returned 1 exit status
make: *** [.build/project.elf] Error 1
*** Failure: Exit code 2 ***
The fault can be replicated with the smallest snippet being:
accos(1.1)
So clearly is related to the compiler/linker believing that the argument to accos() will not be in the domain [-1,1].
In my code I am fairly certain this will always be so.
What can I do?
Will my returned value really be a uint16_t truncation of the floating point value. IS there a more efficient way.
As a corollary, is it more efficient to use an analytic formula for volume, or would it be more efficient to do numeric integration considering at most it would be 500 iterations of a function involving square roots and squares.
Thanks all
Jasper