2

I made a big search about how to Format Numbers with the Arduino. I want to format unsigned Longs into a String in this format: "23,854,972".

The most of the snippets I found work only with the standard C / C++ Libraries. They dont work on the Arduino until I should put some STL libraries on the Arduino, which I want to prevent. It would be too bit of a overhead to import these only for this task. Also these Libraries will of course use some additional Flash and SRAM.

For my Application it is very important that the solution uses the minimum Flash, SRAM and is fast.

Even if a solution does not use STL or works only with the native Arduino Libraries, I would need help to decide which one is more effective in the sense of speed.

Incoming Number: 23854972 Arduino Program Output: 23,854,972

  • Have you tried writing a function that does what you're asking? – Avamander Aug 22 '16 at 21:19
4

Here is my try at it: The usual way to write a number in decimal is to get the digits from right to left with a loop that looks something like

digit = '0' + val % 10;
val /= 10;

The following function does exactly this, with the addition of adding commas at the correct positions:

/*
 * Format an unsigned long (32 bits) into a string in the format
 * "23,854,972".
 *
 * The provided buffer must be at least 14 bytes long. The number will
 * be right-adjusted in the buffer. Returns a pointer to the first
 * digit.
 */
char *ultoa(unsigned long val, char *s)
{
    char *p = s + 13;
    *p = '\0';
    do {
        if ((p - s) % 4 == 2)
            *--p = ',';
        *--p = '0' + val % 10;
        val /= 10;
    } while (val);
    return p;
}

Note that the string is right adjusted in the buffer, and the unused characters are not touched. This means you can get a right adjusted string by:

  • pre-filling the string with spaces (for padding)
  • calling the function above
  • using the original buffer as the right adjusted string

Otherwise you would use the returned pointer to have a string with no padding.

Here is a simple test program:

unsigned long vals[] = {0, 1, 2, 9, 10, 999, 1000, 0xffffffff};
const int COUNT = sizeof vals / sizeof vals[0];

void setup()
{
    Serial.begin(9600);
    char buffer[14];
    for (int i = 0; i < COUNT; i++) {
        unsigned long val = vals[i];
        Serial.print(val);
        Serial.write('\t');
        Serial.println(ultoa(val, buffer));
    }
}

void loop() {}
4

The most effective way to format numbers on Arduino

If "effective way" is minimum effort you could hack the avr-libc source code for ltoa and do something like below:

char *ultos_recursive(unsigned long val, char *s, unsigned radix, int pos)
{
  int c;

  if (val >= radix)
    s = ultos_recursive(val / radix, s, radix, pos+1);
  c = val % radix;
  c += (c < 10 ? '0' : 'a' - 10);
  *s++ = c;
  if (pos % 3 == 0) *s++ = ',';
  return s;
}

char *ltos(long val, char *s, int radix)
{
  if (radix < 2 || radix > 36) {
    s[0] = 0;
  } else {
    char *p = s;
    if (radix == 10 && val < 0) {
      val = -val;
      *p++ = '-';
    }
    p = ultos_recursive(val, p, radix, 0) - 1;
    *p = 0;
  }
  return s;
}

void setup()
{
  Serial.begin(9600);
  while (!Serial);

  char buf[32];
  Serial.println(ltos(12345678, buf, 10));
  Serial.println(ltos(-12345678, buf, 10));
}

void loop()
{
}

Gives the output:

12,345,678
-12,345,678

Cheers!

PS: Please see the table driven, non-recursive, number conversion in Cosa (source and benchmark) for a lean and faster implementation.

  • How would I check which answer/solution gives the faster result? I always print delta-micros() but is there a better way? – William Roy Aug 23 '16 at 10:28
  • The above solution is slow. This is a fast hack to show that you do not need all the libraries mentioned in your original question. See @EdgarBonet's answer for a solution that runs much faster. It can be improved with table lookup to avoid division/modulo. That is what the Cosa version does. – Mikael Patel Aug 23 '16 at 10:46
  • Thank you very much. But how you know if this one or the other one is faster? How to determine it? – William Roy Aug 23 '16 at 11:01
  • Estimate the algorithms complexity and behavior. Read the generated assembly code and calculate the number of clock cycles. Write a test program and verify. – Mikael Patel Aug 23 '16 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.