Float To String - Flash memory consumption

Post here first, or if you can't find a relevant section!
Post Reply
roniin
Posts: 7
Joined: Mon May 04, 2020 6:13 pm

Float To String - Flash memory consumption

Post by roniin »

In my program I have to convert the Float variable to String. I know two methods in Arduino. I was surprised by the memory consumption needed for this! Summary of my tests:
1. STM32F103C8, Official core 1.9.0 Compilation of an empty sketch.
Flash 9760 (14%), Ram 820 (4%)

2. STM32F103C8, Official core 1.9.0 dtostrf

Code: Select all

float f;
String s;

void setup() {
Serial.begin(9600);
f = 1.23;
}

void loop() {
    char buforS[9];
    dtostrf(f, 7 ,2 , buforS);
    //s = String(f, 2);
    //Serial.print(f, 4);
}
Flash 14240 (21%), Ram 820 (4%)

3. STM32F103C8, Official core 1.9.0 s = String(f, 2);
Flash 14412 (21%), Ram 820 (4%)

4. STM32F103C8, Rogers core 2020.5.16 Compilation of an empty sketch.
Flash 18356 (28%), Ram 4256 (20%)

5. STM32F103C8, Rogers core 2020.5.16 dtostrf
Flash 34536 (52%), Ram 4312 (21%)

6. STM32F103C8, Rogers core 2020.5.16 s = String(f, 2);
Flash 34728 (52%) Ram 4312 (21%)

7. Arduino Nano V3 (ATmega328P) Compilation of an empty sketch.
Flash 2774 (9%), Ram 202 (9%)

8. Arduino Nano V3 (ATmega328P) dtostrf
Flash 4298 (13%), Ram 206 (10%)

9. Arduino Nano V3 (ATmega328P) s = String(f, 2);
Flash 4576 (14%), Ram 206 (10%)


In summary, when I use the Official Core, the dtostrf command takes 4480 bytes, the second method s = String (f, 2); takes 4652 bytes.
But if I use Rogers core, the dtostrf command takes 16180 bytes, s = String (f, 2); 16372 bytes.

Similarly for Aurduino Nano V3: 1524 bytes, and 1802 bytes.

Is there any other way to do this conversion? The one that won't eat 16KB? Using Arduino and STM32F103C8, I have a lot of RAM, but 64KB Flash is very low. Especially with the Rogers core.
by fredbox » Sun May 17, 2020 5:22 pm
Give the Pstring library a try: http://arduiniana.org/libraries/pstring/

Code: Select all

  float f=1.234;
  char buforS[9];
  PString(buforS, sizeof(buforS), f,4);
  Serial.println(buforS);
Before adding the code above to an existing program: 19012 / 3556.
After adding: 22056 / 3556.
Output:

Code: Select all

Sketch uses 22056 bytes (33%) of program storage space. Maximum is 65536 bytes.
Global variables use 3556 bytes (17%) of dynamic memory, leaving 16924 bytes for local variables. Maximum is 20480 bytes.

Output:
1.2340
Go to full post

stas2z
Posts: 131
Joined: Mon Feb 24, 2020 8:17 pm
Answers: 8

Re: Float To String - Flash memory consumption

Post by stas2z »

originally dtostrf (which is built-in avr-libc function) emulated with sprintf, which cause linking all huge printf related implementation to your binary
this is what really happens with libmaple

official core use newlib nano library, where float printing is disabled by default and requires special linker parameters, so it as it can't use printf for floats without extra linker options it implemented a bit different way than in libmaple

here you can see the code, copy/pasted from official core, first commented part is an original code used in libmaple

Code: Select all

char *dtostrf(double val, signed char width, unsigned char prec, char *sout)
{
  //Commented code is the original version
  /*char fmt[20];
  sprintf(fmt, "%%%d.%df", width, prec);
  sprintf(sout, fmt, val);
  return sout;*/

  // Handle negative numbers
  uint8_t negative = 0;
  if (val < 0.0) {
    negative = 1;
    val = -val;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (int i = 0; i < prec; ++i) {
    rounding /= 10.0;
  }

  val += rounding;

  // Extract the integer part of the number
  unsigned long int_part = (unsigned long)val;
  double remainder = val - (double)int_part;

  // Extract digits from the remainder
  unsigned long dec_part = 0;
  double decade = 1.0;
  for (int i = 0; i < prec; i++) {
    decade *= 10.0;
  }
  remainder *= decade;
  dec_part = (int)remainder;

  if (negative) {
    sprintf(sout, "-%ld.%0*ld", int_part, prec, dec_part);
  } else {
    sprintf(sout, "%ld.%0*ld", int_part, prec, dec_part);
  }
  // Handle minimum field width of the output string
  // width is signed value, negative for left adjustment.
  // Range -128,127
  char fmt[129] = "";
  unsigned int w = width;
  if (width < 0) {
    negative = 1;
    w = -width;
  } else {
    negative = 0;
  }

  if (strlen(sout) < w) {
    memset(fmt, ' ', 128);
    fmt[w - strlen(sout)] = '\0';
    if (negative == 0) {
      char *tmp = malloc(strlen(sout) + 1);
      strcpy(tmp, sout);
      strcpy(sout, fmt);
      strcat(sout, tmp);
      free(tmp);
    } else {
      // left adjustment
      strcat(sout, fmt);
    }
  }

  return sout;
}

User avatar
fpiSTM
Posts: 851
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 33
Location: Le Mans
Contact:

Re: Float To String - Flash memory consumption

Post by fpiSTM »

And after that some said the official core is huge :mrgreen:

fredbox
Posts: 97
Joined: Thu Dec 19, 2019 3:05 am
Answers: 2

Re: Float To String - Flash memory consumption

Post by fredbox »

Give the Pstring library a try: http://arduiniana.org/libraries/pstring/

Code: Select all

  float f=1.234;
  char buforS[9];
  PString(buforS, sizeof(buforS), f,4);
  Serial.println(buforS);
Before adding the code above to an existing program: 19012 / 3556.
After adding: 22056 / 3556.
Output:

Code: Select all

Sketch uses 22056 bytes (33%) of program storage space. Maximum is 65536 bytes.
Global variables use 3556 bytes (17%) of dynamic memory, leaving 16924 bytes for local variables. Maximum is 20480 bytes.

Output:
1.2340

roniin
Posts: 7
Joined: Mon May 04, 2020 6:13 pm

Re: Float To String - Flash memory consumption

Post by roniin »

Thanks for the clarification. I have no experience with STM32 :oops:

fredbox - this is what i was looking for. Thank you for your help. Pstring is light and secure against buffer overflow. 8-)

mauriziostm32
Posts: 20
Joined: Sat Mar 21, 2020 3:18 pm

Re: Float To String - Flash memory consumption

Post by mauriziostm32 »

Hi Guys
Pstring is nice and easy to use, but if you have loops that need to be fast...

*** CORRECTION ***

…. I wrote something wrong, it is fast enough … I just forgot a test delay inside a function... Pstring is OK

Many thanks to who wrote this function

Post Reply

Return to “General discussion”