Display an integer with an arbitrary decimal point?

My current project uses a number with one decimal place. I never need more precision than that, so I'm trying to think of things in terms of a fixed point rather than floating point decimal. Instead of storing 1234.5 as a float, I store it as an int like 12345 and change the math accordingly. The only time I ever need the decimal point back is when I want to display the number on the LCD.

I could use string functions to stick a decimal point in there, but I'd rather avoid using string functions for memory/stability reasons

I could just divide by 10 into a float, but I was trying to avoid floats if possible.

Is there another trick or function to solve this problem? It must be a common one, but I can't seem to think of the right keywords to effectively search for it.

Print n/10
Print n%10

noiasca:
Print n/10
Print n÷10

I think that won't work. Dividing an int by an int will just drop the decimal portion. 12345/10=1234. I could do 12345/10.0=1234.50, but then I have a floating point operation. Not the end of the world, but I was wondering if there was an alternative.

It works, I just tried. :wink:

int yourInt = 12345;
int X = yourInt / 10;
int Y = yourInt % 10;

Serial.print(X);
Serial.print('.');
Serial.print(Y);

Erik_Baas:
It works, I just tried. :wink:

Print n/10
Print '.' // < !!
Print n÷10

Did you mean use the modulo (%) operator?

Erik_Baas:
It works, I just tried. :wink:

int yourInt = 12345;

int X;
int Y;

X = yourInt / 10;
Y = yourInt % 10;

Serial.print(X);
Serial.print('.');
Serial.print(Y);

Oh. Ooooh. That second line is modulo. I thought the post was showing me two ways of dividing. Ha!
Thanks for the clarification.

TheMemberFormerlyKnownAsAWOL:
Did you mean use the modulo (%) operator?

Yes. I didn't even notice the typo by noiasca... :wink:

Since division and modulo are both very expensive operations on an 8-bit AVR without hardware support for them, a more efficient method may be:

void setup() {
  int16_t myInt = 12345;
  int16_t temp;

  Serial.begin(115200);
  delay(1000);

  temp = myInt / 10;
  Serial.print(temp);
  Serial.print(".");
  Serial.println(myInt - 10 * temp);
}

void loop() {
}

I say "may" because it's possible that the compiler could come up with this on its own.

Umm.. Maybe this only works on the teensys but I use this to set the number of digits past the decimal point when formatting an output c string.

dtostrf(value,0, digits,cStr);

In action : Vid of RPN calculator

Is that what you are looking for?

-jim lee

jimLee:
Umm.. Maybe this only works on the teensys but I use this to set the number of digits past the decimal point when formatting an output c string.

dtostrf(value,0, digits,cStr);

In action : Vid of RPN calculator

Is that what you are looking for?

-jim lee

Go back and reread the original post.

I just did before posting that. He didn't want to use the String lib. But at some point, even if everything he does is in ints, he needs to display a float with one past decimal. That line of code should do the conversion for him.

Sheesh! So prickly today.

-jim lee

He didn't want to use float type either. Hence storing 10x actual value in an integer. Wants to print it to look like float. by putting '.' before last digit. Code you posted won't do that because 'value' must be a float and actual value, not integer 10x actual value.

try

int yourInt = 12345;
int X;
int Y;

X = yourInt / 10;
Y = yourInt - (X * 10);

Serial.print(X);
Serial.print('.');
Serial.print(Y);

okay, same answer was given above but this is a more literal interpretation.

By the way, I did some testing comparing modulo with brute force successive subtraction, modulo lost, I think 5 or 8 times slower IIRC. But math speed depends so much on which processor is running it. Also even a single instruction multiply instruction puts a CPU at a huge advantage for a lot of things. You can go on from there, but that basic enhancement is a big one. I think integer divide is not possible or isn't feasible, I don't know which, in a single machine cycle. I know the hardware behind multiplication, it's easy to see how it can be done a lot in parallel. But the AVR is a tiny RISC with addition and subtraction only. That's one reason why you see a lot of the new Arduinos come with more advanced CPU's.

aarg:
try

int yourInt = 12345;

int X;
int Y;

X = yourInt / 10;
Y = yourInt - (X * 10);

Serial.print(X);
Serial.print('.');
Serial.print(Y);



okay, same answer was given above but this is a more literal interpretation.

By the way, I did some testing comparing modulo with brute force successive subtraction, modulo lost, I think 5 or 8 times slower IIRC. But math speed depends so much on which processor is running it. Also even a single instruction multiply instruction puts a CPU at a huge advantage for a lot of things. You can go on from there, but that basic enhancement is a big one. I think integer divide is not possible or isn't feasible, I don't know which, in a single machine cycle. I know the hardware behind multiplication, it's easy to see how it can be done a lot in parallel. But the AVR is a tiny RISC with addition and subtraction only. That's one reason why you see a lot of the new Arduinos come with more advanced CPU's.

