System.Single.Epsilon property

This article provides supplementary remarks to the reference documentation for this API.

The value of the Epsilon property reflects the smallest positive Single value that is significant in numeric operations or comparisons when the value of the Single instance is zero. For example, the following code shows that zero and Epsilon are considered to be unequal values, whereas zero and half the value of Epsilon are considered to be equal.

using System;

public class Example1
{
   public static void Main()
   {
      float[] values = { 0f, Single.Epsilon, Single.Epsilon * .5f };
      
      for (int ctr = 0; ctr <= values.Length - 2; ctr++)
      {
         for (int ctr2 = ctr + 1; ctr2 <= values.Length - 1; ctr2++)
         {
            Console.WriteLine("{0:r} = {1:r}: {2}", 
                              values[ctr], values[ctr2],  
                              values[ctr].Equals(values[ctr2]));
         }
         Console.WriteLine();
      }      
   }
}
// The example displays the following output:
//       0 = 1.401298E-45: False
//       0 = 0: True
//       
//       1.401298E-45 = 0: False
open System

let values = [ 0f; Single.Epsilon; Single.Epsilon * 0.5f ]

for i = 0 to values.Length - 2 do
    for i2 = i + 1 to values.Length - 1 do
        printfn $"{values[i]:r} = {values[i2]:r}: {values[i].Equals(values[i2])}"
    printfn ""
// The example displays the following output:
//       0 = 1.401298E-45: False
//       0 = 0: True
//       
//       1.401298E-45 = 0: False
Module Example1
    Public Sub Main()
        Dim values() As Single = {0, Single.Epsilon, Single.Epsilon * 0.5}

        For ctr As Integer = 0 To values.Length - 2
            For ctr2 As Integer = ctr + 1 To values.Length - 1
                Console.WriteLine("{0:r} = {1:r}: {2}",
                              values(ctr), values(ctr2),
                              values(ctr).Equals(values(ctr2)))
            Next
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output:
'       0 = 1.401298E-45: False
'       0 = 0: True
'       
'       1.401298E-45 = 0: False

More precisely, the single-precision floating-point format consists of a sign, a 23-bit mantissa or significand, and an 8-bit exponent. As the following example shows, zero has an exponent of -126 and a mantissa of 0. Epsilon has an exponent of -126 and a mantissa of 1. This means that Single.Epsilon is the smallest positive Single value that is greater than zero and represents the smallest possible value and the smallest possible increment for a Single whose exponent is -126.

using System;

public class Example2
{
   public static void Main()
   {
      float[] values = { 0.0f, Single.Epsilon };
      foreach (var value in values) {
         Console.WriteLine(GetComponentParts(value));
         Console.WriteLine();
      }   
   }

   private static string GetComponentParts(float value)
   {
      string result = String.Format("{0:R}: ", value);
      int indent = result.Length;

      // Convert the single to a 4-byte array.
      byte[] bytes = BitConverter.GetBytes(value);
      int formattedSingle = BitConverter.ToInt32(bytes, 0);
      
      // Get the sign bit (byte 3, bit 7).
      result += String.Format("Sign: {0}\n", 
                              (formattedSingle >> 31) != 0 ? "1 (-)" : "0 (+)");

      // Get the exponent (byte 2 bit 7 to byte 3, bits 6)
      int exponent =  (formattedSingle >> 23) & 0x000000FF;
      int adjustment = (exponent != 0) ? 127 : 126;
      result += String.Format("{0}Exponent: 0x{1:X4} ({1})\n", new String(' ', indent), exponent - adjustment);

      // Get the significand (bits 0-22)
      long significand = exponent != 0 ? 
                         ((formattedSingle & 0x007FFFFF) | 0x800000) : 
                         (formattedSingle & 0x007FFFFF); 
      result += String.Format("{0}Mantissa: 0x{1:X13}\n", new String(' ', indent), significand);    
      return result;   
   }
}
//       // The example displays the following output:
//       0: Sign: 0 (+)
//          Exponent: 0xFFFFFF82 (-126)
//          Mantissa: 0x0000000000000
//       
//       
//       1.401298E-45: Sign: 0 (+)
//                     Exponent: 0xFFFFFF82 (-126)
//                     Mantissa: 0x0000000000001
open System

