Go Down

### Topic: From float to seperate INTs - in an elegant manner :-) (Read 3027 times)previous topic - next topic

#### point5

##### May 04, 2012, 10:01 pm
Hi, I stumbing about a bit on this one.... trying to find an elegant solution to converting a float with one decimal place to 3 sperate integer values... so:

float value = 24.8
becomes
int a = 2
int b = 4
int c = 8

Thanks for any pointers.

#### 3dprinter

#1
##### May 04, 2012, 10:52 pm
Code: [Select]
`float f = 24.8 ;int a ;int b ;int c ;a = int(f)/10 ; b= int(f)%10 ; c=int((f-int(f))*10) ;`

#### el_supremo

#2
##### May 04, 2012, 11:27 pm
The fraction needs to be rounded, otherwise the .8 will set c=7
Use this:
Code: [Select]
`c=int((f-int(f)+0.05)*10);`

Pete
Don't send me technical questions via Private Message.

#### 3dprinter

#3
##### May 05, 2012, 02:29 pm
Damn, you're right ! Didnt test it. The cause is that 24.8 is (probably) internally stored as 24.7999999... due to the finite limit of representing decimal fractions in binary.

Well, in an effort to keep my pride intact and to keep it "elegant" use the round function for the last bit
Code: [Select]
`c=round((f[n]-int(f[n]))*10) ;`

#### michael_x

#4
##### May 05, 2012, 02:50 pmLast Edit: May 05, 2012, 03:53 pm by michael_x Reason: 1
"Elegant" would also be to sprintf the float into a char[] with exactly the format you want ("%4.1f"),
and then simply get the individual digits ( - '0' )

BTW: Strictly seen (and visible on machines where float and double are different), there is no float x with ( x == 24.8 )

#### PaulS

#5
##### May 05, 2012, 03:28 pm
Quote
"Elegant" would also be to sprintf the float into a char[] with exactly the format you want ("%4.1f"),
and then simply get the individual digits ( - '0' )

Well, that might be elegant, but it won't work. The %f format specifier does not work on the Arduino.

#### michael_x

#6
##### May 05, 2012, 03:54 pm

The %f format specifier does not work on the Arduino.

oops !  Thanks

#### point5

#7
##### May 06, 2012, 06:44 pm
Thanks folks - very nice solution with elegance built in... off to try it now :-)

#### robtillaart

#8
##### May 06, 2012, 07:34 pm

do you need the individual digits as int or as a char or..... as a byte?  NB a char/byte is large enough to hold one digit  (byte == uint8_t)

The code sofar does not handle negative numbers (see code below), don't know if they can occur - just like numbers bigger than 99?

so I did an alternative version that
+ handle negatives
+ uses less floating point operations.
+ can easily be extended to larger numbers as it uses an array for the digits
+ has room for optimization
Code: [Select]
`void setup(){  Serial.begin(9600);  float f = 24.8;  int a = int(f)/10;  int b = int(f)%10;  int c = round((f-int(f))*10);  Serial.println(f,4);  Serial.println(a,DEC);  Serial.println(b,DEC);  Serial.println(c,DEC);  f = -24.8;  a = int(f)/10;  b = int(f)%10;  c = round((f-int(f))*10);  Serial.println(f,4);  Serial.println(a,DEC);  Serial.println(b,DEC);  Serial.println(c,DEC);  // array version#define DIGITS 3  int ar[DIGITS];  f = -24.8;  int t = round(f*10);  int s = 1;  if (t < 0) {    t = -t;     s = -1;   }  for (int i=DIGITS-1; i>=0; i--)  {    ar[i] = t %10;    t /=10;  }  Serial.println(f,4);  if (s==-1) Serial.println("-");  for (int i=0; i<DIGITS; i++)  {    Serial.println(ar[i],DEC);  }  f = 24.8;  t = round(f*10);  s = 1;  if (t < 0) {    t = -t;     s = -1;   }  for (int i=DIGITS-1; i>=0; i--)  {    ar[i] = t %10;    t /=10;  }  Serial.println(f,4);  if (s==-1) Serial.println("-");  for (int i=0; i<DIGITS; i++)  {    Serial.println(ar[i],DEC);  }}void loop(){}`

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### point5

#9
##### May 06, 2012, 10:41 pm
Very nice too :-).... if this function is useful to lots of people I guess it will end up as a library one day.

My aim with all this is to read temperature from a TMP275 I2C sensor (haven't got that working yet - tried modifying the TMP102 library but I'm still missing something important) as a single decimal point value, say 12.3 and then writing this to 3 shift registers as a series of segment bytes controlling 3 seven segment digits.

I don't know if this is the best way of doing it but I thought that if I could seperate out the number into INTs I could then run each digit through some case statements to assign the right segment bytes before writing these to the shift registers.

#### michael_x

#10
##### May 07, 2012, 10:17 am
Thanks for bringing this TMP275 I2C sensor to my attention. Very interesting data sheet.
(http://pdf1.alldatasheet.com/datasheet-pdf/view/161348/BURR-BROWN/TMP275.html)

However, I understand the sensor itself does not provide float numbers ( and especially nothing with rounding issues like 24.8 ).

If you really need floats for some other cases, I'd suggest you don't round yourself, but work with the exact reading.
(no rounding issue with e.g. float t=24.75; )

If you don't need floats except for displaying more accuracy than full degrees, I'd simply interpret the hi byte as an integer temp, and translate the lower bits separately. The possible values depend on your chosen accuracy 9 .. 12 bit.
With 9 bit there will be only two cases:  ".0" or ".5"
With full 12 bit accuracy, you mit pick the desired display digit from a char subdecimal[] = "0112233455678899"; with 16 entries for the least significant nibble (0x0 .. 0xF) as index.

#### point5

#11
##### May 07, 2012, 10:27 am
Hi Michael,

Thanks for the info - that would certainly be one way to do it - I guess I was hoping to find/translate a library for the TMP275 which would have been spitting out a float value.... perhaps my next task should be to get the TMP275 working and go from there :-)

#### odometer

#12
##### May 07, 2012, 07:41 pm
Why not just multiply by 10, handle as an integer, and then drop in a decimal point (and, if necessary, a leading zero)?

Go Up