Thanks for this info. Because I'm using cooperative multitasking in this project, I certainly don't want to waste any cycles. How do you balance the speed improvement of removing the modulo against the costs associated with creating and using another variable? The time to write a line to the LCD is on the order of 5ms anyway. Then again, if the performance increase significant, there's no reason not to make this substitution standard practice, shaving off microseconds wherever possible. The math is simple enough that it doesn't impair readability.

For anyone else using a method like this, I just want to point out that in order to support negative numbers, you need the absolute value of Y so you don't get a result like "-1234.-5".

It's also true that everything ends of as a string eventually, if you're going to display it. It's far beyond my skill level to try to compare forming a string and printing it to giving print the integer and letting it figure out the details (+10 Overloads? Is that bad? It sounds bad.) Here's what I have currently:

lcd.setCursor(0, 3);
snprintf( lineFour, 21, "Target: %4d.%1d lbs     ", targetWeight/10, abs(targetWeight%10) );
lcd.print( lineFour );

Now that I think of it, I should probably only overwrite the value and not re-print "Target:" every time...

Another way, just for fun.

//
// insert arbitrary decimal point
//
// https://forum.arduino.cc/index.php?topic=708114.msg4759275#msg4759275

//int number = 1234;
int number = -4321;
byte decimalPlaces = 1;
byte counter;
char asText[10];

void setup() {
  Serial.begin(115200);
  itoa(number, asText, 10);
  Serial.println(asText); // print converted int
  byte integerPart = strlen(asText);
  for (counter = 0; counter < integerPart; counter++) {
    Serial.print(asText[counter]);
    if (counter == integerPart - 1 - decimalPlaces) {
      Serial.print(".");
    }
  }
}

void loop() {
}

I was interested in what I could do with all the spared processing power by avoiding the modulo division.

// https://forum.arduino.cc/index.php?topic=708114.15
const uint16_t cycles = 10;
uint32_t startTime, endTime;
int16_t myRandom;
int16_t by10 = 0;
byte integerPart;
char asText[10];
byte counter;
const byte decimalPlaces = 1;  // let's help the compiler

void setup() {
  Serial.begin(115200);
  randomSeed(A0);

  delay(1000);
  startTime = micros();
  for (uint16_t i = 0; i < cycles; i++)
  {
    myRandom = random(1000, 10000);
    Serial.print(myRandom / 10);
    Serial.print(".");
    Serial.println(myRandom % 10);
  }
  endTime = micros();
  Serial.print(endTime - startTime); Serial.println("us modulo");
  delay(1000); // give serial some time to print


  startTime = micros();
  for (uint16_t i = 0; i < cycles; i++)
  {
    myRandom = random(1000, 10000);
    by10 = myRandom / 10;
    Serial.print(by10);
    Serial.print(".");
    Serial.println(myRandom - (by10 * 10));
  }
  endTime = micros();
  Serial.print(endTime - startTime); Serial.println("us no modulo");
  delay(1000); // give serial some time to print

  startTime = micros();
  for (uint16_t i = 0; i < cycles; i++)
  {
    myRandom = random(1000, 10000);
    itoa(myRandom, asText, 10);
    //Serial.println(asText); // print converted int
    integerPart = strlen(asText);
    for (counter = 0; counter < integerPart; counter++) {
      Serial.print(asText[counter]);
      if (counter == integerPart - 1 - decimalPlaces) { // doesn't matter ... the compiler optimization will care about
        Serial.print(".");
      }
    }
    Serial.println();
  }
  endTime = micros();
  Serial.print(endTime - startTime); Serial.println("us itoa");
}

void loop() {}

I think the three concepts are fair written.

let's try it:
229.8
683.9
455.2
833.0
949.1
886.7
961.6
446.9
509.9
951.5
3832us modulo
792.5
978.1
577.1
258.8
281.8
451.3
175.5
120.6
152.5
556.8
3680us no modulo
100.7
354.3
875.0
378.7
772.3
453.3
273.9
406.9
918.9
686.7
2148us itoa

When the compiler optimization doesn't play to much games with me, I would say, I will keep the modulo just for the readability of the source. :wink:
The slowest part is the output anyway.

itoa() fared pretty well. Thanks for the interesting test results!

See Absolute value in C

Just print a decimal point in the appropriate position on the lcd so that the number then “appears” as a decimal.

Take your number and divide by 1000 to knock offs the decimal number . Print what’s left , print decimal place then , print the decimal bit

...but don't forget significant zeroes after the decimal point.