다음을 통해 공유


System.Single.Epsilon 속성

이 문서는 이 API에 대한 참조 설명서를 보충하는 추가 설명을 제공합니다.

Epsilon 속성 값은 Single 인스턴스의 값이 0일 경우 숫자 연산 또는 비교에서 중요한 가장 작은 양의 Single 값을 반영합니다. 예를 들어 다음 코드에서는 0과 Epsilon 같지 않은 값으로 간주되는 반면, Epsilon 값의 0과 절반은 같은 것으로 간주됩니다.

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

보다 정확하게 말하자면, 단정밀도 부동 소수점 형식은 부호, 23비트 매니티사 또는 유의성 및 8비트 지수로 구성됩니다. 다음 예제에서 알 수 있듯이 0에는 지수가 -126 및 매니티사는 0입니다. Epsilon 에는 -126 지수와 1의 가수가 있습니다. 즉, Single.Epsilon 0보다 크고 가능한 가장 작은 값과 지수가 -126인 값에 대해 Single 가능한 가장 작은 증분을 나타내는 가장 작은 양의 Single 값입니다.

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

그러나 Epsilon 속성은 형식의 Single 전체 자릿수에 대한 일반적인 측정값이 아니며 값이 0인 인스턴스에 Single 만 적용됩니다.

비고

Epsilon 속성의 값은 부동 소수점 산술 연산의 반올림으로 인한 상대 오차의 상한을 나타내는 컴퓨터 엡실론과 동일하지 않습니다.

이 상수의 값은 1.4e-45입니다.

두 개의 분명히 동등한 부동 소수점 숫자는 가장 낮은 유효 자릿수의 차이로 인해 같지 않을 수 있습니다. 예를 들어, C# 식((float)1/3 == (float)0.33333)은 왼쪽의 나누기 연산이 최대 정밀도를 가지지만, 오른쪽의 상수는 정확도가 지정된 자릿수로 제한되어 있기 때문에 동일하게 비교되지 않습니다. 두 부동 소수점 숫자를 같음으로 간주할 수 있는지 여부를 결정하는 사용자 지정 알고리즘을 만드는 경우 상수보다 Epsilon 큰 값을 사용하여 두 값이 같은 것으로 간주될 수 있는 절대 차이 여백을 설정해야 합니다. (일반적으로 차이의 여백은 Epsilon보다 여러 배 더 큽니다.)

플랫폼 참고 사항

ARM 시스템에서는 Epsilon 상수의 값이 너무 작아 감지할 수 없으므로 0과 같습니다. 대신 1.175494351E-38과 같은 대체 엡실론 값을 정의할 수 있습니다.