Casting int16_t to float

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all friends,

 

I have a problem that I dont't understand. May be my C-knoledge is not the best.

The problem is that I have int16_t variables and when casting to float, it results in NaN if the variable is 0.

What is the problem?

#include <avr/io.h>
#include <math.h>
void filter(float);

int16_t var;
var = 0;

int main(void){
	filter((float)var);
}

filter (float var){
code...
}

 

Last Edited: Mon. Nov 28, 2016 - 08:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This has nothing to do with Studio bugs itself which this forum is for, I'll move it to general programming.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can't write var = 0 outside of a function.
You can say int16_t var = 0 i.e. an initialised definition.
.
I am not at a PC. Your cast code looks fine to me.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi.

 

The same problem with var inside a function.

#include <avr/io.h>
#include <math.h>
void filter(float);

int16_t var;


int main(void){
    var = 0;
    
	filter((float)var);
}

filter (float var){
code...
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How are you observing "NaN" anyway? I would suspect the debugger you are using interpreting the value incorrectly.

 

As David says, there is nothing wrong in the code above.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think we need to see all the code in a small example.  the following works fine.  this example runs on 328P Xplained mini.  baud 38400

 

/*
 * GccApplication328a.c
 *
 * Created: 11/28/2016 8:06:09 PM
 * Author : jstampfl
 */ 


#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
volatile int outpos0;
volatile char outbuf0[80];
void prstr0(char* buf);
float filter (float fvar);


int main(void)
{
	char string[80];
	UBRR0L =25; // 38400
	UCSR0B = (1 << RXEN0) | (1 << TXEN0); //Turn on RX/TX
	UCSR0B |= (1 << RXCIE0 ) | (1 << TXCIE0);   // Enable the USART Tx & Rx Complete interrupt
	sei();
	_delay_ms(1000);
	int16_t var = 0;
	int nvar = 1;  //just to show it changes
	float outit;
	outit = filter((float) var);
	nvar = (int) outit;
	itoa (nvar,string,10);
	prstr0(string);
    /* Replace with your application code */
    while (1) 
    {
    }
}

float filter (float fvar)
{
	float a = 2.7;
	fvar = fvar * a;
	return fvar;
}

ISR ( USART_TX_vect )
{
	if ( outpos0 != 0)
	{
		if (outbuf0[outpos0] == 0)
		{
			outpos0 = 78;
		} else UDR0 = outbuf0[outpos0];
		if (outpos0 > 0 && outpos0 < 78)
		{
			outpos0++;
		}
		else
		{
			
			outpos0 = 0;
		}
	}
}
void prstr0(char* buf)
{
	while (outpos0 > 0)
	{
		_delay_us(2);
	}
	strcpy((char*)outbuf0,buf);
	UDR0 = outbuf0[0];
	outpos0 = 1;
}

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	outit = filter((float) var);
	nvar = (int) outit;
	itoa (nvar,string,10);

How does that prove it works? You are converting the returned float back to an int?!? Why don't you just sprintf("%f") rather than trying to use itoa()?

 

Also how does multiplying 0 by 2.7 (or anything come to that) prove that it works? 0 * anything is 0.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I observ the Nan in the debugger.

But, I use 6 int16_t variables as input to a IMU filter to find the pitch angle from gyros (in 1/10 deg/s) and  accelerometers (in 1/5000 g). If the angle changd more than 2 degree a LED it turned on.

When that the variables is 0, the code is not working.

I have found a workaround, as the input values from gyros and accelerometer is not stabble, by never using 0 as parameter.

However, sending all gyro values as 0.0 to the function works.

So, does anybody knows what is wrong?

    while ( true ) {
        vTaskDelay(10);
            if (Gyro_x == 0) Gyro_x += 1;
            if (Gyro_y == 0) Gyro_y += 1;
            if (Gyro_z == 0) Gyro_z += 1;
            if (Acc_x == 0) Acc_x +=  1;
            if (Acc_y == 0) Acc_y += 1;
            if (Acc_z == 0) Acc_z += 1;
       filterUpdate(
		//	   		0.0, 0.0, 0.0,
					 ((float)Gyro_x)/(10.0*RAD_FACTOR), (float)(Gyro_y)/(10.0*RAD_FACTOR), (float)(Gyro_z)/(10.0*RAD_FACTOR),
                     (float)(Acc_x)/5000.0, (float)(Acc_y)/5000.0, (float)(Acc_z)/5000.0);
            }

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Asle wrote:
I observ the Nan in the debugger.
Then like I say, it could be the debugger at fault - which debugger are you talking about? If you look at the asm code which 4 registers are the float value held in? What are the actual contents of those 4 registers?

 

NaN is 0x7FFFFFFF so three of the registers should hold 0xFF and the "high" register should hold 0x7F if it is really NaN.

 

I am willing to bet you find 0x00 in all four registers.

 

(if you don't then post the Asm for the line that sets up the parameters to call filter())

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clawson asks " Why don't you just sprintf("%f") rather than trying to use itoa()?"

 

Main reason is that it adds 1300 bytes to my program.

 

 

 


 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it adds 1300 bytes to my program.

But how much hair does it save you? OK you have a lot more than me but still better save it.  wink

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I have made a small test program and still I cannot understand that the caasting of int16_t to float is correct of the value is 0.

#include <avr/io.h>
#include <math.h>
uint8_t IsFloat(float);

int main(void)
{
	volatile uint8_t isfloat0, isfloat1, isnotfloat;
	volatile int16_t gx;
	gx = 0;

	isnotfloat = IsFloat((float)gx);	//returns 0
	gx = 1;
	isfloat0 = IsFloat((float)gx);		//returns 1
	isfloat1 = IsFloat(1.0);			//returns 1
	
	while(1){
	}
}

/*************************************************************************
*
*  Check for legal float
*
*************************************************************************/
uint8_t IsFloat(float A){
	int32_t exp;
	// A NAN has an exponent of 255 (shifted left 23 positions) and
	// Denormalized has an exponent set to 0
	exp = *(int32_t*)&A & 0x7F800000L;
	if ( exp && (exp != 0x7F800000L) ) {
		return(1);
	}
	return(0);
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I say I suspect this is just your debugger (they aren't perfect!). Did you try what I suggested:

clawson wrote:
If you look at the asm code which 4 registers are the float value held in? What are the actual contents of those 4 registers? NaN is 0x7FFFFFFF so three of the registers should hold 0xFF and the "high" register should hold 0x7F if it is really NaN.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I expect that your function is correct.

 

But don't understand the problem, there should be no difference if you do "(float) 0" or "0.0"

 

They should give the same result

And because gx is known to be 0 at compile time I would expect the compile will insert the float constant for 0.0 into the code.

 

Take a look at the ASM output.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
there should be no difference if you do "(float) 0" or "0.0"
Good point! That allows me to build this test code:

$ cat avr.c
#include <avr/io.h>
#include <avr/eeprom.h>

float filter(float);

float result;

int main(void)
{
    result = filter((float)0);
}

$ avr-gcc -c -mmcu=atmega16 -g -Os avr.c -o avr.o
$ avr-objdump -S avr.o

avr.o:     file format elf32-avr


Disassembly of section .text:

00000000 <main>:

float result;

int main(void)
{
    result = filter((float)0);
   0:	60 e0       	ldi	r22, 0x00	; 0
   2:	70 e0       	ldi	r23, 0x00	; 0
   4:	cb 01       	movw	r24, r22
   6:	0e 94 00 00 	call	0	; 0x0 <main>
   a:	60 93 00 00 	sts	0x0000, r22
   e:	70 93 00 00 	sts	0x0000, r23
  12:	80 93 00 00 	sts	0x0000, r24
  16:	90 93 00 00 	sts	0x0000, r25
}
  1a:	08 95       	ret

As can be seen here the register setup before the call is simply to load the entire r25:r24:r23:r22 with 0x00000000. There is no sign of 0x7FFFFFFF (NaN) here. Exactly what I was expecting to see.

 

I think the debugger is simply interpreting 0x00000000 incorrectly as NaN instead of 0.0

 

One day I'll try this in AS7 and know for sure.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I stepped through your program in AS7 Simulator.

I added the volatile qualifier to make A show up in the Locals window.

 

exp = 0x00000000 for A = 0.0

exp = 0x3f800000 for A = 1.001938

 

The exercise is very trivial.   You just need to Google for the float format.

 

More importantly,  say what you really want to do.    It should be very straightforward to process the output from an accelerometer.

Even if you go backwards and forwards through f-p and integer calculations.

 

Personally,  I would like to make it simple to understand.   Easier to maintain !!

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Still waiting to here where he is seeing "NaN" then. The original problem report here was:

Asle wrote:
it results in NaN if the variable is 0.

Clearly it does not then?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so I looked at wiki:

Zero[edit]

The number zero is represented specially:

sign = 0 for positive zero, 1 for negative zero.

biased exponent = 0.

fraction = 0.

I guess that it's this way so you can fill with 0 to clear.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
float fvar;
unsigned char frep[sizeof(fvar)];
...
memcpy(frep, &fvar, sizeof(frep));
unsigned count=0
for(unsigned j=0; j< sizeof(frep); ++j)  count+=!!(frep[j]);
do something with count

 

Iluvatar is the better part of Valar.