Filling with zeros is a pain.
Here's a version avoiding the steenking loops by using nested snprintf()s:
void setup()
{
long val = -12; //12345678L;
long scale = 1000L; // 3-decimal places scale
Serial.begin(9600);
Serial.print( "DEMO: start val = " );
Serial.print( val, DEC );
Serial.print( " mm == " );
printFixedDec( val, scale );
Serial.print( " m == " );
printFixedDec( val, ( scale = 1000000 ));
Serial.println( " Km" );
Serial.println( );
Serial.print( "22 / 7 = " );
scale = 10000000;
printFixedDec( 22 * scale / 7, scale );
Serial.println( );
long testValV3[] = {1, 123, 1000, 1234, 2001, -1, -123, -1000, -1234, -2001,1000000000/3,-2000000000/3};
for (auto val : testValV3) {
Serial.print(val);
Serial.print("/1000=\t");
printFixedDec(val,1000);
Serial.println();
}
}
void printFixedDec( long val, long scale ) // we don't need no steenking loops!
{
if (val < 0) {
Serial.print('-');
val = -val;
}
char buff[50], format[20];
// snprintf(buff,sizeof(buff)-1,"%li %i %li",val/scale,numPlaces(scale)-1,val%scale);
// snprintf(buff,sizeof(buff)-1,"%li %0*li",val/scale,numPlaces(scale)-1,val%scale);
//snprintf(format,sizeof(format)-1,"%%li.%%0%ili",(int)(log(scale)/log(10)));
snprintf(format, sizeof(format) - 1, "%%li.%%0%ili", numPlaces(scale) - 1);
snprintf(buff, sizeof(buff) - 1, format, val / scale, val % scale);
Serial.print(buff);
}
int numPlaces (long n) {
// https://stackoverflow.com/a/1068937/1653571
#include <limits.h>
if (n < 0) n = (n == LONG_MIN) ? LONG_MAX : -n;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
/* 2147483647 is 2^31-1 - add more ifs as needed
and adjust this final return as well. */
return 10;
}
void loop()
{
}
DEMO: start val = -12 mm == -0.012 m == -0.000012 Km
22 / 7 = 3.1428571
1/1000= 0.001
123/1000= 0.123
1000/1000= 1.000
1234/1000= 1.234
2001/1000= 2.001
-1/1000= -0.001
-123/1000= -0.123
-1000/1000= -1.000
-1234/1000= -1.234
-2001/1000= -2.001
333333333/1000= 333333.333
-666666666/1000= -666666.666
When fixed point seems like a good idea, and you have to use it for printing, it might be cleanest to work directly in integral milli-units, micro-units or SI-prefixed units and completely avoid printing decimals.