Double 结构
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
表示一个双精度浮点数。
public value class double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, IFormattable
public value class double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, ISpanFormattable
public value class double : IComparable, IConvertible, IFormattable
public value class double : IComparable, IComparable<double>, IEquatable<double>, IFormattable
public struct Double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, IFormattable
public struct Double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, ISpanFormattable
[System.Serializable]
public struct Double : IComparable, IConvertible, IFormattable
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public struct Double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, IFormattable
public struct Double : IComparable, IComparable<double>, IEquatable<double>, IFormattable
type double = struct
interface IConvertible
interface IFormattable
type double = struct
interface IConvertible
interface ISpanFormattable
interface IFormattable
[<System.Serializable>]
type double = struct
interface IFormattable
interface IConvertible
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type double = struct
interface IFormattable
interface IConvertible
type double = struct
interface IFormattable
Public Structure Double
Implements IComparable, IComparable(Of Double), IConvertible, IEquatable(Of Double), IFormattable
Public Structure Double
Implements IComparable, IComparable(Of Double), IConvertible, IEquatable(Of Double), ISpanFormattable
Public Structure Double
Implements IComparable, IConvertible, IFormattable
Public Structure Double
Implements IComparable, IComparable(Of Double), IEquatable(Of Double), IFormattable
- 继承
- 属性
- 实现
示例
下面的代码示例阐释了的用法 Double :
// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
public ref class Temperature: public IComparable, public IFormattable
{
// IComparable.CompareTo implementation.
public:
virtual int CompareTo( Object^ obj )
{
if (obj == nullptr) return 1;
if (dynamic_cast<Temperature^>(obj) )
{
Temperature^ temp = (Temperature^)(obj);
return m_value.CompareTo( temp->m_value );
}
throw gcnew ArgumentException( "object is not a Temperature" );
}
// IFormattable.ToString implementation.
virtual String^ ToString( String^ format, IFormatProvider^ provider )
{
if ( format != nullptr )
{
if ( format->Equals( "F" ) )
{
return String::Format( "{0}'F", this->Value.ToString() );
}
if ( format->Equals( "C" ) )
{
return String::Format( "{0}'C", this->Celsius.ToString() );
}
}
return m_value.ToString( format, provider );
}
// Parses the temperature from a string in the form
// [ws][sign]digits['F|'C][ws]
static Temperature^ Parse( String^ s, NumberStyles styles, IFormatProvider^ provider )
{
Temperature^ temp = gcnew Temperature;
if ( s->TrimEnd(nullptr)->EndsWith( "'F" ) )
{
temp->Value = Double::Parse( s->Remove( s->LastIndexOf( '\'' ), 2 ), styles, provider );
}
else
if ( s->TrimEnd(nullptr)->EndsWith( "'C" ) )
{
temp->Celsius = Double::Parse( s->Remove( s->LastIndexOf( '\'' ), 2 ), styles, provider );
}
else
{
temp->Value = Double::Parse( s, styles, provider );
}
return temp;
}
protected:
double m_value;
public:
property double Value
{
double get()
{
return m_value;
}
void set( double value )
{
m_value = value;
}
}
property double Celsius
{
double get()
{
return (m_value - 32.0) / 1.8;
}
void set( double value )
{
m_value = 1.8 * value + 32.0;
}
}
};
// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
public class Temperature : IComparable, IFormattable
{
// IComparable.CompareTo implementation.
public int CompareTo(object obj) {
if (obj == null) return 1;
Temperature temp = obj as Temperature;
if (obj != null)
return m_value.CompareTo(temp.m_value);
else
throw new ArgumentException("object is not a Temperature");
}
// IFormattable.ToString implementation.
public string ToString(string format, IFormatProvider provider) {
if( format != null ) {
if( format.Equals("F") ) {
return String.Format("{0}'F", this.Value.ToString());
}
if( format.Equals("C") ) {
return String.Format("{0}'C", this.Celsius.ToString());
}
}
return m_value.ToString(format, provider);
}
// Parses the temperature from a string in the form
// [ws][sign]digits['F|'C][ws]
public static Temperature Parse(string s, NumberStyles styles, IFormatProvider provider) {
Temperature temp = new Temperature();
if( s.TrimEnd(null).EndsWith("'F") ) {
temp.Value = Double.Parse( s.Remove(s.LastIndexOf('\''), 2), styles, provider);
}
else if( s.TrimEnd(null).EndsWith("'C") ) {
temp.Celsius = Double.Parse( s.Remove(s.LastIndexOf('\''), 2), styles, provider);
}
else {
temp.Value = Double.Parse(s, styles, provider);
}
return temp;
}
// The value holder
protected double m_value;
public double Value {
get {
return m_value;
}
set {
m_value = value;
}
}
public double Celsius {
get {
return (m_value-32.0)/1.8;
}
set {
m_value = 1.8*value+32.0;
}
}
}
' Temperature class stores the value as Double
' and delegates most of the functionality
' to the Double implementation.
Public Class Temperature
Implements IComparable, IFormattable
Public Overloads Function CompareTo(ByVal obj As Object) As Integer _
Implements IComparable.CompareTo
If TypeOf obj Is Temperature Then
Dim temp As Temperature = CType(obj, Temperature)
Return m_value.CompareTo(temp.m_value)
End If
Throw New ArgumentException("object is not a Temperature")
End Function
Public Overloads Function ToString(ByVal format As String, ByVal provider As IFormatProvider) As String _
Implements IFormattable.ToString
If Not (format Is Nothing) Then
If format.Equals("F") Then
Return [String].Format("{0}'F", Me.Value.ToString())
End If
If format.Equals("C") Then
Return [String].Format("{0}'C", Me.Celsius.ToString())
End If
End If
Return m_value.ToString(format, provider)
End Function
' Parses the temperature from a string in form
' [ws][sign]digits['F|'C][ws]
Public Shared Function Parse(ByVal s As String, ByVal styles As NumberStyles, ByVal provider As IFormatProvider) As Temperature
Dim temp As New Temperature()
If s.TrimEnd(Nothing).EndsWith("'F") Then
temp.Value = Double.Parse(s.Remove(s.LastIndexOf("'"c), 2), styles, provider)
Else
If s.TrimEnd(Nothing).EndsWith("'C") Then
temp.Celsius = Double.Parse(s.Remove(s.LastIndexOf("'"c), 2), styles, provider)
Else
temp.Value = Double.Parse(s, styles, provider)
End If
End If
Return temp
End Function
' The value holder
Protected m_value As Double
Public Property Value() As Double
Get
Return m_value
End Get
Set(ByVal Value As Double)
m_value = Value
End Set
End Property
Public Property Celsius() As Double
Get
Return (m_value - 32) / 1.8
End Get
Set(ByVal Value As Double)
m_value = Value * 1.8 + 32
End Set
End Property
End Class
注解
值类型表示一个双精度 64 位数字,其值范围从负 Double 1.79769313486232e308 到正 1.79769313486232e308,以及正零或负零、、 和不是数字 PositiveInfinity NegativeInfinity (NaN) 。 它旨在表示非常大的 (值,例如行星或行星之间的距离) 或极小的 (,例如) 中的分子质量,并且通常不精确 (例如从地球到另一个太阳能系统) 的距离。 类型 Double 符合 IEC 60559:1989 (IEEE 754) 二进制浮点算法的标准。
本主题包括以下各节:
Floating-Point表示形式和精度
Double数据类型以 64 位二进制格式存储双精度浮点值,如下表所示:
组成部分 | Bits |
---|---|
Significand 或 mantissa | 0-51 |
Exponent | 52-62 |
符号 (0 = 正,1 = 负) | 63 |
正如小数部分无法精确表示某些小数值一样 (例如 1/3 或) ,二进制分数无法表示某些 Math.PI 小数值。 例如,1/10(由 .1 精确表示为十进制分数)由 .001100110011 表示为二进制分数,模式"0011"重复为无穷大。 在这种情况下,浮点值提供其表示数字的不精确表示形式。 对原始浮点值执行其他数学运算通常会增加其精度不足。 例如,如果我们比较将 .1 乘以 10 并将 .1 相加 9 次的结果,则会看到该加法,因为它又涉及 8 个操作,因此生成的结果不太精确。 请注意,只有在使用"R"标准数字格式字符串 显示这两个值时,这种差异才明显,该字符串在必要时显示类型支持的所有 Double 17 位 Double 精度。
using System;
public class Example
{
public static void Main()
{
Double value = .1;
Double result1 = value * 10;
Double result2 = 0;
for (int ctr = 1; ctr <= 10; ctr++)
result2 += value;
Console.WriteLine(".1 * 10: {0:R}", result1);
Console.WriteLine(".1 Added 10 times: {0:R}", result2);
}
}
// The example displays the following output:
// .1 * 10: 1
// .1 Added 10 times: 0.99999999999999989
Module Example
Public Sub Main()
Dim value As Double = .1
Dim result1 As Double = value * 10
Dim result2 As Double
For ctr As Integer = 1 To 10
result2 += value
Next
Console.WriteLine(".1 * 10: {0:R}", result1)
Console.WriteLine(".1 Added 10 times: {0:R}", result2)
End Sub
End Module
' The example displays the following output:
' .1 * 10: 1
' .1 Added 10 times: 0.99999999999999989
由于某些数字不能完全表示为小数二进制值,浮点数只能近似实数。
所有浮点数还具有有限数量的有效数字,这也决定了浮点值与实数的近似值。 值具有最多 15 位小数位数的精度,但内部最多保留 Double 17 位数字。 这意味着某些浮点运算可能缺少更改浮点值的精度。 下面的示例进行了这方面的演示。 它定义一个非常大的浮点值,然后将 的和 Double.Epsilon 一个四边形的产品添加到其中。 但是,该产品太小,不能修改原始浮点值。 其最低有效位数是千分之几,而产品中最重要的数字是 10-309。
using System;
public class Example
{
public static void Main()
{
Double value = 123456789012.34567;
Double additional = Double.Epsilon * 1e15;
Console.WriteLine("{0} + {1} = {2}", value, additional,
value + additional);
}
}
// The example displays the following output:
// 123456789012.346 + 4.94065645841247E-309 = 123456789012.346
Module Example
Public Sub Main()
Dim value As Double = 123456789012.34567
Dim additional As Double = Double.Epsilon * 1e15
Console.WriteLine("{0} + {1} = {2}", value, additional,
value + additional)
End Sub
End Module
' The example displays the following output:
' 123456789012.346 + 4.94065645841247E-309 = 123456789012.346
浮点数的有限精度会产生多种后果:
对于特定精度,看起来相等的两个浮点数在进行比较时可能不相等,因为其最小有效位不同。 在下面的示例中,将一系列数字相加,其总数与预期总数进行比较。 尽管这两个值看起来相同,但调用
Equals
方法会指示它们不同。using System; public class Example { public static void Main() { Double[] values = { 10.0, 2.88, 2.88, 2.88, 9.0 }; Double result = 27.64; Double total = 0; foreach (var value in values) total += value; if (total.Equals(result)) Console.WriteLine("The sum of the values equals the total."); else Console.WriteLine("The sum of the values ({0}) does not equal the total ({1}).", total, result); } } // The example displays the following output: // The sum of the values (36.64) does not equal the total (36.64). // // If the index items in the Console.WriteLine statement are changed to {0:R}, // the example displays the following output: // The sum of the values (27.639999999999997) does not equal the total (27.64).
Module Example Public Sub Main() Dim values() As Double = { 10.0, 2.88, 2.88, 2.88, 9.0 } Dim result As Double = 27.64 Dim total As Double For Each value In values total += value Next If total.Equals(result) Then Console.WriteLine("The sum of the values equals the total.") Else Console.WriteLine("The sum of the values ({0}) does not equal the total ({1}).", total, result) End If End Sub End Module ' The example displays the following output: ' The sum of the values (36.64) does not equal the total (36.64). ' ' If the index items in the Console.WriteLine statement are changed to {0:R}, ' the example displays the following output: ' The sum of the values (27.639999999999997) does not equal the total (27.64).
如果将 语句中的格式项从 和 更改为 ,以显示这两个值的所有有效位数,则很明显,由于加法运算期间精度损失,这两个值不 Console.WriteLine(String, Object, Object)
{0}
{1}
{0:R}
{1:R}
Double 相等。 在这种情况下,可以通过调用 方法将值舍入为所需的精度,然后再 Math.Round(Double, Int32) Double 执行比较来解决此问题。如果使用十进制数,则使用浮点数的数学运算或比较运算可能不会生成相同的结果,因为二进制浮点数可能不等于十进制数。 前面的示例通过显示将 .1 乘以 10 并添加 .1 次的结果来说明这一点。
当具有小数值的数值运算的准确性很重要时,可以使用 Decimal 而不是 Double 类型。 如果整数值超出 或 类型的数值运算的准确性 Int64 UInt64 很重要,请使用 BigInteger 类型。
如果涉及浮点数,则值可能不会往返。 如果操作将原始浮点数转换为另一种形式,则值将表示往返;反向运算将转换后的窗体转换回浮点数,最后一个浮点数不等于原始浮点数。 往返可能会失败,因为在转换中丢失或更改了一个或多个最低有效位数。 在下面的示例中,三 Double 个值转换为字符串并保存在文件中。 但是,如输出所示,即使值看起来相同,还原的值也与原始值不相等。
using System; using System.IO; public class Example { public static void Main() { StreamWriter sw = new StreamWriter(@".\Doubles.dat"); Double[] values = { 2.2/1.01, 1.0/3, Math.PI }; for (int ctr = 0; ctr < values.Length; ctr++) { sw.Write(values[ctr].ToString()); if (ctr != values.Length - 1) sw.Write("|"); } sw.Close(); Double[] restoredValues = new Double[values.Length]; StreamReader sr = new StreamReader(@".\Doubles.dat"); string temp = sr.ReadToEnd(); string[] tempStrings = temp.Split('|'); for (int ctr = 0; ctr < tempStrings.Length; ctr++) restoredValues[ctr] = Double.Parse(tempStrings[ctr]); for (int ctr = 0; ctr < values.Length; ctr++) Console.WriteLine("{0} {2} {1}", values[ctr], restoredValues[ctr], values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>"); } } // The example displays the following output: // 2.17821782178218 <> 2.17821782178218 // 0.333333333333333 <> 0.333333333333333 // 3.14159265358979 <> 3.14159265358979
Imports System.IO Module Example Public Sub Main() Dim sw As New StreamWriter(".\Doubles.dat") Dim values() As Double = { 2.2/1.01, 1.0/3, Math.PI } For ctr As Integer = 0 To values.Length - 1 sw.Write(values(ctr).ToString()) If ctr <> values.Length - 1 Then sw.Write("|") Next sw.Close() Dim restoredValues(values.Length - 1) As Double Dim sr As New StreamReader(".\Doubles.dat") Dim temp As String = sr.ReadToEnd() Dim tempStrings() As String = temp.Split("|"c) For ctr As Integer = 0 To tempStrings.Length - 1 restoredValues(ctr) = Double.Parse(tempStrings(ctr)) Next For ctr As Integer = 0 To values.Length - 1 Console.WriteLine("{0} {2} {1}", values(ctr), restoredValues(ctr), If(values(ctr).Equals(restoredValues(ctr)), "=", "<>")) Next End Sub End Module ' The example displays the following output: ' 2.17821782178218 <> 2.17821782178218 ' 0.333333333333333 <> 0.333333333333333 ' 3.14159265358979 <> 3.14159265358979
在这种情况下,可以使用"G17"标准数字格式字符串来成功往返这些值,以保留值的完整精度, Double 如以下示例所示。
using System; using System.IO; public class Example { public static void Main() { StreamWriter sw = new StreamWriter(@".\Doubles.dat"); Double[] values = { 2.2/1.01, 1.0/3, Math.PI }; for (int ctr = 0; ctr < values.Length; ctr++) sw.Write("{0:G17}{1}", values[ctr], ctr < values.Length - 1 ? "|" : "" ); sw.Close(); Double[] restoredValues = new Double[values.Length]; StreamReader sr = new StreamReader(@".\Doubles.dat"); string temp = sr.ReadToEnd(); string[] tempStrings = temp.Split('|'); for (int ctr = 0; ctr < tempStrings.Length; ctr++) restoredValues[ctr] = Double.Parse(tempStrings[ctr]); for (int ctr = 0; ctr < values.Length; ctr++) Console.WriteLine("{0} {2} {1}", values[ctr], restoredValues[ctr], values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>"); } } // The example displays the following output: // 2.17821782178218 = 2.17821782178218 // 0.333333333333333 = 0.333333333333333 // 3.14159265358979 = 3.14159265358979
Imports System.IO Module Example Public Sub Main() Dim sw As New StreamWriter(".\Doubles.dat") Dim values() As Double = { 2.2/1.01, 1.0/3, Math.PI } For ctr As Integer = 0 To values.Length - 1 sw.Write("{0:G17}{1}", values(ctr), If(ctr < values.Length - 1, "|", "")) Next sw.Close() Dim restoredValues(values.Length - 1) As Double Dim sr As New StreamReader(".\Doubles.dat") Dim temp As String = sr.ReadToEnd() Dim tempStrings() As String = temp.Split("|"c) For ctr As Integer = 0 To tempStrings.Length - 1 restoredValues(ctr) = Double.Parse(tempStrings(ctr)) Next For ctr As Integer = 0 To values.Length - 1 Console.WriteLine("{0} {2} {1}", values(ctr), restoredValues(ctr), If(values(ctr).Equals(restoredValues(ctr)), "=", "<>")) Next End Sub End Module ' The example displays the following output: ' 2.17821782178218 = 2.17821782178218 ' 0.333333333333333 = 0.333333333333333 ' 3.14159265358979 = 3.14159265358979
Single 值的精度低于 Double 值。 由于 Single 精度差异,转换为看似等效的值通常 Double Double 不等于值。 在下面的示例中,相同的除法运算的结果将分配给 Double 和 Single 值。 将 Single 值强制转换到 Double 后,两个值的比较显示它们不相等。
using System; public class Example { public static void Main() { Double value1 = 1/3.0; Single sValue2 = 1/3.0f; Double value2 = (Double) sValue2; Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2)); } } // The example displays the following output: // 0.33333333333333331 = 0.3333333432674408: False
Module Example Public Sub Main() Dim value1 As Double = 1/3 Dim sValue2 As Single = 1/3 Dim value2 As Double = CDbl(sValue2) Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2)) End Sub End Module ' The example displays the following output: ' 0.33333333333333331 = 0.3333333432674408: False
若要避免此问题,请使用 来表示数据类型,或使用 方法,使两 Double Single Round 个值具有相同的精度。
此外,由于类型的精度损失,具有值的算术和赋值运算的结果可能因平台而 Double 略有不同 Double 。 例如,分配文本值的结果在 32 位和 64 位版本的文本中 Double 可能.NET Framework。 当将文本值 -4.42330604244772E-305 和值为 -4.42330604244772E-305 的变量分配给变量时,以下示例演示了此差异。 Double 请注意,在这种情况下 Parse(String) , 方法的结果不会丢失精度。
double value = -4.42330604244772E-305;
double fromLiteral = -4.42330604244772E-305;
double fromVariable = value;
double fromParse = Double.Parse("-4.42330604244772E-305");
Console.WriteLine("Double value from literal: {0,29:R}", fromLiteral);
Console.WriteLine("Double value from variable: {0,28:R}", fromVariable);
Console.WriteLine("Double value from Parse method: {0,24:R}", fromParse);
// On 32-bit versions of the .NET Framework, the output is:
// Double value from literal: -4.42330604244772E-305
// Double value from variable: -4.42330604244772E-305
// Double value from Parse method: -4.42330604244772E-305
//
// On other versions of the .NET Framework, the output is:
// Double value from literal: -4.4233060424477198E-305
// Double value from variable: -4.4233060424477198E-305
// Double value from Parse method: -4.42330604244772E-305
Dim value As Double = -4.42330604244772E-305
Dim fromLiteral As Double = -4.42330604244772E-305
Dim fromVariable As Double = value
Dim fromParse As Double = Double.Parse("-4.42330604244772E-305")
Console.WriteLine("Double value from literal: {0,29:R}", fromLiteral)
Console.WriteLine("Double value from variable: {0,28:R}", fromVariable)
Console.WriteLine("Double value from Parse method: {0,24:R}", fromParse)
' On 32-bit versions of the .NET Framework, the output is:
' Double value from literal: -4.42330604244772E-305
' Double value from variable: -4.42330604244772E-305
' Double value from Parse method: -4.42330604244772E-305
'
' On other versions of the .NET Framework, the output is:
' Double value from literal: -4.4233060424477198E-305
' Double value from variable: -4.4233060424477198E-305
' Double value from Parse method: -4.42330604244772E-305
测试相等性
若要被视为相等,两 Double 个值必须表示相同的值。 但是,由于值之间的精度差异,或者由于一个或两个值的精度损失,预期相同的浮点值通常因最低有效位数的差异而不相等。 因此,调用 方法以确定两个值是否相等,或者调用 方法来确定两个值之间的关系,通常 Equals CompareTo Double 会产生意外的结果。 在下面的示例中,这一点很明显,其中两个明显相等的值不相等,因为第一个值的精度为 15 位,而第二个值的精度为 Double 17。
using System;
public class Example
{
public static void Main()
{
double value1 = .333333333333333;
double value2 = 1.0/3;
Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2));
}
}
// The example displays the following output:
// 0.333333333333333 = 0.33333333333333331: False
Module Example
Public Sub Main()
Dim value1 As Double = .333333333333333
Dim value2 As Double = 1/3
Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
End Sub
End Module
' The example displays the following output:
' 0.333333333333333 = 0.33333333333333331: False
遵循不同代码路径并按不同方式操作的计算值通常证明不相等。 在下面的示例中,一 Double 个值是平方的,然后计算平方根以还原原始值。 第二 Double 秒乘以 3.51,在结果的平方根除以 3.51 之前平方以还原原始值。 尽管这两个值看起来相同,但调用 方法会 Equals(Double) 指示它们不相等。 使用"R"标准格式字符串返回一个结果字符串,该字符串显示每个 Double 值的所有有效位数,表明第二个值小于第一个值0000000000001 .0000000000001。
using System;
public class Example
{
public static void Main()
{
double value1 = 100.10142;
value1 = Math.Sqrt(Math.Pow(value1, 2));
double value2 = Math.Pow(value1 * 3.51, 2);
value2 = Math.Sqrt(value2) / 3.51;
Console.WriteLine("{0} = {1}: {2}\n",
value1, value2, value1.Equals(value2));
Console.WriteLine("{0:R} = {1:R}", value1, value2);
}
}
// The example displays the following output:
// 100.10142 = 100.10142: False
//
// 100.10142 = 100.10141999999999
Module Example
Public Sub Main()
Dim value1 As Double = 100.10142
value1 = Math.Sqrt(Math.Pow(value1, 2))
Dim value2 As Double = Math.Pow(value1 * 3.51, 2)
value2 = Math.Sqrt(value2) / 3.51
Console.WriteLine("{0} = {1}: {2}",
value1, value2, value1.Equals(value2))
Console.WriteLine()
Console.WriteLine("{0:R} = {1:R}", value1, value2)
End Sub
End Module
' The example displays the following output:
' 100.10142 = 100.10142: False
'
' 100.10142 = 100.10141999999999
如果精度损失可能会影响比较结果,可以采用以下任一替代方法来调用 Equals 或 CompareTo 方法:
调用 Math.Round 方法以确保两个值具有相同的精度。 下面的示例修改了前面的示例以使用这种方法,以便两个小数值是等效的。
using System; public class Example { public static void Main() { double value1 = .333333333333333; double value2 = 1.0/3; int precision = 7; value1 = Math.Round(value1, precision); value2 = Math.Round(value2, precision); Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2)); } } // The example displays the following output: // 0.3333333 = 0.3333333: True
Module Example Public Sub Main() Dim value1 As Double = .333333333333333 Dim value2 As Double = 1/3 Dim precision As Integer = 7 value1 = Math.Round(value1, precision) value2 = Math.Round(value2, precision) Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2)) End Sub End Module ' The example displays the following output: ' 0.3333333 = 0.3333333: True
精度问题仍适用于中点值的舍入。 有关更多信息,请参见 Math.Round(Double, Int32, MidpointRounding) 方法。
测试近似相等性而不是相等性。 这要求你定义两个值可以不同但仍相等的绝对量,或者定义一个相对量,使较小的值与较大的值不同。
警告
Double.Epsilon 在测试相等性时,有时用作两个值 Double 之间的距离的绝对度量值。 但是,测量可加或减的值中可能最小的值,其 Double.Epsilon Double 值为零。 对于大多数正值和负 Double 值,的值 Double.Epsilon 太小,无法检测到。 因此,除了为零的值之外,我们不建议在测试是否相等时使用它。
下面的示例使用后一种方法定义
IsApproximatelyEqual
一个方法,该方法测试两个值之间的相对差异。 它还对比了对 方法和 方法IsApproximatelyEqual
的调用 Equals(Double) 结果。using System; public class Example { public static void Main() { double one1 = .1 * 10; double one2 = 0; for (int ctr = 1; ctr <= 10; ctr++) one2 += .1; Console.WriteLine("{0:R} = {1:R}: {2}", one1, one2, one1.Equals(one2)); Console.WriteLine("{0:R} is approximately equal to {1:R}: {2}", one1, one2, IsApproximatelyEqual(one1, one2, .000000001)); } static bool IsApproximatelyEqual(double value1, double value2, double epsilon) { // If they are equal anyway, just return True. if (value1.Equals(value2)) return true; // Handle NaN, Infinity. if (Double.IsInfinity(value1) | Double.IsNaN(value1)) return value1.Equals(value2); else if (Double.IsInfinity(value2) | Double.IsNaN(value2)) return value1.Equals(value2); // Handle zero to avoid division by zero double divisor = Math.Max(value1, value2); if (divisor.Equals(0)) divisor = Math.Min(value1, value2); return Math.Abs((value1 - value2) / divisor) <= epsilon; } } // The example displays the following output: // 1 = 0.99999999999999989: False // 1 is approximately equal to 0.99999999999999989: True
Module Example Public Sub Main() Dim one1 As Double = .1 * 10 Dim one2 As Double = 0 For ctr As Integer = 1 To 10 one2 += .1 Next Console.WriteLine("{0:R} = {1:R}: {2}", one1, one2, one1.Equals(one2)) Console.WriteLine("{0:R} is approximately equal to {1:R}: {2}", one1, one2, IsApproximatelyEqual(one1, one2, .000000001)) End Sub Function IsApproximatelyEqual(value1 As Double, value2 As Double, epsilon As Double) As Boolean ' If they are equal anyway, just return True. If value1.Equals(value2) Then Return True ' Handle NaN, Infinity. If Double.IsInfinity(value1) Or Double.IsNaN(value1) Then Return value1.Equals(value2) Else If Double.IsInfinity(value2) Or Double.IsNaN(value2) Return value1.Equals(value2) End If ' Handle zero to avoid division by zero Dim divisor As Double = Math.Max(value1, value2) If divisor.Equals(0) Then divisor = Math.Min(value1, value2) End If Return Math.Abs((value1 - value2) / divisor) <= epsilon End Function End Module ' The example displays the following output: ' 1 = 0.99999999999999989: False ' 1 is approximately equal to 0.99999999999999989: True
Floating-Point值和异常
与整型运算(在溢出或非法操作(如被零除)时引发异常)不同,浮点值运算不会引发异常。 相反,在异常情况下,浮点运算的结果是零、正无穷大、负无穷大或不是 NaN () :
如果浮点运算的结果对于目标格式来说太小,则结果为零。 当两个非常小的数字相乘时,可能会发生这种情况,如以下示例所示。
using System; public class Example { public static void Main() { Double value1 = 1.1632875981534209e-225; Double value2 = 9.1642346778e-175; Double result = value1 * value2; Console.WriteLine("{0} * {1} = {2}", value1, value2, result); Console.WriteLine("{0} = 0: {1}", result, result.Equals(0.0)); } } // The example displays the following output: // 1.16328759815342E-225 * 9.1642346778E-175 = 0 // 0 = 0: True
Module Example Public Sub Main() Dim value1 As Double = 1.1632875981534209e-225 Dim value2 As Double = 9.1642346778e-175 Dim result As Double = value1 * value2 Console.WriteLine("{0} * {1} = {2}", value1, value2, result) Console.WriteLine("{0} = 0: {1}", result, result.Equals(0.0)) End Sub End Module ' The example displays the following output: ' 1.16328759815342E-225 * 9.1642346778E-175 = 0 ' 0 = 0: True
如果浮点运算的结果数量超出目标格式的范围,则操作的结果为 或 ,这适用于结果 PositiveInfinity NegativeInfinity 的符号。 溢出的操作的结果是 ,溢出的操作的结果是 , Double.MaxValue PositiveInfinity Double.MinValue NegativeInfinity 如以下示例所示。
using System; public class Example { public static void Main() { Double value1 = 4.565e153; Double value2 = 6.9375e172; Double result = value1 * value2; Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)); Console.WriteLine("NegativeInfinity: {0}\n", Double.IsNegativeInfinity(result)); value1 = -value1; result = value1 * value2; Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)); Console.WriteLine("NegativeInfinity: {0}", Double.IsNegativeInfinity(result)); } } // The example displays the following output: // PositiveInfinity: True // NegativeInfinity: False // // PositiveInfinity: False // NegativeInfinity: True
Module Example Public Sub Main() Dim value1 As Double = 4.565e153 Dim value2 As Double = 6.9375e172 Dim result As Double = value1 * value2 Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)) Console.WriteLine("NegativeInfinity: {0}", Double.IsNegativeInfinity(result)) Console.WriteLine() value1 = -value1 result = value1 * value2 Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)) Console.WriteLine("NegativeInfinity: {0}", Double.IsNegativeInfinity(result)) End Sub End Module ' The example displays the following output: ' PositiveInfinity: True ' NegativeInfinity: False ' ' PositiveInfinity: False ' NegativeInfinity: True
PositiveInfinity 还从除数为零且正除数的结果,以及除数为 NegativeInfinity 零和负除数的结果。
如果浮点运算无效,则操作的结果是 NaN 。 例如, NaN 结果来自以下操作:
- 除数为零,除数为零。 请注意,其他被零除的情况会导致 或 PositiveInfinity NegativeInfinity 。
输入无效的任何浮点运算。 例如,使用负值调用 方法将返回 ,调用值大于 1 或小于负值的方法 Math.Sqrt NaN Math.Acos 也返回 。
具有值为 的参数的任何操作 Double.NaN 。
类型转换和 Double 结构
该 Double 结构不定义任何显式或隐式转换运算符; 相反,转换是由编译器实现的。
任何基元数值类型的值转换为 Double 扩大转换,因此不需要显式强制转换运算符或对转换方法的调用,除非编译器显式要求它。 例如,c # 编译器需要一个转换运算符用于从到的 Decimal 转换 Double ,而 Visual Basic 编译器则不需要。 下面的示例将其他基元数值类型的最小值或最大值转换为 Double 。
using System;
public class Example
{
public static void Main()
{
dynamic[] values = { Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
Decimal.MaxValue, Int16.MinValue, Int16.MaxValue,
Int32.MinValue, Int32.MaxValue, Int64.MinValue,
Int64.MaxValue, SByte.MinValue, SByte.MaxValue,
Single.MinValue, Single.MaxValue, UInt16.MinValue,
UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
UInt64.MinValue, UInt64.MaxValue };
double dblValue;
foreach (var value in values) {
if (value.GetType() == typeof(Decimal))
dblValue = (Double) value;
else
dblValue = value;
Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
value, value.GetType().Name,
dblValue, dblValue.GetType().Name);
}
}
}
// The example displays the following output:
// 0 (Byte) --> 0 (Double)
// 255 (Byte) --> 255 (Double)
// -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
// 79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
// -32768 (Int16) --> -32768 (Double)
// 32767 (Int16) --> 32767 (Double)
// -2147483648 (Int32) --> -2147483648 (Double)
// 2147483647 (Int32) --> 2147483647 (Double)
// -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
// 9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
// -128 (SByte) --> -128 (Double)
// 127 (SByte) --> 127 (Double)
// -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
// 3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
// 0 (UInt16) --> 0 (Double)
// 65535 (UInt16) --> 65535 (Double)
// 0 (UInt32) --> 0 (Double)
// 4294967295 (UInt32) --> 4294967295 (Double)
// 0 (UInt64) --> 0 (Double)
// 18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
Module Example
Public Sub Main()
Dim values() As Object = { Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
Decimal.MaxValue, Int16.MinValue, Int16.MaxValue,
Int32.MinValue, Int32.MaxValue, Int64.MinValue,
Int64.MaxValue, SByte.MinValue, SByte.MaxValue,
Single.MinValue, Single.MaxValue, UInt16.MinValue,
UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
UInt64.MinValue, UInt64.MaxValue }
Dim dblValue As Double
For Each value In values
dblValue = value
Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
value, value.GetType().Name,
dblValue, dblValue.GetType().Name)
Next
End Sub
End Module
' The example displays the following output:
' 0 (Byte) --> 0 (Double)
' 255 (Byte) --> 255 (Double)
' -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
' 79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
' -32768 (Int16) --> -32768 (Double)
' 32767 (Int16) --> 32767 (Double)
' -2147483648 (Int32) --> -2147483648 (Double)
' 2147483647 (Int32) --> 2147483647 (Double)
' -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
' 9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
' -128 (SByte) --> -128 (Double)
' 127 (SByte) --> 127 (Double)
' -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
' 3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
' 0 (UInt16) --> 0 (Double)
' 65535 (UInt16) --> 65535 (Double)
' 0 (UInt32) --> 0 (Double)
' 4294967295 (UInt32) --> 4294967295 (Double)
' 0 (UInt64) --> 0 (Double)
' 18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
此外, Single 值 Single.NaN 、 Single.PositiveInfinity 和 Single.NegativeInfinity 分别转换为、和 Double.NaN Double.PositiveInfinity Double.NegativeInfinity 。
请注意,某些数值类型的值到值的转换 Double 可能会导致精度损失。 如示例中所示,将 Decimal 、 Int64 和 UInt64 值转换为值时可能会丢失精度 Double 。
Double值到任何其他基元数值数据类型的值的转换是收缩转换,要求在 c # ) 中 (转换运算符、Visual Basic) 中 (转换方法或调用 Convert 方法。 超出目标数据类型范围的值(由目标类型的 MinValue
和 MaxValue
属性定义)的行为如下表中所示。
目标类型 | 结果 |
---|---|
任何整型 | OverflowException如果在检查的上下文中发生转换,则为异常。 如果在未检查的上下文中发生转换 (c # ) 中的默认值,则转换操作会成功,但值溢出。 |
Decimal | 一个 OverflowException 异常。 |
Single | Single.NegativeInfinity 对于负值,则为。 Single.PositiveInfinity 对于正值。 |
此外,、 Double.NaN 、 Double.PositiveInfinity 和将 Double.NegativeInfinity 引发, OverflowException 以便转换为已检查上下文中的整数,但这些值在转换为未检查的上下文中的整数时溢出。 对于到的转换 Decimal ,它们始终引发 OverflowException 。 对于到的转换 Single ,它们分别转换为 Single.NaN 、 Single.PositiveInfinity 和 Single.NegativeInfinity 。
请注意,将 Double 值转换为另一种数值类型可能会导致精度损失。 如果转换为任何整型类型,如示例的输出所示,当 Double 值舍入 (与 Visual Basic) 或截断 (如 c # ) 中的时,小数部分将丢失。 对于 Decimal 和值的转换 Single ,此 Double 值在目标数据类型中可能没有精确的表示形式。
下面的示例将多 Double 个值转换为多个其他数值类型。 由于checked关键字) ,转换在 Visual Basic (默认) 和 c # (中的检查上下文中进行。 该示例的输出显示了已检查的未检查上下文中的转换结果。 可以通过使用 /removeintchecks+
编译器开关进行编译,并通过注释掉语句,在 Visual Basic 中的未检查上下文中执行转换 checked
。
using System;
public class Example
{
public static void Main()
{
Double[] values = { Double.MinValue, -67890.1234, -12345.6789,
12345.6789, 67890.1234, Double.MaxValue,
Double.NaN, Double.PositiveInfinity,
Double.NegativeInfinity };
checked {
foreach (var value in values) {
try {
Int64 lValue = (long) value;
Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
value, value.GetType().Name,
lValue, lValue.GetType().Name);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert {0} to Int64.", value);
}
try {
UInt64 ulValue = (ulong) value;
Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
value, value.GetType().Name,
ulValue, ulValue.GetType().Name);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert {0} to UInt64.", value);
}
try {
Decimal dValue = (decimal) value;
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
dValue, dValue.GetType().Name);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert {0} to Decimal.", value);
}
try {
Single sValue = (float) value;
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
sValue, sValue.GetType().Name);
}
catch (OverflowException) {
Console.WriteLine("Unable to convert {0} to Single.", value);
}
Console.WriteLine();
}
}
}
}
// The example displays the following output for conversions performed
// in a checked context:
// Unable to convert -1.79769313486232E+308 to Int64.
// Unable to convert -1.79769313486232E+308 to UInt64.
// Unable to convert -1.79769313486232E+308 to Decimal.
// -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
// -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
// Unable to convert -67890.1234 to UInt64.
// -67890.1234 (Double) --> -67890.1234 (Decimal)
// -67890.1234 (Double) --> -67890.13 (Single)
//
// -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
// Unable to convert -12345.6789 to UInt64.
// -12345.6789 (Double) --> -12345.6789 (Decimal)
// -12345.6789 (Double) --> -12345.68 (Single)
//
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
// 12345.6789 (Double) --> 12345.6789 (Decimal)
// 12345.6789 (Double) --> 12345.68 (Single)
//
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
// 67890.1234 (Double) --> 67890.1234 (Decimal)
// 67890.1234 (Double) --> 67890.13 (Single)
//
// Unable to convert 1.79769313486232E+308 to Int64.
// Unable to convert 1.79769313486232E+308 to UInt64.
// Unable to convert 1.79769313486232E+308 to Decimal.
// 1.79769313486232E+308 (Double) --> Infinity (Single)
//
// Unable to convert NaN to Int64.
// Unable to convert NaN to UInt64.
// Unable to convert NaN to Decimal.
// NaN (Double) --> NaN (Single)
//
// Unable to convert Infinity to Int64.
// Unable to convert Infinity to UInt64.
// Unable to convert Infinity to Decimal.
// Infinity (Double) --> Infinity (Single)
//
// Unable to convert -Infinity to Int64.
// Unable to convert -Infinity to UInt64.
// Unable to convert -Infinity to Decimal.
// -Infinity (Double) --> -Infinity (Single)
// The example displays the following output for conversions performed
// in an unchecked context:
// -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
// Unable to convert -1.79769313486232E+308 to Decimal.
// -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
// -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
// -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
// -67890.1234 (Double) --> -67890.1234 (Decimal)
// -67890.1234 (Double) --> -67890.13 (Single)
//
// -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
// -12345.6789 (Double) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
// -12345.6789 (Double) --> -12345.6789 (Decimal)
// -12345.6789 (Double) --> -12345.68 (Single)
//
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
// 12345.6789 (Double) --> 12345.6789 (Decimal)
// 12345.6789 (Double) --> 12345.68 (Single)
//
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
// 67890.1234 (Double) --> 67890.1234 (Decimal)
// 67890.1234 (Double) --> 67890.13 (Single)
//
// 1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// 1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert 1.79769313486232E+308 to Decimal.
// 1.79769313486232E+308 (Double) --> Infinity (Single)
//
// NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// NaN (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert NaN to Decimal.
// NaN (Double) --> NaN (Single)
//
// Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert Infinity to Decimal.
// Infinity (Double) --> Infinity (Single)
//
// -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
// Unable to convert -Infinity to Decimal.
// -Infinity (Double) --> -Infinity (Single)
Module Example
Public Sub Main()
Dim values() As Double = { Double.MinValue, -67890.1234, -12345.6789,
12345.6789, 67890.1234, Double.MaxValue,
Double.NaN, Double.PositiveInfinity,
Double.NegativeInfinity }
For Each value In values
Try
Dim lValue As Int64 = CLng(value)
Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
value, value.GetType().Name,
lValue, lValue.GetType().Name)
Catch e As OverflowException
Console.WriteLine("Unable to convert {0} to Int64.", value)
End Try
Try
Dim ulValue As UInt64 = CULng(value)
Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
value, value.GetType().Name,
ulValue, ulValue.GetType().Name)
Catch e As OverflowException
Console.WriteLine("Unable to convert {0} to UInt64.", value)
End Try
Try
Dim dValue As Decimal = CDec(value)
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
dValue, dValue.GetType().Name)
Catch e As OverflowException
Console.WriteLine("Unable to convert {0} to Decimal.", value)
End Try
Try
Dim sValue As Single = CSng(value)
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
sValue, sValue.GetType().Name)
Catch e As OverflowException
Console.WriteLine("Unable to convert {0} to Single.", value)
End Try
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output for conversions performed
' in a checked context:
' Unable to convert -1.79769313486232E+308 to Int64.
' Unable to convert -1.79769313486232E+308 to UInt64.
' Unable to convert -1.79769313486232E+308 to Decimal.
' -1.79769313486232E+308 (Double) --> -Infinity (Single)
'
' -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
' Unable to convert -67890.1234 to UInt64.
' -67890.1234 (Double) --> -67890.1234 (Decimal)
' -67890.1234 (Double) --> -67890.13 (Single)
'
' -12345.6789 (Double) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
' Unable to convert -12345.6789 to UInt64.
' -12345.6789 (Double) --> -12345.6789 (Decimal)
' -12345.6789 (Double) --> -12345.68 (Single)
'
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (Int64)
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (UInt64)
' 12345.6789 (Double) --> 12345.6789 (Decimal)
' 12345.6789 (Double) --> 12345.68 (Single)
'
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
' 67890.1234 (Double) --> 67890.1234 (Decimal)
' 67890.1234 (Double) --> 67890.13 (Single)
'
' Unable to convert 1.79769313486232E+308 to Int64.
' Unable to convert 1.79769313486232E+308 to UInt64.
' Unable to convert 1.79769313486232E+308 to Decimal.
' 1.79769313486232E+308 (Double) --> Infinity (Single)
'
' Unable to convert NaN to Int64.
' Unable to convert NaN to UInt64.
' Unable to convert NaN to Decimal.
' NaN (Double) --> NaN (Single)
'
' Unable to convert Infinity to Int64.
' Unable to convert Infinity to UInt64.
' Unable to convert Infinity to Decimal.
' Infinity (Double) --> Infinity (Single)
'
' Unable to convert -Infinity to Int64.
' Unable to convert -Infinity to UInt64.
' Unable to convert -Infinity to Decimal.
' -Infinity (Double) --> -Infinity (Single)
' The example displays the following output for conversions performed
' in an unchecked context:
' -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
' Unable to convert -1.79769313486232E+308 to Decimal.
' -1.79769313486232E+308 (Double) --> -Infinity (Single)
'
' -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
' -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
' -67890.1234 (Double) --> -67890.1234 (Decimal)
' -67890.1234 (Double) --> -67890.13 (Single)
'
' -12345.6789 (Double) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
' -12345.6789 (Double) --> 18446744073709539270 (0xFFFFFFFFFFFFCFC6) (UInt64)
' -12345.6789 (Double) --> -12345.6789 (Decimal)
' -12345.6789 (Double) --> -12345.68 (Single)
'
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (Int64)
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (UInt64)
' 12345.6789 (Double) --> 12345.6789 (Decimal)
' 12345.6789 (Double) --> 12345.68 (Single)
'
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
' 67890.1234 (Double) --> 67890.1234 (Decimal)
' 67890.1234 (Double) --> 67890.13 (Single)
'
' 1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' 1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
' Unable to convert 1.79769313486232E+308 to Decimal.
' 1.79769313486232E+308 (Double) --> Infinity (Single)
'
' NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' NaN (Double) --> 0 (0x0000000000000000) (UInt64)
' Unable to convert NaN to Decimal.
' NaN (Double) --> NaN (Single)
'
' Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
' Unable to convert Infinity to Decimal.
' Infinity (Double) --> Infinity (Single)
'
' -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
' Unable to convert -Infinity to Decimal.
' -Infinity (Double) --> -Infinity (Single)
有关数值类型转换的详细信息,请参阅 .NET Framework 和类型转换表中的类型转换。
Floating-Point 功能
Double结构和相关类型提供了在以下几个方面执行操作的方法:
值比较。 您可以调用 Equals 方法来确定两个 Double 值是否相等,或调用 CompareTo 方法来确定两个值之间的关系。
该 Double 结构还支持一组完整的比较运算符。 例如,你可以测试是否相等或不相等,或确定一个值是否大于或等于另一个值。 如果其中一个操作数是非的数值类型,则在 Double 执行比较之前将其转换为 Double 。
你还可以调用 IsNaN 、 IsInfinity 、 IsPositiveInfinity 和 IsNegativeInfinity 方法来测试这些特殊值。
数学运算。 常见算术运算(例如加法、减法、乘法和除法)由语言编译器和公共中间语言 (CIL) 指令实现,而不是通过方法实现 Double 。 如果数学运算中的一个操作数为数值类型而不是,则在 Double 执行运算前将其转换为 Double 。 操作的结果也是 Double 值。
其他数学运算可以通过调用类中
static
Shared
Visual Basic) 方法 (来执行 System.Math 。 它包括通常用于算术 (的其他方法,例如 Math.Abs 、 Math.Sign 和 Math.Sqrt) 、几何图形 (如 Math.Cos 和 Math.Sin) )以及 (等微积分) Math.Log 。您还可以操作值中的单个位 Double 。 BitConverter.DoubleToInt64Bits方法 Double 在64位整数中保留值的位模式。 BitConverter.GetBytes(Double)方法返回其在字节数组中的位模式。
舍入。 舍入通常用作一种方法,用于降低由于浮点表示形式和精度问题导致的值之间的差异。 可以 Double 通过调用方法来舍入值 Math.Round 。
格式设置。 可以 Double 通过调用 ToString 方法或使用复合格式设置功能,将值转换为其字符串表示形式。 有关格式字符串如何控制浮点值的字符串表示形式的信息,请参阅 标准数字格式字符串 和 自定义数字格式字符串 主题。
分析字符串。 可以 Double 通过调用或方法,将浮点值的字符串表示形式转换为值 Parse TryParse 。 如果分析操作失败,则该 Parse 方法将引发异常,而 TryParse 方法返回
false
。类型转换。 Double结构为接口提供了显式接口实现 IConvertible ,该接口支持任意两个标准 .NET Framework 数据类型之间的转换。 语言编译器还支持将所有其他标准数值类型的值隐式转换为 Double 值。 将任何标准数值类型的值转换为 Double 扩大转换,不需要使用强制转换运算符或转换方法的用户。
但是, Int64 和值的转换 Single 可能会导致精度损失。 下表列出了每种类型的精度差异:
类型 最大精度 内部精度 Double 15 17 Int64 19个十进制数字 19个十进制数字 Single 7个十进制数字 9个十进制数字 精确的问题会影响 Single 转换为值的值 Double 。 在下面的示例中,两个由相同除法运算生成的值是不相等的,因为其中一个值是转换为的单精度浮点值 Double 。
using System; public class Example { public static void Main() { Double value = .1; Double result1 = value * 10; Double result2 = 0; for (int ctr = 1; ctr <= 10; ctr++) result2 += value; Console.WriteLine(".1 * 10: {0:R}", result1); Console.WriteLine(".1 Added 10 times: {0:R}", result2); } } // The example displays the following output: // .1 * 10: 1 // .1 Added 10 times: 0.99999999999999989
Module Example Public Sub Main() Dim value As Double = .1 Dim result1 As Double = value * 10 Dim result2 As Double For ctr As Integer = 1 To 10 result2 += value Next Console.WriteLine(".1 * 10: {0:R}", result1) Console.WriteLine(".1 Added 10 times: {0:R}", result2) End Sub End Module ' The example displays the following output: ' .1 * 10: 1 ' .1 Added 10 times: 0.99999999999999989
字段
Epsilon |
表示大于零的最小正 Double 值。 此字段为常数。 |
MaxValue |
表示 Double 的最大可能值。 此字段为常数。 |
MinValue |
表示 Double 的最小可能值。 此字段为常数。 |
NaN |
表示不是数字 ( |
NegativeInfinity |
表示负无穷。 此字段为常数。 |
PositiveInfinity |
表示正无穷。 此字段为常数。 |
方法
CompareTo(Double) |
将此实例与指定的双精度浮点数进行比较,并返回一个整数,该整数指示此实例的值是小于、等于还是大于指定双精度浮点数的值。 |
CompareTo(Object) |
将此实例与指定对象进行比较,并返回一个整数,该整数指示此实例的值是小于、等于还是大于指定对象的值。 |
Equals(Double) |
返回一个值,该值指示此实例和指定的 Double 对象是否表示相同的值。 |
Equals(Object) |
返回一个值,该值指示此实例是否等于指定的对象。 |
GetHashCode() |
返回此实例的哈希代码。 |
GetTypeCode() | |
IsFinite(Double) |
确定指定值是否为有限值(零、不正常或正常)。 |
IsInfinity(Double) |
返回一个值,该值指示指定数字是计算为负无穷大还是正无穷大。 |
IsNaN(Double) |
返回一个值,该值指示指定的值是否不为数字 (NaN)。 |
IsNegative(Double) |
确定指定值是否为负值。 |
IsNegativeInfinity(Double) |
返回一个值,通过该值指示指定数字是否计算为负无穷大。 |
IsNormal(Double) |
确定指定值是否正常。 |
IsPositiveInfinity(Double) |
返回一个值,通过该值指示指定数字是否计算为正无穷大。 |
IsSubnormal(Double) |
确定指定值是否不正常。 |
Parse(ReadOnlySpan<Char>, NumberStyles, IFormatProvider) |
将字符范围(其中包含指定样式和区域性特定格式的数字的字符串表示形式)转换为它的等效双精度浮点数。 |
Parse(String) |
将数字的字符串表示形式转换为它的等效双精度浮点数。 |
Parse(String, IFormatProvider) |
将指定的区域性特定格式的数字的字符串表示形式转换为它的等效双精度浮点数。 |
Parse(String, NumberStyles) |
将指定样式的数字的字符串表示形式转换为它的等效双精度浮点数。 |
Parse(String, NumberStyles, IFormatProvider) |
将指定样式和区域性特定格式的数字的字符串表示形式转换为它的等效双精度浮点数。 |
ToString() |
将此实例的数值转换为其等效的字符串表示形式。 |
ToString(IFormatProvider) |
使用指定的区域性特定格式信息,将此实例的数值转换为它的等效字符串表示形式。 |
ToString(String) |
使用指定的格式,将此实例的数值转换为它的等效字符串表示形式。 |
ToString(String, IFormatProvider) |
使用指定的格式和区域性特定格式信息,将此实例的数值转换为它的等效字符串表示形式。 |
TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider) |
尝试将当前双精度实例的值的格式设置为提供的字符范围。 |
TryParse(ReadOnlySpan<Char>, Double) |
将指定样式和区域性特定格式的数字的范围表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。 |
TryParse(ReadOnlySpan<Char>, NumberStyles, IFormatProvider, Double) |
将字符范围(其中包含指定样式和区域性特定格式的数字的字符串表示形式)转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。 |
TryParse(String, Double) |
将数字的字符串表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。 |
TryParse(String, NumberStyles, IFormatProvider, Double) |
将指定样式和区域性特定格式的数字的字符串表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。 |
运算符
Equality(Double, Double) |
返回一个值,该值指示两个指定的 Double 值是否相等。 |
GreaterThan(Double, Double) | |
GreaterThanOrEqual(Double, Double) | |
Inequality(Double, Double) |
返回一个值,该值指示两个指定的 Double 值是否不相等。 |
LessThan(Double, Double) | |
LessThanOrEqual(Double, Double) |
显式接口实现
适用于
线程安全性
此类型的所有成员都是线程安全的。 看似修改实例状态的成员实际上返回用新值初始化的新实例。 与任何其他类型一样,读取和写入包含此类型的实例的共享变量时,必须通过锁保护以保证线程安全。