Output floats with flexible precision

When I use cout in C++ I have floats printed with flexible precision:

std::cout << 0.123; // prints 0.123
std::cout << 0.1234 // prints 0.1234

But I can only print with fixed precision on Arduino:

Serial.print(0.123, 4); // prints 0.1230
Serial.print(0.1234, 4); // prints 0.1234
Serial.print(0.12345, 4); // prints 0.1234

Is it possible to print with flexible precision?

Edits:

Is it possible to call some function with float arg so that it printed this float with maximum possible precision without trailing zeros (without setting the precision in advance):

someFunction(0.1); // prints 0.1

somFunction(0.123); // prints 0.123

on an Arduino I use sprintf to format the data into a text array (with field width, precision, etc as required) then use Serial.print() to print the array

1 Like

Replace 4, the precision, with a integer variable, N for examl,e.

Set N to the desired precision digits.

    int N = 3;
    Serial.println(0.123456, N);

Just figure out N, looks like you don't like seeing a zero on the last place(s), so that should be easy.

See it here

a7

by default %f will not work one requires a header file, e.g.

#include <PrintEx.h>

void setup() {
  float x=0.1234567;
  Serial.begin(115200);
  Serial.println();
  char text[100]={0};
  sprintf(text,"'%6.3f'", x);
  Serial.println(text);
  sprintf(text,"'%10.6f'", x);
  Serial.println(text);  
}

void loop() {}

a run gives

' 0.123'
'  0.123457'

Edit: or can just use printf(), e.g.

#include <PrintEx.h>

StreamEx mySerial = Serial;

void setup() {
  float x=0.1234567;
  Serial.begin(115200);
  Serial.println();
  mySerial.printf("'%6.3f'\n", x);
  mySerial.printf("'%10.6f'\n", x);
}

void loop() {}

So you want to suppress trailing zeros after the decimal point?

1 Like

The above code says that 4-digit (arg2) will be printed after the decimal point of the float number of arg1.

Because you have only 3-digit after the decimal point of arg1 (0.123), the Serial.print() method appends a 0 (zero) at the end to make it 4-digit. Similar interpretation applies for the following code:

Serial.print(0.12345, 4); // prints 0.1234

you could replace trailing '0' with 0, e.g.

#include <PrintEx.h>

void setup() {
  Serial.begin(115200);
  float x=1.2300000f;
  char text2[100]={0};
  sprintf(text2,"%10.6f", x);
  Serial.println(text2);  
  for (int i=strlen(text2)-1; (i>0) && (text2[i] == '0'); i--)
     text2[i]=0;
  Serial.println(text2);  
 
}

void loop() {}

gives

  1.230000
  1.23
2 Likes

This didn't compile:

Fixed and more interestingly:
std::cout << 0.1230; // prints 0.123
std::cout << 0.1234; // prints 0.1234

1 Like

What was the error? Going blind looking to see why…

Never mind, GF spotted it.

a7

O

Off topic: how do you do strike-through? Oh--I see from the quote in the edit box that you do strike-through by bracketing the text with double-tildes.

Yeah, a missing semicolon was minor. But the important part of the OP's question was the ragged precision of dropping the trailing zeros.

I would like to print out float without setting precision in advance so that the float printed with maximum precision. Something like Serial.print(0.12345); // prints 0.12345; Serial.print(0.1); // prints 0.1;

@brand17

You need to understand the functioning of the Serial.print(arg1, arg2) method.

1. Serial.print(0.12345) will show 0.12; because, the 2nd argument is silent which is 2 by default and indicates the number of digits to be printed after the decimal point on the condition that the 1st argument is a floating point number.

2. To see 0.12345 on the Serial Monitor, you must execute the following code:

Serial.print(0.12345, 5);

3. The execution of Serial.print(0.1) will show what? Is it 0.1 or 0.10?

Is it possible to call some function with float arg so that it printed this float with maximum possible precision (without setting it in advance):

someFunction(0.1); // prints 0.1

somFunction(0.123); // prints 0.123

To show something on the Serial Monitor, you must execute the print() method which essentially follows the rules of post #12.

Where is the answer to Q3 of post #12?

to print to the maximum float precision you need to get the value of FLT_DIG in float.h and print that number of digits
e.g.
FLT_DIG: Number of decimal digits that can be rounded into a floating-point type and back again to the same decimal digits, without loss in precision.

the <float.h> header file consists of platform-dependent and implementation specific floating point values
program for PC using GNU C

#include <float.h>

int main(void) {
  printf("FLT_DIG %d\n",FLT_DIG);
  printf("DBL_DIG %d\n",DBL_DIG);
}

when run gives

FLT_DIG 6
DBL_DIG 15

floats have a precision of 6 digits (4 bytes) and doubles 15 digits (8 bytes)

on an Arduino Uno

#include <float.h>

void setup() {
  Serial.begin(115200);
  Serial.print("FLT_DIG ");Serial.println(FLT_DIG);
  Serial.print("DBL_DIG ");Serial.println(DBL_DIG);
}

void loop() {}

gives

FLT_DIG 6
DBL_DIG 6

indicating that float and double are the same (both 4 bytes)

on an Arduino Due

FLT_DIG 6
DBL_DIG 15

however, precision does depend of the source of your data - if you are acquiring data from a sensor with three digits of precision it is no use printing six digits

I see the answer in the post #7. Is there any simpler approach? Answer to Q3 is 0.10

1 Like

There are harder ways.

But you are giving 0 a status it does not have. Just because the last digits are 0 does not mean the floating point number is any more, or less, precise.

You are chasing a cosmetic desire, you wanna see it look a certain way. This is understandable.

But floats have 6-7 digits of significance, period. Some of them may be zeroes, some of those may come near the end…

a7

1 Like

thanks. So the only way is your post #7?

that is how I generally print floats and doubles - consider PI defined to 50 digits

#include <float.h>

int main(void) {
  double pi=3.14159265358979323846264338327950288419716939937510;
  float x=pi;
  printf(" float PI %25.20f\n",x);
  printf("double PI %25.20lf\n",pi);
}

on a pc running GNU C gives

 float PI    3.14159274101257320000
double PI    3.14159265358979310000

after 6 or 7 digits the float output is meaningless similar double after 15 or 16 digits

I have seen engineers read data from experiments, e.g. from analogue meters or 4 digit digital meters, and perform double calculations and print results with 15 digits

1 Like

Just two questions out of curiosity:
1. What is the accuracy and precision of float-type data in terms of "number of digits".
2. What is the accuracy and precision of double-type data in terms of "number of digits".