### Author Topic: Arduino and decimal numbers  (Read 9741 times)

0 Members and 1 Guest are viewing this topic.

#### Red Squirrel

• Super Contributor
• Posts: 2391
• Country:
##### Arduino and decimal numbers
« on: July 03, 2015, 07:16:36 am »
I'm working on a mini project that will require to display numerical info on a LCD (volts and amps).  To keep things clean I want the number to always take up the same amount of digits.  Going for 0.00 format where decimal point can change.   So if the value is 0.1 It will display 0.10, if it's 22 it will display 22.0 etc...   A value over 1000 would simply show 999 but it's not likely to reach that far as that would involve magic smoke assuming the readings are actually right.

Is there an easy way to do this, or do I have code the logic myself using string manipulation?

If it matters, I'm coding the MCU directly using Arduino software/libs and not actually using an arduino board.

#### Mr.B

• Supporter
• Posts: 1058
• Country:
##### Re: Arduino and decimal numbers
« Reply #1 on: July 03, 2015, 07:21:29 am »
...or do I have code the logic myself using string manipulation?

AFAIK, yes, this is the only way to do it in Arduino.
Case statements and string manipulation.

Edit: thinking in wrong language... Switch statements...
Time is the overseer of all things.

#### obiwanjacobi

• Frequent Contributor
• Posts: 968
• Country:
• What's this yippee-yayoh pin you talk about!?
##### Re: Arduino and decimal numbers
« Reply #2 on: July 03, 2015, 09:16:19 am »
Perhaps you find my TextWriter class useful? It does not do as you describe but it may 'inspire' you...

http://atl.codeplex.com/SourceControl/latest#Source/Code/ArduinoTemplateLibrary/TextWriter.h

[2c]
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!

#### hamster_nz

• Super Contributor
• Posts: 2197
• Country:
##### Re: Arduino and decimal numbers
« Reply #3 on: July 03, 2015, 10:05:25 am »
You could always put it into a 999.99 format field, and then start displaying from a different place depending on if there are any leading zeros.

Code: [Select]
char *start_from;char string[7]; // Allow an extra byte for terminating null char// This can be done smarter, and depends on the data type for 'a'// I'm incorrectly assuming it is a floating point number.string[0] = (a/100)%10 + '0';string[1] = (a/10)%10 + '0';string[2] = (a/1)%10 + '0';string[3] = '.';string[4] = (a*10)%10 + '0';string[5] = (a*100)%10 + '0';// Work out where to display fromif(string[0] = '0')   start_from = string+0;else if(string[1] = '0')   start_from = string+1;else   start_from = string+2;// Add a null terminator to the string.start_from[4] = ''\0';output_to_the_display(start_from);
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.

#### f1rmb

• Regular Contributor
• Posts: 180
• Country:
##### Re: Arduino and decimal numbers
« Reply #4 on: July 03, 2015, 12:06:01 pm »
Hi,