let getComponentParts (value: float32) =
    let result = $"{value:R}: "
    let indent = result.Length

    // Convert the single to a 4-byte array.
    let bytes = BitConverter.GetBytes value
    let formattedSingle = BitConverter.ToInt32(bytes, 0)
    
    // Get the sign bit (byte 3, bit 7).
    let result = result + $"""Sign: {if formattedSingle >>> 31 <> 0 then "1 (-)" else "0 (+)"}\n""" 

    // Get the exponent (byte 2 bit 7 to byte 3, bits 6)
    let exponent =  (formattedSingle >>> 23) &&& 0x000000FF
    let adjustment = if exponent <> 0 then 127 else 126
    let result = result + $"{String(' ', indent)}Exponent: 0x{1:X4} ({exponent - adjustment})\n"

    // Get the significand (bits 0-22)
    let significand = 
        if exponent <> 0 then 
            (formattedSingle &&& 0x007FFFFF) ||| 0x800000
        else 
            formattedSingle &&& 0x007FFFFF
             
    result + $"{String(' ', indent)}Mantissa: 0x{significand:X13}\n"


let values = [ 0f; Single.Epsilon ]
for value in values do
    printfn $"{getComponentParts value}\n"
//       // The example displays the following output:
//       0: Sign: 0 (+)
//          Exponent: 0xFFFFFF82 (-126)
//          Mantissa: 0x0000000000000
//       
//       
//       1.401298E-45: Sign: 0 (+)
//                     Exponent: 0xFFFFFF82 (-126)
//                     Mantissa: 0x0000000000001
Module Example2
    Public Sub Main()
        Dim values() As Single = {0.0, Single.Epsilon}
        For Each value In values
            Console.WriteLine(GetComponentParts(value))
            Console.WriteLine()
        Next
    End Sub

    Private Function GetComponentParts(value As Single) As String
        Dim result As String = String.Format("{0:R}: ", value)
        Dim indent As Integer = result.Length

        ' Convert the single to an 8-byte array.
        Dim bytes() As Byte = BitConverter.GetBytes(value)
        Dim formattedSingle As Integer = BitConverter.ToInt32(bytes, 0)

        ' Get the sign bit (byte 3, bit 7).
        result += String.Format("Sign: {0}{1}",
                              If(formattedSingle >> 31 <> 0, "1 (-)", "0 (+)"),
                              vbCrLf)

        ' Get the exponent (byte 2 bit 7 to byte 3, bits 6)
        Dim exponent As Integer = (formattedSingle >> 23) And &HFF
        Dim adjustment As Integer = If(exponent <> 0, 127, 126)
        result += String.Format("{0}Exponent: 0x{1:X4} ({1}){2}",
                              New String(" "c, indent), exponent - adjustment,
                              vbCrLf)

        ' Get the significand (bits 0-22)
        Dim significand As Long = If(exponent <> 0,
                         (formattedSingle And &H7FFFFF) Or &H800000,
                         formattedSingle And &H7FFFFF)
        result += String.Format("{0}Mantissa: 0x{1:X13}{2}",
                              New String(" "c, indent), significand, vbCrLf)

        Return result
    End Function
End Module
' The example displays the following output:
'       0: Sign: 0 (+)
'          Exponent: 0xFFFFFF82 (-126)
'          Mantissa: 0x0000000000000
'       
'       
'       1.401298E-45: Sign: 0 (+)
'                     Exponent: 0xFFFFFF82 (-126)
'                     Mantissa: 0x0000000000001

However, the Epsilon property is not a general measure of precision of the Single type; it applies only to Single instances that have a value of zero.

Note

The value of the Epsilon property is not equivalent to machine epsilon, which represents the upper bound of the relative error due to rounding in floating-point arithmetic.

The value of this constant is 1.4e-45.

Two apparently equivalent floating-point numbers might not compare equal because of differences in their least significant digits. For example, the C# expression, (float)1/3 == (float)0.33333, does not compare equal because the division operation on the left side has maximum precision while the constant on the right side is precise only to the specified digits. If you create a custom algorithm that determines whether two floating-point numbers can be considered equal, you must use a value that is greater than the Epsilon constant to establish the acceptable absolute margin of difference for the two values to be considered equal. (Typically, that margin of difference is many times greater than Epsilon.)

Platform notes

On ARM systems, the value of the Epsilon constant is too small to be detected, so it equates to zero. You can define an alternative epsilon value that equals 1.175494351E-38 instead.