Float vs Double

Hi,

I'm doing basic work learning about potentiometer using the UNO. I can read in values ok over analog, but I would like double precision output to the serial monitor. I'm able to get that, but it looks the same, regardless if I use float or double as data types.

Here are my questions:

  1. which data type is preferred to use for small precision, such as 2.35?
  2. is there a way to specify (or force) a precision (e.g. 6 decimal places)
/* Reading analog values with 2-decimal precision
 *  
 *  
 */

int potPin = 0;

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
 float volts = ((analogRead(potPin) * 5) / float(1023));

 Serial.println(volts);
 
 delay(10);
}

Float and double are the same on AVRs - they aren't on the Due and some other fancier microcontrollers, but they are for AVRs.

A common practice is to do all the math as integers, and only at the end, display that as a decimal - for example if you want 3 decimal places, do all your math as integers a factor of 1000 higher, then divide by 1000.0 at the end (or if printing, print number/1000, the decimal, and then number %1000 - thus avoiding floats entirely). Floating point math bloats the program size and the 32-bit floats aren't quite precise enough for a lot of applications.

1 Like

@project_science

As I have understood that you wish to display the voltage of the wiper point (volt) of your potentiometer with:
(a) 2-digit after the decimal point
(b) 6-digit after the decimal point

A: If it would be my project, I would carry out the following steps to print the value on Serial Monitor with 4-digit after decimal point (without any floating point calculation. Ref: Post#1; flash consumption: 1874 bytes):

void setup() 
{
  Serial.begin(9600);
  analogReference(DEFAULT);
  
 // volt = analogRead(A5)*5/1023;
 // ==> volt = analogRead(A5)*0.0048
 //==> volt*10000 = analogRead(A5)*48 
  unsigned long ampVolt; 
  ampVolt = ((unsigned long) 48)*analogRead(A5);
  Serial.println(ampVolt, HEX);   //prints: 60000
  Serial.println(ampVolt, DEC);     //prints: 24576
  
  unsigned long q = ((unsigned long)ampVolt)/10000;
  unsigned long r = ((unsigned long) ampVolt)%10000;
  Serial.print(q, DEC);  //prints: 2
  Serial.print('.');    //prints: 2.
  Serial.println(r, DEC); //prints: 2.4576  (4-digit precision)
}

void loop() 
{
  
}

B: Using floating point calculations (flash consumption: 3334 bytes: Ref: Post#1)

float volt = ((float) analogRead(A5))*5/1023;
Serial.println(volt, 2); //prints: 2.50 (2-digit precision)
Serial.print(volt, 6);    //prints: 2.497556 (6-digit precision)

C: Observation
(a) Integer math consumes 1874 bytes flash, and the execution time is: 498 us
(b) Float math consumes 3334 bytes flash, and the execution time is: 513 us.

If it would be my project, I would carry out the following steps to print the value on Serial Monitor with 4-digit after decimal point

Or you could stop for a moment, engage brain, and think for a moment about the decimal representation of a ten bit value.

If the 10-bit value is the ADC value (say: 0x0200 = 512 for 2.50 Volt), then it is going to be multiplied by 5 (getting 2560) and then divided by 1023 (getting: 2.50 = 0x0010/0x0011). My brain is not going to work how to obtain back ~=2.5 without amplifying the raw response of the ADC and avoiding the float math.

The simple way:

 float volts = analogRead(potPin) * 5 / 1024.0;
 Serial.println(volts, 2);

Let's not get into a fooferaw unless you need more than this.

Notice that /1023 is not the correct scale factor. It is /1024.

Part II, without float:

#include <stdint.h>
// fix binary decimal point so the integer part is 16 bits and the fractional part is 16 bits:
const long scaleFactor = (long)UINT16_MAX + 1;

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < 1024; i++)
  {
    // convert input quantity to scaled value
    // long scaledVolts = analogRead(potPin) * scaleFactor * 5 / 1024;
    long scaledVolts = i * scaleFactor * 5  / 1024;

    // print scaled value
    Serial.print(scaledVolts / scaleFactor);
    Serial.print('.');
    Serial.print((scaledVolts * 10 / scaleFactor) % 10);
    Serial.println((scaledVolts * 100 / scaleFactor) % 10);
  }
}
void loop() {}