In the Arduino Core library the printing of floats is done with the use of unsigned long numbers.
The current 1.0.4 implementation prints "ovf" when a float is larger that maxlong (approx).
This is not correct.
To solve this I added code to printFloat so it will print print large ( > 1E+9) and small ( < 1E-3) numbers automatically in scientific notation: x.xxxxE+nn or x.xxxxE-nn
There is also the engineering E-notation that only allows multiples of 3 as exponent. Could be implemented in a similar way. However that would require an interface change of print() for floats as one should be able to select the representation. The interface would change to something like print(float number, uint8_t digits, uint8_t repr = 0); For repr there could be defines or an enum { NORMAL, ENGINEERING, SCIENTIFIC, .... } or just 0,1,2
please review and test.
printFloat() can be found in print.cpp - one of the core libs.
update: do not use this code, it has some bugs ; => use zip file from reply #10 instead
size_t Print::printFloat(double number, uint8_t digits)
{
size_t n = 0;
int exponent = 0;
if (isnan(number)) return print("nan");
if (isinf(number)) return print("inf");
if ( abs(number) > 1000000000.0)
{
while (abs(number) > 10.0)
{
number /= 10.0;
exponent++;
}
}
else if (abs(number) < 0.001)
{
while (abs(number) < 1.0)
{
number *= 10.0;
exponent--;
}
}
// Handle negative numbers
if (number < 0.0)
{
n += print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
n += print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0) {
n += print(".");
}
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
n += print(toPrint);
remainder -= toPrint;
}
if (exponent != 0)
{
n += print('E');
if (exponent > 0)
{
n += print('+');
}
n += print(exponent);
}
return n;
}
Simple test sketch to show it works at least for some values
//
// FILE: testEnotation.ino
// AUTHOR: Rob Tillaart
// DATE: 2013-05-12
//
// PURPOSE: test scientific notation above 1E9
//
void setup()
{
Serial.begin(115200);
float f = 355.0/113.0;
for (int i = 0; i < 45; i++)
{
Serial.println(f, 6);
f = f * 10;
}
f = 355.0/113.0;
for (int i = 0; i < 45; i++)
{
Serial.println(f, 6);
f = f / 10;
}
}
void loop()
{
}
as always comments are welcome