Overview

Floating-point numbers are essential for handling decimal values in Arduino and MicroPython programming. However, due to their inherent approximation nature, comparing them directly for equality can be problematic. This section explores how to effectively use and compare floating-point numbers in your sketches.

What We Will Learn in This Section

  • Declaring and manipulating floating-point variables.
  • Challenges with comparing floating-point values.
  • Implementing a solution using tolerance checks.

Why Is This Lesson Important to You?

Understanding the behaviour of floating-point numbers helps ensure accurate calculations and condition checks in Arduino projects, preventing unexpected errors.

Components List

  • ESP32
  • USB cable for programming and power
  • Computer with Arduino IDE installed

Circuit Diagram (With Connection)

Not applicable for this topic.

Arduino CodeHere’s an explanation of the code:

 

float value = 1.1;

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

void loop() {
  value = value - 0.1;
 
  if (value == 0) {
    Serial.println("The value is exactly zero");
  } else if (almostEqual(value, 0)) {
    Serial.print("The value ");
    Serial.print(value, 7); // Print to 7 decimal places
    Serial.println(" is almost equal to zero, restarting countdown");
    value = 1.1;
  } else {
    Serial.println(value);
  }
 
bool almostEqual(float a, float b) {
  const float DELTA = 0.00001; // Maximum difference to be almost equal
  if (a == 0) return fabs(b) <= DELTA;
  if (b == 0) return fabs(a) <= DELTA;
  return fabs((a - b) / max(fabs(a), fabs(b))) <= DELTA;
}

 

  1. Variable Declaration
float value = 1.1;
  • float value = 1.1;: Declares a floating-point variable value and initializes it with 1.1.
  1. Setup Function
void setup() {
  Serial.begin(9600);
}
  • void setup(): Runs once when the microcontroller starts.
  • Serial.begin(9600);: Initializes serial communication at a baud rate of 9600. This allows you to send and receive data via the Serial Monitor.
  1. Loop Function
void loop() {
  value = value – 0.1;
  • void loop(): This function runs repeatedly in a continuous loop.
  • value = value – 0.1;: Subtracts 0.1 from the current value of value each time the loop runs.
  1. Conditional Statements
if (value == 0) {
  Serial.println(“The value is exactly zero”);
} else if (almostEqual(value, 0)) {
  Serial.print(“The value “);
  Serial.print(value, 7); // Print to 7 decimal places
  Serial.println(” is almost equal to zero, restarting countdown”);
  value = 1.1;
} else {
  Serial.println(value);
}
  • if (value == 0): Checks if value is exactly zero. If true, it prints “The value is exactly zero”.
  • else if (almostEqual(value, 0)): If value is not exactly zero, this condition checks if value is “almost equal” to zero by calling the almostEqual() function. If true, it prints the value to 7 decimal places and resets value to 1.1.
  • else: If neither condition is true, it simply prints the current value.
  1. The almostEqual Function
bool almostEqual(float a, float b) {
  const float DELTA = 0.00001; // Maximum difference to be almost equal
  if (a == 0) return fabs(b) <= DELTA;
  if (b == 0) return fabs(a) <= DELTA;
  return fabs((a – b) / max(fabs(a), fabs(b))) <= DELTA;
}
  • almostEqual(float a, float b): This function checks if two floating-point numbers a and b are nearly equal.
  • const float DELTA = 0.00001;: Defines a small threshold value (DELTA) that determines how close two numbers must be to be considered “almost equal.”
  • fabs(): This function returns the absolute value of a floating-point number.
  • if (a == 0) return fabs(b) <= DELTA;: If a is zero, checks if b is within the threshold.
  • if (b == 0) return fabs(a) <= DELTA;: If b is zero, checks if a is within the threshold.
  • return fabs((a – b) / max(fabs(a), fabs(b))) <= DELTA;: For non-zero values, it compares the relative difference between a and b to the threshold DELTA.

MicroPython

import time
import math

value = 1.1

def almost_equal(a, b, delta=0.00001):
    if a == 0:
        return abs(b) <= delta
    if b == 0:
        return abs(a) <= delta
    return abs((a - b) / max(abs(a), abs(b))) <= delta

while True:
    value -= 0.1
   
    if value == 0:
        print("The value is exactly zero")
    elif almost_equal(value, 0):
        print(f"The value {value:.7f} is almost equal to zero, restarting countdown")
        value = 1.1
    else:
        print(value)
   
    time.sleep(0.25)

 

Here’s an explanation of the code:

  1. Importing Modules
import time
import math
  • import time: Imports the time module to use functions related to time, such as sleep for delays.
  • import math: Although imported, the math module is not used in this particular code. It could be removed unless needed for other operations.
  1. Variable Declaration
value = 1.1
  • value = 1.1: Declares a floating-point variable value and initializes it with 1.1.
  1. Defining the almost_equal Function
def almost_equal(a, b, delta=0.00001):
    if a == 0:
        return abs(b) <= delta
    if b == 0:
        return abs(a) <= delta
    return abs((a – b) / max(abs(a), abs(b))) <= delta
  • def almost_equal(a, b, delta=0.00001):: Defines a function almost_equal that checks if two floating-point numbers a and b are nearly equal, within a small threshold (delta).
  • delta=0.00001: This sets the default value of delta to 0.00001, representing the maximum difference for the numbers to be considered almost equal.
  • if a == 0:: If a is zero, the function checks if b is within the threshold.
  • if b == 0:: If b is zero, the function checks if a is within the threshold.
  • return abs((a – b) / max(abs(a), abs(b))) <= delta: For non-zero values, the function calculates the relative difference between a and b and checks if it’s within the threshold delta.
  1. Main Loop
while True:
    value -= 0.1
  • while True:: Starts an infinite loop, which runs continuously.
  • value -= 0.1: Decreases value by 0.1 each time the loop runs.
  1. Conditional Statements
if value == 0:
    print(“The value is exactly zero”)
elif almost_equal(value, 0):
    print(f“The value {value:.7f} is almost equal to zero, restarting countdown”)
    value = 1.1
else:
    print(value)
  • if value == 0:: Checks if value is exactly zero. If true, prints “The value is exactly zero.”
  • elif almost_equal(value, 0):: If value is not exactly zero, this condition checks if value is “almost equal” to zero using the almost_equal function. If true, it prints the value to 7 decimal places and resets value to 1.1.
  • else:: If neither condition is true, it simply prints the current value.
  1. Delay
time.sleep(0.25)
  • time.sleep(0.25): Pauses the loop for 0.25 seconds before continuing.

Summary

  • Precision Issues: Floating-point numbers are approximations. Precision issues can arise, especially with repetitive calculations.
  • Comparison Challenges: Use tolerance-based methods to compare floating-point numbers.
  • Tolerance Setting: Adjust the delta value for your application’s needs.
  • Application Context: Understand the context and constraints of floating-point operations.
  • Microcontroller Constraints: Efficient handling of floating-point operations is crucial due to limited resources.

Leave a Reply

Your email address will not be published. Required fields are marked *