# Converting `millis()` to decimal seconds?

I would like to get my Arduino to print milliseconds as decimals of seconds. For example, instead of printing 10456, printing 10.456

I have tried to set a float value or millis, and dividing by 1000 but that gives me a whole number "0" to "1" which is not ideal

The code I use is:

``````float ourtime = (millis() / 1000);
dataFile.print (ourtime);
``````

What would be the easiest, and least taxing (for the processor) way of getting a script to return milliseconds as seconds while taxing the unit as little as possible ?

• Could you make explicit the meaning of "the best way"? Do you mean, a way that works properly, a way with readable code, a fast way (how fast), a way is as little code as possible?... – jfpoilpret Feb 25 '17 at 7:25

Dividing an integer by an integer (1000) yields an integer, regardless of what you cast that result to.

Instead you need to divide the integer by a float, or cast the integer to a float first. The simplest way is:

``````Serial.println(millis() / 1000.0, 3);
``````

The `3` as the second parameter tells `Serial.println()` how many decimal places to print. The `.0` at the end of `1000.0` forces the compiler to see `1000` as a float value (you can also use `1000f` if you prefer).

Since floating point can be quite expensive it's possible to emulate it using integer division and modulus (although they are still quite expensive):

``````uint32_t now = millis();
uint32_t secs = now / 1000;
uint32_t ms = now % 1000;

Serial.print(now / 1000);
Serial.print(".");
if (ms < 100) Serial.print("0");
if (ms < 10) Serial.print("0");
Serial.println(ms);
``````

You could replace the `%` with a x1000 and a subtraction too if you like:

``````uint32_t now = millis();
uint32_t secs = now / 1000;
uint32_t ms = now - (secs * 1000);

Serial.print(now / 1000);
Serial.print(".");
if (ms < 100) Serial.print("0");
if (ms < 10) Serial.print("0");
Serial.println(ms);
``````

A further method would be to first "print" the milliseconds to a string, then split it into two chunks. Print the first chunk, then a decimal point, and finally the second chunk. This avoids the use of any division or multiplication, but does use expensive string operations:

``````char num[10];
snprintf(num, 10, "%lu", millis());
uint8_t nlen = strlen(num);

for (uint8_t i = 0; i < nlen - 3; i++) {
Serial.write(num[i]);
}
Serial.write('.');
for (uint8_t i = nlen-3; i < nlen; i++) {
Serial.write(num[i]);
}
Serial.println();
``````

So really there is no "perfect" method for converting milliseconds into seconds that uses hardly any CPU cycles. All base 10 operations tend to be a bit expensive on a small microcontroller without hardware support for integer MUL/DIV instructions, or a Floating Point Unit.

• You mean `if (ms < 100)` and `if (ms < 10)`. Integer division is not cheap either: I timed your float code version at 11480 CPU cycles (not counting the call to `millis()`) and you int version at 7561 cycles, i.e. 34% less time. Both for the millis value 12345678UL. So it's faster, but not by orders of magnitude. – Edgar Bonet Feb 24 '17 at 21:10
• You are right, my keyboard is hiding under the desk at the moment and I can't actually see it. No division on an AVR is cheap. If you are that concerned about the speed of division you would pick an MCU with a hardware division unit, or an FPU and use floating point. – Majenko Feb 24 '17 at 21:13
• Serial.println(millis() / 1000.0, 3); is a great idea, but if used alone, it drops zeros. So the output would be "0.849", "0.874", "0.95" (and not "0.950") which may cause problems. – AhBajeezus Feb 24 '17 at 21:15
• Sure. I am just saying that replacing floating point division by integer division does not provide as large a speedup as one may naively expect. – Edgar Bonet Feb 24 '17 at 21:17
• Also you have to wonder how much of the difference is due to the serial print routines, one handling float and the other handling integers... – Majenko Feb 24 '17 at 21:19

Division is quite expensive.

Division can be done with subtraction, or shifting - right shift 10 (= /1024) and then compensate for that 24....

You may need too benchmark to see if on your chip this will yield any gaiin.

edit:

I did some quick benchmarking against the brutal force approach by Majenko (division followed by the mod operation), for full range 16-bit types, dividing by 1000, on a PIC16, XC8 free mode:

for 16-bit types 1. Majenko's approach (1000 divisor + mod): 45.9M ticks; 2. revised Majenko's approach (1000 divisor, no mod): 36.9M ticks; 3. My approach (1024 divisor, no mod): 20.8M ticks.

[edit 2]for 32-bit types 1. Majenko's approach (1000 divisor + mod): 101.6M ticks; 2. revised Majenko's approach (1000 divisor, no mod): 63.0M ticks; 3. My approach (1024 divisor, no mod): 19.3M ticks.

the same trend applies under the pro mode.

the same trend applies for AVR, with the speed gain being bigger.

edit 2: 32-bit benchmarking added.

I also revised my approach for 32-bit types to speed up the execution a little.

lessons learned:

1) mod ops shall be avoided as much as you can;

2) divisions shall be avoided as much as you can.

3) algorithm rules!

however, be cautious to extrapolate the data here. on a chip with hardware multiplier + divider (STM8, my favorite chip), this trend may not apply and you should benchmark on the target chip to be safe.

• Care to show the algorithm to “compensate for that 24”? – Edgar Bonet Feb 24 '17 at 20:26
• I don't think it the division that is slow, but the use of a float on a CPU that doesn't support floating point operations. – Gerben Feb 24 '17 at 21:39