Before we get to understand epsilon, let us first understand what is precision of a number?
What is precision?
As we have explained in detail in “The book of C”, each data type has a finite memory allocated to it and hence it can store finite range of data. In case of floating point numbers memory utilization includes another parameter – precision.
In simple terms, precision is a measure of accuracy. For example, 3.14 and 3.14285714 are both values of pi. However, 3.14285714 is a more precise value of pi, or in other words it has higher precision. You would need more memory to store all the extra digits in 3.14285714.
Let’s consider the following example.
01: #include <stdio.h>
02: int main(int argc, char * argv[]) {
03: float f = 0.1;
04: float sum = 0, product = 0;
05: sum = f + f + f + f + f + f + f + f + f + f;
06: product = f * 10;
07: if (sum == product) {
08: printf(“Sum and product are same\n”);
09: } else {
10: printf(“Sum and product are not same\n”);
11: }
12: printf(“Sum is %.15f, product is %.15f\n”, sum, product);
13: return 0;
14: }
In this example, we are using two different methods to arrive at value 1.0. At line 06, we have added 0.1 to itself 10 times, for which the result should be 1.0. At line 07, we have multiplied 0.1 by 10, which should again evaluate to 1.0. Hence logically, the comparison at line 08 should evaluate to true. However, the output of above program when executed is,
Sum and product are not same
Sum is 1.000000119209290, product is 1.000000000000000
[Note: Results may vary with compiler, CPU and certain compiler settings]
What happened? Why didn’t sum and product match? The answer lies in the precision of type float (or double). When you derive the same value, but via different arithmetic operations, it may or may not lead to exact same value. Due to rounding errors, most floating-point numbers end up being slightly imprecise.
However there must be some way to do floating point numbers arithmetic with a deterministic output. The answer lies in epsilon.
What is epsilon?
Epsilon defines the minimum precision the system guarantees for float, double and long double datatypes. These are defined by following pre-defined macros, defined in file <cfloat.h>:
FLT_EPSILON /* Defines precision for float datatype */
DBL_EPSILON /*Defines precision for double datatype */
LDBL_EPSILON /* Defines precision for long double datatype*/
Mathematically, we can say that FLT_EPSILON is a value such that
(number – FLT_EPSILON) < number < (number + FLT_EPSILON)
where ‘number’ is a variable of float datatype.
Compare using epsilon
Let us re-write the example in this article and perform comparison of float numbers using epsilon. The if-else construct in above example can be rewritten as:
07: if ((sum – product) < FLT_EPSILON) {
08: printf(“Sum and product are same\n”);
09: } else {
10: printf(“Sum and product are not same\n”);
11: }
Now the output on console is what we expected it to be in first place:
Sum and product are same
Sum is 1.000000119209290, product is 1.000000000000000
C standard guarantees minimum epsilon for float to be 1E-5, i.e. 1 X 10-5 or 0.00001. Hence any value that is greater than 0.99999 and less than 1.00001 is effectively 1.0.
Epsilon value for double and long double is defined to be at least 1E-9. However it is advisable to use the exact value defined for a system using the above defined system macros for all arithmetic or logical operations.