Partager via


Propriété System.Single.Epsilon

Cet article fournit des remarques supplémentaires à la documentation de référence de cette API.

La valeur de la Epsilon propriété reflète la plus petite valeur positive Single significative dans les opérations numériques ou les comparaisons lorsque la valeur de l’instance Single est égale à zéro. Par exemple, le code suivant montre que zéro et Epsilon sont considérés comme des valeurs inégales, tandis que zéro et la moitié de Epsilon la valeur sont considérées comme égales.

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($"{values[ctr]:r} = {values[ctr2]:r}: {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

Plus précisément, le format à virgule flottante simple précision se compose d'un signe, d'une mantisse ou d'un significande de 23 bits, et d'un exposant de 8 bits. Comme l’illustre l’exemple suivant, zéro a un exposant de -126 et une mantisse de 0. Epsilon a un exposant de -126 et une mantisse de 1. Cela signifie que Single.Epsilon est la plus petite valeur positive Single supérieure à zéro et représente la plus petite valeur possible et le plus petit incrément possible pour un Single dont l'exposant est égal à -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

Toutefois, la propriété n’est pas une mesure générale de précision du Epsilon type ; elle s’applique uniquement aux instances dont la Single valeur est égale à Single zéro.

Remarque

La valeur de la Epsilon propriété n’est pas équivalente à l'epsilon de machine, qui représente la borne supérieure de l’erreur relative provoquée par l’arrondi en arithmétique à virgule flottante.

La valeur de cette constante est 1,4e-45.

Deux nombres à virgule flottante apparemment équivalents peuvent ne pas être égaux lors de la comparaison en raison de différences dans leurs chiffres les plus insignifiants. Par exemple, l’expression C#, (float)1/3 == (float)0.33333, n’est pas égale parce que l’opération de division sur la partie gauche est à la précision maximale, tandis que la constante de la partie droite est exacte seulement jusqu’aux chiffres spécifiés. Si vous créez un algorithme personnalisé qui détermine si deux nombres à virgule flottante peuvent être considérés comme égaux, vous devez utiliser une valeur supérieure à la Epsilon constante pour établir la marge absolue acceptable de différence pour les deux valeurs à considérer comme égales. (En règle générale, cette marge de différence est plusieurs fois supérieure à Epsilon.)

Notes de plateforme

Sur les systèmes ARM, la valeur de la Epsilon constante est trop petite pour être détectée, de sorte qu’elle équivaut à zéro. Vous pouvez définir une autre valeur epsilon égale à 1,175494351E-38 à la place.