System.Single.Epsilon 屬性
本文提供此 API 參考文件的補充備註。
屬性值會反映實例值為 Epsilon 零時,數值作業或比較中最小的正 Single 值 Single 。 例如,下列程式代碼顯示零和 Epsilon 視為不相等值,而 零和一半的值 Epsilon 視為相等。
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
更精確地說,單精度浮點格式包含符號、23 位的 mantissa 或 significand,以及 8 位指數。 如下列範例所示,零的指數為 -126,而 mantissa 為 0。 Epsilon 指數為 -126,且指數為 1。 這表示 Single.Epsilon 是大於零的最小正 Single 值,代表最小的可能值,以及其指數為 -126 的最小可能遞增 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 一般量值;它只適用於 Single 值為零的實例。
注意
屬性的值 Epsilon 不等於計算機 epsilon,這表示因浮點算術四捨五入而造成相對誤差的上限。
這個常數的值是 1.4e-45。
兩個明顯相等的浮點數可能不會比較相等,因為其最小有效位數的差異。 例如,C# 運算式 (float)1/3 == (float)0.33333
不會比較相等,因為左邊的除法運算具有最大精確度,而右邊的常數只精確到指定的數位。 如果您建立自定義演算法來判斷兩個浮點數是否可視為相等,您必須使用大於 Epsilon 常數的值,為兩個值建立可接受的絕對差異邊界,才能視為相等。 (一般而言,差異的邊界是大於 Epsilon的倍數。
平臺注意事項
在 ARM 系統上,常數的值 Epsilon 太小而無法偵測到,因此相當於零。 您可以定義等於 1.175494351E-38 的替代 epsilon 值。