you could use the undocumented function dtostrf() (it's part of AVR, check stdlib.h).

Cheers.
---
Daniel

#### senso

• Frequent Contributor
• Posts: 897
• Country:
##### Re: Arduino and decimal numbers
« Reply #5 on: July 03, 2015, 12:56:03 pm »
Wont printf be able to do that with the formating options?

#### MarkF

• Super Contributor
• Posts: 1529
• Country:
##### Re: Arduino and decimal numbers
« Reply #6 on: July 07, 2015, 01:03:39 am »
If you're programming in C, just do a sprintf command:

Code: [Select]
float value;char line[32];// set value...// format for output (use just "%.2f" for no leading zero)sprintf(line,"%0.2f",value);// send line to the display...

#### fake-name

• Regular Contributor
• Posts: 74
##### Re: Arduino and decimal numbers
« Reply #7 on: July 07, 2015, 01:26:41 am »

you could use the undocumented function dtostrf() (it's part of AVR, check stdlib.h).

What part of it's undocumented? It's not documented in the arduweenie stuff, but their documentation is garbage anyways.

#### miguelvp

• Super Contributor
• Posts: 5549
• Country:
##### Re: Arduino and decimal numbers
« Reply #8 on: July 07, 2015, 01:30:35 am »
Regarding printf and sprintf.

I guess if you can take the about 2KB overhead of the function it would be a solution, but not everyone wants to waste that much space for just printing some characters.

Maybe you have space now, but what happens when your program needs to do more?

#### MarkF

• Super Contributor
• Posts: 1529
• Country:
##### Re: Arduino and decimal numbers
« Reply #9 on: July 07, 2015, 01:49:54 am »
Regarding printf and sprintf.

I guess if you can take the about 2KB overhead of the function it would be a solution, but not everyone wants to waste that much space for just printing some characters.

Maybe you have space now, but what happens when your program needs to do more?

If you want to do everything in integers, keep all your values * 100.  Then when you want to display them, divide by 100 to get the integer part and do a modulo 100 to get the decimal part.

#### hamster_nz

• Super Contributor
• Posts: 2197
• Country:
##### Re: Arduino and decimal numbers
« Reply #10 on: July 07, 2015, 02:05:32 am »
If you're programming in C, just do a sprintf command:

test1() performs the conversion, test2() uses sprintf():

Code: [Select]
#include <stdio.h>void test1(float value) {  char *start_from;  char string[7]; // Allow an extra byte for terminating null char  unsigned a;  // 'a' is 100*value, but restricted in range    if(value > 999.0) a = 99999;  else if(value < 0) a = 0;  else a = value * 100;  // Extract the digits  string[6] = a%10 + '0'; a /= 10;  string[5] = a%10 + '0'; a /= 10;  string[4] = '.';  string[3] = a%10 + '0'; a /= 10;  string[2] = a%10 + '0'; a /= 10;  string[1] = a%10 + '0';   string[0] = ' ';  // Work out where to display from  start_from = string;  if(string[1] != '0')    start_from += 0;  // Leading space, 3 digits  else if(string[2] != '0')    start_from += 2;  // Two digits, one decimal  else    start_from += 3;  // One digit, two decimals  // Add a terminator  start_from[4] = '\0';  // Display it  printf("Test1 is '%s'\r\n",start_from);}void test2(float a){  char line[32];  sprintf(line,"%0.2f",a);  printf("Test2 is '%s'\r\n",line);}int main(int argc, char *argv[]){  float value = 0.1;  printf("Input is %f\r\n",value);  test1(value);  test2(value);  puts("\r\n");  value = 22.0;  printf("Input is %f\r\n",value);  test1(value);  test2(value);  puts("\r\n");  value = 100.0;  printf("Input is %f\r\n",value);  test1(value);  test2(value);  puts("\r\n");  value = 123456789.0;  printf("Input is %f\r\n",value);  test1(value);  test2(value);  puts("\r\n");  value = -1.0;  printf("Input is %f\r\n",value);  test1(value);  test2(value);  puts("\r\n");}
And the output:

Code: [Select]
Input is 0.100000Test1 is '0.10'Test2 is '0.10'Input is 22.000000Test1 is '22.0'Test2 is '22.00'Input is 100.000000Test1 is ' 100'Test2 is '100.00'Input is 123456792.000000Test1 is ' 999'Test2 is '123456792.00'Input is -1.000000Test1 is '0.00'Test2 is '-1.00'
Also, using sprintf() just once will increase your program's code size quite a bit, but if you using it elsewhere then why not...
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.

#### miguelvp

• Super Contributor
• Posts: 5549
• Country:
##### Re: Arduino and decimal numbers
« Reply #11 on: July 07, 2015, 02:06:27 am »
Regarding printf and sprintf.

I guess if you can take the about 2KB overhead of the function it would be a solution, but not everyone wants to waste that much space for just printing some characters.

Maybe you have space now, but what happens when your program needs to do more?

If you want to do everything in integers, keep all your values * 100.  Then when you want to display them, divide by 100 to get the integer part and do a modulo 100 to get the decimal part.

I wasn't talking about support for %f but just using sprintf even without float support will add around 2KB to your program. Maybe that's not an issue but it could be one.

And if you just want to print some numbers, why do you want to carry the sprintf extra baggage?

#### f1rmb

• Regular Contributor
• Posts: 180
• Country:
##### Re: Arduino and decimal numbers
« Reply #12 on: July 07, 2015, 04:04:44 am »

you could use the undocumented function dtostrf() (it's part of AVR, check stdlib.h).

What part of it's undocumented? It's not documented in the arduweenie stuff, but their documentation is garbage anyways.

What part ? Seriously ?

daniel@daniel-ThinkPad-X201 ~ $man dtostrf No manual entry for dtostrf Since when "dtostrf" or "dtostre" are C standard (stdlib) . It's an AVRism, and if you don't jump reading stdlib.h to see the function prototype, no way you miraculously think of it. BTW, nice and useful comment To the OP, I share the same advice, try to avoid sprintf() if possible, it's a memory hog. Cheers. --- Daniel « Last Edit: July 07, 2015, 04:06:55 am by f1rmb » #### miguelvp • Super Contributor • Posts: 5549 • Country: ##### Re: Arduino and decimal numbers « Reply #13 on: July 07, 2015, 04:19:42 am » Don't look, kind of looks like documentation to me: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdlib_1ga060c998e77fb5fc0d3168b3ce8771d42.html Just because it's not on your man pages doesn't mean it's undocumented #### f1rmb • Regular Contributor • Posts: 180 • Country: ##### Re: Arduino and decimal numbers « Reply #14 on: July 07, 2015, 04:33:51 am » Don't look, kind of looks like documentation to me: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdlib_1ga060c998e77fb5fc0d3168b3ce8771d42.html Just because it's not on your man pages doesn't mean it's undocumented Once again, it's not a C standard function but an AVRism, unlike *printf(), or did I missed something for the last 25 years ? If it's not in man pages, it doesn't even exists Cheers. --- Daniel #### miguelvp • Super Contributor • Posts: 5549 • Country: ##### Re: Arduino and decimal numbers « Reply #15 on: July 07, 2015, 04:48:24 am » hmm, undocumented to me means there is no documentation available, and nothing to do with being part of the C standard libraries. I always thought that even standard C libraries are not really part of C, since they are just libraries, but hey, when in Rome! #### SL4P • Super Contributor • Posts: 2117 • Country: • There's more value if you figure it out yourself! ##### Re: Arduino and decimal numbers « Reply #16 on: July 07, 2015, 05:14:34 am » For all the hate levelled at printf() and it's derivatives - I love it, as it let's me get the output results I want i a convenient and standardized manner. decimals, justification, fill - everything you want today or have wanted for the last 30 years! Yes it occupies memory, and if you want to do just one specific format - write your own output function - otherwise stop complaining! Don't ask a question if you aren't willing to listen to the answer. #### Red Squirrel • Super Contributor • Posts: 2391 • Country: ##### Re: Arduino and decimal numbers « Reply #17 on: July 07, 2015, 10:02:11 am » Thanks for the ideas, I'll play around with those. Goal is to probably use ints throughout most of the program, given the ADC produces a value from 1 to 1024 it's probably easier for me to times it by a certain value so I get a number in the 10,000's then just add a decimal point at the right spot. I read somewhere that division is slower on MCUs so to try to avoid it. Probably not a big issue for this particular app but may as well try to use good habits. I'll try to avoid springf as well. Come to think of it all I really need to do here is get the value converted to a string, then I can do a char by char analsys to decide what digits to display and where to put to decimal. #### SL4P • Super Contributor • Posts: 2117 • Country: • There's more value if you figure it out yourself! ##### Re: Arduino and decimal numbers « Reply #18 on: July 07, 2015, 10:21:39 am » I read somewhere that division is slower on MCUs so to try to avoid it. Keep in mind that bit shifting / rotating is very fast, and you can do quite a lot of maths with combinations of the above... also as you said - think (integer x 1xxx), then plonk a decimal back where it belongs! Don't ask a question if you aren't willing to listen to the answer. #### MarkF • Super Contributor • Posts: 1529 • Country: ##### Re: Arduino and decimal numbers « Reply #19 on: July 07, 2015, 11:22:22 am » I read somewhere that division is slower on MCUs so to try to avoid it. Keep in mind that bit shifting / rotating is very fast, and you can do quite a lot of maths with combinations of the above... also as you said - think (integer x 1xxx), then plonk a decimal back where it belongs! Most modern compilers know this too. Don't try to out smart them. Write your code the most straight forward way and then look at the generated assembly if you need to try to optimize it yourself. #### westfw • Super Contributor • Posts: 3125 • Country: ##### Re: Arduino and decimal numbers « Reply #20 on: July 08, 2015, 07:34:50 am » Quote Test2 is '22.00' I'll point out that this is NOT the desired output. I haven't done a lot with floating point printf, but I couldn't immediately come up with a printf format that WOULD produce the correct results. (Nor a fortran format, either :-)) Now that several people have suggested a format that doesn't work, I guess I'll ask explicitly: IS there a format that will produce those outputs? IIRC, the OP wanted: 0.01 0.22 3.33 44.4 555 6666 9999 #### MarkF • Super Contributor • Posts: 1529 • Country: ##### Re: Arduino and decimal numbers « Reply #21 on: July 08, 2015, 08:02:08 am » Quote Test2 is '22.00' I'll point out that this is NOT the desired output. I haven't done a lot with floating point printf, but I couldn't immediately come up with a printf format that WOULD produce the correct results. (Nor a fortran format, either :-)) Now that several people have suggested a format that doesn't work, I guess I'll ask explicitly: IS there a format that will produce those outputs? IIRC, the OP wanted: 0.01 0.22 3.33 44.4 555 6666 9999 Short answer: NO. Long answer: He would need to check the magnitude of the variable before doing the format. Code: [Select] float val;char txt[32];if (val < 10.0) { sprintf(txt,"%4.2f",val); // format with 2 decimal digits}else if (val < 100.0) { sprintf(txt,"%4.1f",val); // format with 1 decimal digit}else if (val < 1000.0 { sprintf(txt,"%4.0f",val); // format with 0 decimal digits}else { sprintf(txt," 999"); // display 999 if greater than or equal to 1000} #### hamster_nz • Super Contributor • Posts: 2197 • Country: ##### Re: Arduino and decimal numbers « Reply #22 on: July 08, 2015, 10:11:42 am » Code: [Select] float val;char txt[32];if (val < 10.0) { sprintf(txt,"%4.2f",val); // format with 2 decimal digits}else if (val < 100.0) { sprintf(txt,"%4.1f",val); // format with 1 decimal digit}else if (val < 1000.0 { sprintf(txt,"%4.0f",val); // format with 0 decimal digits}else { sprintf(txt," 999"); // display 999 if greater than or equal to 1000} Annoying corner case time ... 99.99 is less than 100.0 ,but will produce a 5 character output with a "%4.1f" format due to rounding. Grrr.. Code: [Select] $ cat a.c#include <stdio.h>int main(int argc, char *argv){   printf("%4.1f\r\n",(float)99.5);   printf("%4.1f\r\n",(float)99.99);}$gcc -o a a.c ; ./a$ ./a99.5100.0
so you also need to use limits that allow for the effects of rounding.

Also, with an embedded display when you jump form "9.99" to "10.0" and back again rapidly the display can become hard to read. This can
be really non-trivial to solve.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.

#### MarkF

• Super Contributor
• Posts: 1529
• Country:
##### Re: Arduino and decimal numbers
« Reply #23 on: July 08, 2015, 05:23:39 pm »
I guess the easiest way would be to truncate the value before formatting it:

Code: [Select]
void toAscii(int x, int y, float val) {   char txt[16];   if (val < 10.)       val = floor(val*100.)/100.;   else if (val < 100.)      val = floor(val*10.)/10.;   else      val = floor(val);   if (val < 10.)       sprintf(txt,"%4.2f",val);   else if (val < 100.)       sprintf(txt,"%4.1f",val);   else if (val < 1000.)       sprintf(txt,"%4.0f",val);   else       sprintf(txt," 999");   drawTextToDisplay(x,y,txt);}

#### NANDBlog

• Super Contributor
• Posts: 4563
• Country:
• Current job: ATEX certified product design
##### Re: Arduino and decimal numbers
« Reply #24 on: July 08, 2015, 05:32:46 pm »
Regarding printf and sprintf.

I guess if you can take the about 2KB overhead of the function it would be a solution, but not everyone wants to waste that much space for just printing some characters.

Maybe you have space now, but what happens when your program needs to do more?

If you want to do everything in integers, keep all your values * 100.  Then when you want to display them, divide by 100 to get the integer part and do a modulo 100 to get the decimal part.

I wasn't talking about support for %f but just using sprintf even without float support will add around 2KB to your program. Maybe that's not an issue but it could be one.

And if you just want to print some numbers, why do you want to carry the sprintf extra baggage?
Most code for Arduino will contain printf for debugging reason anyway, so I'm not sure why would be a problem to use it. The whole reason for using a Arduino is to reduce the time required to connect the stuff and write the code, when efficiency is irrelevant.

Smf