formatted printing of int values in 1/10ths or 1/100ths

Formatted printing of a "pseudo" float is not that easy as I thought. To avoid floats I use int (or long) with a unit of tenth or hundredth. To print them, I have to add a comma, fill up with zeros and correct the minus sign.

My solution is the following code using sprintf(), but i think this code is not good and effective. The code needs not to be fast, a Serial.print (or lcd.print) of this number anyway needs 1-3ms.

Suggestions of optimization and simplification are welcome. :wink:

I have also tried without sprintf(), and adding up each decimal place to single char's, but the code will get much more complex (and I've given up).

(Range checks are missing in the code)

// usage: Serial.println(intToString(buffer, -1234, 6, 2)); -> " -12.34"
char * intToString(char * outstr, int value, byte totalLen, byte decMove) {
    if (decMove==0) {
        char formatS[10] = {'%',totalLen+48,'d','\0'};
        sprintf(outstr, formatS,value);
    } else {
        int factor = 1;
        for (int i=0; i<decMove; i++) { factor *=10; }
        char formatS[10] = {'%',totalLen-decMove+47,'d','.','%','0',decMove+48,'d','\0'};
        // Format-String like "%4d.%02d"
        sprintf(outstr, formatS,value/factor,abs(value%factor));
        // missing '-' at eg. -5 > "0.05"
        if ((value < 0) && (value > -factor)) { outstr[totalLen-decMove-3]='-'; }
    }
    return outstr;
}


void TestIntToString() {
    char buffer[10];
    Serial.println(intToString(buffer,    12, 5, 2));
    Serial.println(intToString(buffer,    -1, 5, 2));
    Serial.println(intToString(buffer, -1234, 5, 2));
}

Thank's for any suggestions, Norbert

I think that you are making things too complicated.
Try this as a starting point

 int anInt = 12345;
  char aBuffer[10];
  sprintf(aBuffer, "%d.%d", anInt/100, anInt%100);
  Serial.println(aBuffer);

Hi Norbert

How about converting the int to a float and then using dtostrf() to format it?

char* intToString(char* outstr, int value, byte totalLen, byte decMove) {
  float floatValue = value / pow(10, decMove);
  dtostrf(floatValue, totalLen, decMove, outstr);  
} 


void setup()
{
  char buffer[20];
  Serial.begin(115200);
  Serial.println(intToString(buffer, -1234, 6, 2));
}


void loop()
{
}

Regards

Ray

Hello Ray,

Was I confused? What simple it can be! With two lines of code. I spent hours(!) of reading and testing (I'm quite new in C++).
Should'nt I typecast the int?

float floatValue = (float)value / pow(10, decMove);

I didn't use dtostrf() yet, but I will use it now!

@UKHeliBob:
This I used before, I think the '-' was missing in the range [-1..-99] (-99 div 100 = +0). I wanted a function handling 1/1, 1/10 and 1/100 units.

Thanks for the ultra-quick reply, Norbert

So to avoid using floats you are going to use a float and pow(). That does not seem right to me.

void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");

   int val = -12345;
   printAsFloat(val, 2);
   
}

void loop() 
{
}

void printAsFloat(long val, uint8_t decimals)
{
  int divider[4] = { 1,10,100,1000 };
  // for (int i=0; i< decimals; i++) divider
  if (val < 0)
  {
    Serial.write('-');
    val = -val;
  }
  Serial.print(val/divider[decimals]);
  if (decimals > 0)
  {
    Serial.write(',');
    Serial.print(val % divider[decimals]);
  }
}

Hello robtillaart,

Your code looks better than mine, the idea with the divider-array is good!
The result shout be printed in an char[] and then right-justified, so I can use it in a function and send it to different displays (Serial, LCD, TFT,...), I have some different ones and want to use the same function.

@UKHeliBob, (about the short code of Hackscribble):
You're right - that's not avoiding float, but it's just temporal for printing. All the calulation and storage before are done in int.
But it's a good idea to replace the pow() by a divider-array as robtillaart did it.
The main drawback is the dtostrf() - a lot of code-memory is used. Execution time doesn't really matter, because of the ultra-slow print over software-serial for the LCD and TFT.

Regards, Norbert

printing numbers you do typically in reverse first as you can easily split of the last digit with %10.
after processing all the digits you just reverse the char array.