Page 1 of 1

Float To String - Flash memory consumption

Posted: Sun May 17, 2020 3:19 pm
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.

Re: Float To String - Flash memory consumption

Posted: Sun May 17, 2020 3:49 pm
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;
}

Re: Float To String - Flash memory consumption

Posted: Sun May 17, 2020 4:17 pm
by fpiSTM
And after that some said the official core is huge :mrgreen:

Re: Float To String - Flash memory consumption

Posted: Sun May 17, 2020 5:22 pm
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

Re: Float To String - Flash memory consumption

Posted: Mon May 18, 2020 8:49 am
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-)

Re: Float To String - Flash memory consumption

Posted: Thu Nov 05, 2020 9:07 am
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