Double 结构

定义

表示一个双精度浮点数。

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<double>, IConvertible, IEquatable<double>, IParsable<double>, ISpanParsable<double>, System::Numerics::IAdditionOperators<double, double, double>, System::Numerics::IAdditiveIdentity<double, double>, System::Numerics::IBinaryFloatingPointIeee754<double>, System::Numerics::IBinaryNumber<double>, System::Numerics::IBitwiseOperators<double, double, double>, System::Numerics::IComparisonOperators<double, double>, System::Numerics::IDecrementOperators<double>, System::Numerics::IDivisionOperators<double, double, double>, System::Numerics::IEqualityOperators<double, double>, System::Numerics::IExponentialFunctions<double>, System::Numerics::IFloatingPoint<double>, System::Numerics::IFloatingPointIeee754<double>, System::Numerics::IHyperbolicFunctions<double>, System::Numerics::IIncrementOperators<double>, System::Numerics::ILogarithmicFunctions<double>, System::Numerics::IMinMaxValue<double>, System::Numerics::IModulusOperators<double, double, double>, System::Numerics::IMultiplicativeIdentity<double, double>, System::Numerics::IMultiplyOperators<double, double, double>, System::Numerics::INumber<double>, System::Numerics::INumberBase<double>, System::Numerics::IPowerFunctions<double>, System::Numerics::IRootFunctions<double>, System::Numerics::ISignedNumber<double>, System::Numerics::ISubtractionOperators<double, double, double>, System::Numerics::ITrigonometricFunctions<double>, System::Numerics::IUnaryNegationOperators<double, double>, System::Numerics::IUnaryPlusOperators<double, double>
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 readonly struct Double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, IFormattable
public readonly struct Double : IComparable, IComparable<double>, IConvertible, IEquatable<double>, ISpanFormattable
public readonly struct Double : IComparable<double>, IConvertible, IEquatable<double>, IParsable<double>, ISpanParsable<double>, System.Numerics.IAdditionOperators<double,double,double>, System.Numerics.IAdditiveIdentity<double,double>, System.Numerics.IBinaryFloatingPointIeee754<double>, System.Numerics.IBinaryNumber<double>, System.Numerics.IBitwiseOperators<double,double,double>, System.Numerics.IComparisonOperators<double,double>, System.Numerics.IDecrementOperators<double>, System.Numerics.IDivisionOperators<double,double,double>, System.Numerics.IEqualityOperators<double,double>, System.Numerics.IExponentialFunctions<double>, System.Numerics.IFloatingPoint<double>, System.Numerics.IFloatingPointIeee754<double>, System.Numerics.IHyperbolicFunctions<double>, System.Numerics.IIncrementOperators<double>, System.Numerics.ILogarithmicFunctions<double>, System.Numerics.IMinMaxValue<double>, System.Numerics.IModulusOperators<double,double,double>, System.Numerics.IMultiplicativeIdentity<double,double>, System.Numerics.IMultiplyOperators<double,double,double>, System.Numerics.INumber<double>, System.Numerics.INumberBase<double>, System.Numerics.IPowerFunctions<double>, System.Numerics.IRootFunctions<double>, System.Numerics.ISignedNumber<double>, System.Numerics.ISubtractionOperators<double,double,double>, System.Numerics.ITrigonometricFunctions<double>, System.Numerics.IUnaryNegationOperators<double,double>, System.Numerics.IUnaryPlusOperators<double,double>
[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
type double = struct
    interface IConvertible
    interface IFormattable
    interface IParsable<double>
    interface ISpanFormattable
    interface ISpanParsable<double>
    interface IAdditionOperators<double, double, double>
    interface IAdditiveIdentity<double, double>
    interface IBinaryFloatingPointIeee754<double>
    interface IBinaryNumber<double>
    interface IBitwiseOperators<double, double, double>
    interface IComparisonOperators<double, double>
    interface IEqualityOperators<double, double>
    interface IDecrementOperators<double>
    interface IDivisionOperators<double, double, double>
    interface IIncrementOperators<double>
    interface IModulusOperators<double, double, double>
    interface IMultiplicativeIdentity<double, double>
    interface IMultiplyOperators<double, double, double>
    interface INumber<double>
    interface INumberBase<double>
    interface ISubtractionOperators<double, double, double>
    interface IUnaryNegationOperators<double, double>
    interface IUnaryPlusOperators<double, double>
    interface IExponentialFunctions<double>
    interface IFloatingPoint<double>
    interface ISignedNumber<double>
    interface IFloatingPointIeee754<double>
    interface IHyperbolicFunctions<double>
    interface ILogarithmicFunctions<double>
    interface IPowerFunctions<double>
    interface IRootFunctions<double>
    interface ITrigonometricFunctions<double>
    interface IMinMaxValue<double>
[<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 IAdditionOperators(Of Double, Double, Double), IAdditiveIdentity(Of Double, Double), IBinaryFloatingPointIeee754(Of Double), IBinaryNumber(Of Double), IBitwiseOperators(Of Double, Double, Double), IComparable(Of Double), IComparisonOperators(Of Double, Double), IConvertible, IDecrementOperators(Of Double), IDivisionOperators(Of Double, Double, Double), IEqualityOperators(Of Double, Double), IEquatable(Of Double), IExponentialFunctions(Of Double), IFloatingPoint(Of Double), IFloatingPointIeee754(Of Double), IHyperbolicFunctions(Of Double), IIncrementOperators(Of Double), ILogarithmicFunctions(Of Double), IMinMaxValue(Of Double), IModulusOperators(Of Double, Double, Double), IMultiplicativeIdentity(Of Double, Double), IMultiplyOperators(Of Double, Double, Double), INumber(Of Double), INumberBase(Of Double), IParsable(Of Double), IPowerFunctions(Of Double), IRootFunctions(Of Double), ISignedNumber(Of Double), ISpanParsable(Of Double), ISubtractionOperators(Of Double, Double, Double), ITrigonometricFunctions(Of Double), IUnaryNegationOperators(Of Double, Double), IUnaryPlusOperators(Of Double, Double)
Public Structure Double
Implements IComparable, IConvertible, IFormattable
Public Structure Double
Implements IComparable, IComparable(Of Double), IEquatable(Of Double), IFormattable
继承
Double
属性
实现
IComparable IComparable<Double> IConvertible IEquatable<Double> IFormattable ISpanFormattable IComparable<TOther> IComparable<TSelf> IEquatable<TOther> IEquatable<TSelf> IParsable<Double> IParsable<TSelf> ISpanParsable<Double> ISpanParsable<TSelf> IAdditionOperators<Double,Double,Double> IAdditionOperators<TSelf,TSelf,TSelf> IAdditiveIdentity<Double,Double> IAdditiveIdentity<TSelf,TSelf> IBinaryFloatingPointIeee754<Double> IBinaryNumber<Double> IBinaryNumber<TSelf> IBitwiseOperators<Double,Double,Double> IBitwiseOperators<TSelf,TSelf,TSelf> IComparisonOperators<Double,Double> IComparisonOperators<TSelf,TSelf> IDecrementOperators<Double> IDecrementOperators<TSelf> IDivisionOperators<Double,Double,Double> IDivisionOperators<TSelf,TSelf,TSelf> IEqualityOperators<Double,Double> IEqualityOperators<TSelf,TOther> IEqualityOperators<TSelf,TSelf> IExponentialFunctions<Double> IExponentialFunctions<TSelf> IFloatingPoint<Double> IFloatingPoint<TSelf> IFloatingPointIeee754<Double> IFloatingPointIeee754<TSelf> IHyperbolicFunctions<Double> IHyperbolicFunctions<TSelf> IIncrementOperators<Double> IIncrementOperators<TSelf> ILogarithmicFunctions<Double> ILogarithmicFunctions<TSelf> IMinMaxValue<Double> IModulusOperators<Double,Double,Double> IModulusOperators<TSelf,TSelf,TSelf> IMultiplicativeIdentity<Double,Double> IMultiplicativeIdentity<TSelf,TSelf> IMultiplyOperators<Double,Double,Double> IMultiplyOperators<TSelf,TSelf,TSelf> INumber<Double> INumber<TSelf> INumberBase<Double> INumberBase<TSelf> IPowerFunctions<Double> IPowerFunctions<TSelf> IRootFunctions<Double> IRootFunctions<TSelf> ISignedNumber<Double> ISignedNumber<TSelf> ISubtractionOperators<Double,Double,Double> ISubtractionOperators<TSelf,TSelf,TSelf> ITrigonometricFunctions<Double> ITrigonometricFunctions<TSelf> IUnaryNegationOperators<Double,Double> IUnaryNegationOperators<TSelf,TSelf> IUnaryPlusOperators<Double,Double> IUnaryPlusOperators<TSelf,TSelf>

示例

下面的代码示例说明了如何使用 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;
        }
    }
}
// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
type Temperature() =
    member val Value = 0. with get, set

    member this.Celsius
        with get () = (this.Value - 32.) / 1.8
        and set (value) =
            this.Value <- 1.8 * value + 32.

    // Parses the temperature from a string in the form
    // [ws][sign]digits['F|'C][ws]
    static member Parse(s: string, styles: NumberStyles, provider: IFormatProvider) =
        let temp = Temperature()

        if s.TrimEnd(null).EndsWith "'F" then
            temp.Value <- Double.Parse(s.Remove(s.LastIndexOf '\'', 2), styles, provider)
        elif s.TrimEnd(null).EndsWith "'C" then
            temp.Celsius <- Double.Parse(s.Remove(s.LastIndexOf '\'', 2), styles, provider)
        else
            temp.Value <- Double.Parse(s, styles, provider)
        temp

    interface IComparable with
        // IComparable.CompareTo implementation.
        member this.CompareTo(obj: obj) =
            match obj with 
            | null -> 1
            | :? Temperature as temp ->
                this.Value.CompareTo temp.Value
            | _ ->
                invalidArg "obj" "object is not a Temperature"

    interface IFormattable with
        // IFormattable.ToString implementation.
        member this.ToString(format: string, provider: IFormatProvider) =
            match format with
            | "F" ->
                $"{this.Value}'F"
            | "C" ->
                $"{this.Celsius}'C"
            | _ ->
                this.Value.ToString(format, provider)
' 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

注解

Double类型表示双精度 64 位数字,其值范围为负 1.79769313486232e308 到正 1.79769313486232e308,以及正零或负零,PositiveInfinityNegativeInfinity而不是数字 (NaN) 。 它旨在表示极大 (的值,如行星或星系之间的距离) 或极小的 (,如公斤) 物质的分子质量,通常不精确 (,例如从地球到另一个太阳系) 的距离。 该 Double 类型符合二进制浮点算术标准 IEC 60559:1989 (IEEE 754) 标准。

本主题包括以下各节:

Floating-Point表示和精度

Double数据类型以 64 位二进制格式存储双精度浮点值,如下表所示:

组成部分 Bits
Significand or mantissa 0-51
Exponent 52-62
符号 (0 = 正数,1 = 负) 63

正如小数分数无法精确表示某些小数值 ((如 1/3 或 Math.PI) ),二进制分数无法表示某些小数值。 例如,1/10(以小数分数精确表示)由 .001100110011 表示为二进制分数,模式“0011”重复为无穷大。 在这种情况下,浮点值提供它所表示的数字的不精确表示形式。 对原始浮点值执行其他数学运算往往会增加其缺乏精度。 例如,如果我们比较了将 .1 乘以 10 的结果,并将 .1 乘以 .19 倍,则我们看到该加法涉及 8 个运算,因此产生了更精确的结果。 请注意,仅当使用“R”标准数值格式字符串显示这两Double个值时,这种差异才明显,如有必要,该字符串将显示类型支持Double的所有 17 位精度。

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
let value = 0.1
let result1 = value * 10.
let mutable result2 = 0.
for i = 1 to 10 do
    result2 <- result2 + value

printfn $".1 * 10:           {result1:R}"
printfn $".1 Added 10 times: {result2:R}"
// 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

由于某些数字不能完全表示为小数二进制值,浮点数只能近似实数。

所有浮点数也有有限数量的有效位数,这也决定了浮点值如何准确近似于实数。 一个 Double 值最多具有 15 个小数位数的精度,但内部最多保留 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
open System

let value = 123456789012.34567
let additional = Double.Epsilon * 1e15
printfn $"{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).
    
    let values = [ 10.0; 2.88; 2.88; 2.88; 9.0 ]
    let result = 27.64
    let total = List.sum values
    
    if total.Equals result then
        printfn "The sum of the values equals the total."
    else
        printfn $"The sum of the values ({total}) does not equal the 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).
    

    如果更改语句{0:R} {1:R} {0} {1}中的Console.WriteLine(String, Object, Object)格式项并显示这两Double个值的所有有效数字,则很明显,由于加法运算期间精度损失,这两个值是不相等的。 在这种情况下,可以通过调用 Math.Round(Double, Int32) 方法将值舍入 Double 到所需的精度,然后再执行比较来解决该问题。

  • 如果使用小数,则使用浮点数的数学或比较运算可能不会生成相同的结果,因为二进制浮点数可能不等于小数。 前面的示例演示了这一点,显示将 .1 乘以 10 并添加 .1 次的结果。

    当具有小数值的数值运算的准确性很重要时,可以使用 Decimal 而不是 Double 类型。 当数值运算的整数值超出 Int64UInt64 类型的精度很重要时,请使用该 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
    
    open System
    open System.IO
    
    let values = [ 2.2 / 1.01; 1. / 3.; Math.PI ]
    
    using (new StreamWriter(@".\Doubles.dat")) (fun sw ->
        for i = 0 to values.Length - 1 do
            sw.Write(string values[i])
            if i <> values.Length - 1 then
                sw.Write "|")
    
    using (new StreamReader(@".\Doubles.dat")) (fun sr ->
        let temp = sr.ReadToEnd()
        let tempStrings = temp.Split '|'
    
        let restoredValues =
            [ for i = 0 to tempStrings.Length - 1 do
                  Double.Parse tempStrings[i] ]
    
        for i = 0 to values.Length - 1 do
            printfn $"""{values[i]} {if values[ i ].Equals restoredValues[i] then "=" else "<>"} {restoredValues[i]}""")
    
    // 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
    
    open System
    open System.IO
    
    let values = [ 2.2 / 1.01; 1. / 3.; Math.PI ]
    
    using (new StreamWriter(@".\Doubles.dat")) (fun sw -> 
        for i = 0 to values.Length - 1 do
            sw.Write $"""{values[i]:G17}{if i < values.Length - 1 then "|" else ""}""")
    
    using (new StreamReader(@".\Doubles.dat")) (fun sr ->
        let temp = sr.ReadToEnd()
        let tempStrings = temp.Split '|'
        
        let restoredValues = 
          [ for i = 0 to tempStrings.Length - 1 do
                Double.Parse tempStrings[i] ]
    
        for i = 0 to values.Length - 1 do
            printfn $"""{restoredValues[i]} {if values[i].Equals restoredValues[i] then "=" else "<>"} {values[i]}""")
    
    // 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
    

重要

与值一起使用 Double 时,在某些情况下,“R”格式说明符无法成功往返原始值。 若要确保 Double 值成功往返,请使用“G17”格式说明符。

  • Single 值精度小于 Double 值。 Single转换为看似等效Double的值通常不等于Double值,因为精度差异。 在以下示例中,将相同的除法运算结果分配给一 Double 个值和一个 Single 值。 将 Single 值强制转换为 a 之后,两个 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
    
    open System
    
    let value1 = 1. / 3.
    let sValue2 = 1f /3f
    
    let value2 = double sValue2
    printfn $"{value1:R} = {value2:R}: {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值的算术和赋值运算的结果可能会略有不同。 例如,分配文本Double值的结果可能与.NET Framework的 32 位和 64 位版本不同。 以下示例演示了当文本值 -4.4230604244772E-305 和值为 -4.4233060424772E-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
let value = -4.42330604244772E-305

let fromLiteral = -4.42330604244772E-305
let fromVariable = value
let fromParse = Double.Parse "-4.42330604244772E-305"

printfn $"Double value from literal: {fromLiteral,29:R}"
printfn $"Double value from variable: {fromVariable,28:R}"
printfn $"Double value from Parse method: {fromParse,24:R}"
// 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 个值之间的关系,通常会产生意外的结果。 以下示例中很明显,其中两个明显相等 Double 的值结果不相等,因为第一个值具有 15 位精度,而第二个值有 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
open System

let value1 = 0.333333333333333
let value2 = 1. / 3.
printfn $"{value1:R} = {value2:R}: {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。

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
open System

let value1 = 
    Math.Pow(100.10142, 2)
    |> sqrt

let value2 = 
    let v = pown (value1 * 3.51) 2
    (Math.Sqrt v) / 3.51

printfn $"{value1} = {value2}: {value1.Equals value2}\n"
printfn $"{value1:R} = {value2:R}"
// 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

如果精度损失可能会影响比较结果,则可以采用以下任一替代方法来调用 EqualsCompareTo 方法:

  • 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
    
    open System
    
    let v1 = 0.333333333333333
    let v2 = 1. / 3.
    let precision = 7
    let value1 = Math.Round(v1, precision)
    let value2 = Math.Round(v2, precision)
    printfn $"{value1:R} = {value2:R}: {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
    
    open System
    
    let isApproximatelyEqual (value1: double) (value2: double) (epsilon: double) =
        // If they are equal anyway, just return True.
        if value1.Equals value2 then 
            true
        else
            // Handle NaN, Infinity.
            if Double.IsInfinity value1 || Double.IsNaN value1 then 
                value1.Equals value2
            elif Double.IsInfinity value2 || Double.IsNaN value2 then
                value1.Equals value2
            else
                // Handle zero to avoid division by zero
                let divisor = max value1 value2
                let divisor = 
                    if divisor.Equals 0 then
                        min value1 value2
                    else 
                        divisor
                abs ((value1 - value2) / divisor) <= epsilon
    
    let one1 = 0.1 * 10.
    let mutable one2 = 0.
    for _ = 1 to 10 do
        one2 <- one2 + 0.1
    
    printfn $"{one1:R} = {one2:R}: {one1.Equals one2}"
    printfn $"{one1:R} is approximately equal to {one2:R}: {isApproximatelyEqual one1 one2 0.000000001}"
    
    // 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
    
    let value1 = 1.1632875981534209e-225
    let value2 = 9.1642346778e-175
    let result = value1 * value2
    printfn $"{value1} * {value2} = {result}"
    printfn $"{result} = 0: {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
    
  • 如果浮点操作的结果量超过目标格式的范围,则操作的结果是 PositiveInfinityNegativeInfinity,适合结果的符号。 溢出Double.MaxValuePositiveInfinity的操作的结果,以及溢出Double.MinValueNegativeInfinity的操作的结果,如以下示例所示。

    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
    
    open System
    
    let value1 = 4.565e153
    let value2 = 6.9375e172
    let result = value1 * value2
    printfn $"PositiveInfinity: {Double.IsPositiveInfinity result}"
    printfn $"NegativeInfinity: {Double.IsNegativeInfinity result}\n"
    
    let value3 = - value1
    let result2 = value2 * value3
    printfn $"PositiveInfinity: {Double.IsPositiveInfinity result2}"
    printfn $"NegativeInfinity: {Double.IsNegativeInfinity result2}"
    
    // 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 以下操作的结果:

  • 任何具有无效输入的浮点操作。 例如,使用负值调用 Math.Sqrt 方法将 NaN返回,调用 Math.Acos 方法的值大于一个或小于负值。

  • 具有其值为 Double.NaN的参数的任何操作。

类型转换和双精度结构

结构 Double 不定义任何显式或隐式转换运算符;而是由编译器实现转换。

任何基元数值类型的 Double 值转换都是一个扩大的转换,因此不需要显式强制转换运算符或调用转换方法,除非编译器显式要求它。 例如,C# 编译器要求转换运算符进行转换 DecimalDouble而 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)
open System

let values: obj[] = 
    [| 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 |]

for value in values do
    let dblValue = value :?> double
    printfn $"{value} ({value.GetType().Name}) --> {dblValue:R} ({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)

此外,这些SingleSingle.NaNSingle.PositiveInfinity、值以及Single.NegativeInfinity分别转换为 Double.NaNDouble.PositiveInfinityDouble.NegativeInfinity/

请注意,将某些数值类型的值转换为 Double 值可能涉及精度损失。 如示例所示,在将精度和值转换为DecimalInt64UInt64Double值时,可能会丢失精度。

将值转换为 Double 任何其他基元数值数据类型的值是一种缩小的转换,需要在 C#) 中 (强制转换运算符、Visual Basic) 中的转换方法 (或对方法的 Convert 调用。 超出目标数据类型范围的值(由目标类型的 MinValueMaxValue 属性定义)的行为如下表所示。

目标类型 结果
任何整型类型 OverflowException如果转换发生在已检查的上下文中,则为异常。

如果在未选中的上下文中发生转换, (C#) 中的默认值,则转换操作会成功,但值溢出。
Decimal 一个 OverflowException 异常。
Single Single.NegativeInfinity 表示负值。

Single.PositiveInfinity 表示正值。

此外,Double.NaNDouble.PositiveInfinity如果Double.NegativeInfinityOverflowException转换为未选中的上下文中的整数,则这些值会溢出。 对于转换到 Decimal,它们始终引发一个 OverflowException。 对于转换到 Single,它们分别转换为 Single.NaNSingle.PositiveInfinity转换 Single.NegativeInfinity

请注意,精度损失可能导致将值转换为 Double 其他数值类型。 如果转换为任何整型类型,如示例中所示,当值舍入 ((如 Visual Basic) 中)或截断 ((如 C#) 中所示)时 Double ,小数分量将丢失。 对于转换到 Decimal 值和 Single 值, Double 该值在目标数据类型中可能没有精确的表示形式。

以下示例将多个 Double 值转换为其他几个数值类型。 转换发生在 Visual Basic 中检查的上下文中, (默认) ,在 C# (中,因为 选中 关键字) ,在 F# (中,因为 已选中 模块) 。 该示例的输出显示两个未选中上下文中转换的结果。 可以通过使用/removeintchecks+编译器开关、C# 注释掉语句和在 F# open Checked 中注释掉checked语句,在 Visual Basic 中的未选中上下文中执行转换。

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)
open System
open Checked

let values = 
    [| Double.MinValue; -67890.1234; -12345.6789
       12345.6789; 67890.1234; Double.MaxValue
       Double.NaN; Double.PositiveInfinity;
       Double.NegativeInfinity |]

for value in values do
    try
        let lValue = int64 value
        printfn $"{value} ({value.GetType().Name}) --> {lValue} (0x{lValue:X16}) ({lValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Int64."
    try
        let ulValue = uint64 value
        printfn $"{value} ({value.GetType().Name}) --> {ulValue} (0x{ulValue:X16}) ({ulValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to UInt64."
    try
        let dValue = decimal value
        printfn $"{value} ({value.GetType().Name}) --> {dValue} ({dValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Decimal."
    try
        let sValue = float32 value
        printfn $"{value} ({value.GetType().Name}) --> {sValue} ({sValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Single."
    printfn ""
// 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,则会在执行比较之前将其转换为 a Double

    警告

    由于精度差异,预期相等的两 Double 个值可能不相等,这会影响比较的结果。 有关比较两Double个值的详细信息,请参阅“测试相等”部分。

    还可以调用和IsNaNIsInfinityIsPositiveInfinityIsNegativeInfinity方法来测试这些特殊值。

  • 数学运算。 常见的算术运算(例如加法、减法、乘法和除法)由语言编译器和公共中间语言 (CIL) 指令实现,而不是由 Double 方法实现。 如果数学运算中的某个操作数不是数值类型 Double,则会在执行该操作之前将其转换为 a Double 。 操作的结果也是一个 Double 值。

    可以通过调用类中的 Visual Basic) 方法System.Math中的 (Shared来执行static其他数学运算。 它包括常用于算术 (的其他方法,例如,和) 、几何 ((如Math.Cos Math.Sin 和) )以及) 等Math.Log微积分 (。Math.Sqrt Math.SignMath.Abs

    还可以操作值中的 Double 单个位。 该方法 BitConverter.DoubleToInt64BitsDouble 64 位整数中保留值的位模式。 该方法 BitConverter.GetBytes(Double) 在字节数组中返回其位模式。

  • 舍入。 舍入通常用作一种技术,用于减少浮点表示和精度问题导致的值之间的差异的影响。 可以通过调用Math.Round方法来舍入Double值。

  • 格式设置。 可以通过调用ToString方法或使用复合格式设置功能将值转换为Double其字符串表示形式。 有关格式字符串如何控制浮点值的字符串表示形式的信息,请参阅 标准数字格式字符串自定义数字格式字符串 主题。

  • 分析字符串。 可以通过调用ParseTryParse方法将浮点值的Double字符串表示形式转换为值。 如果分析操作失败,该方法 Parse 将引发异常,而 TryParse 该方法返回 false

  • 类型转换。 该Double结构为IConvertible接口提供显式接口实现,该接口支持在任意两种标准.NET Framework数据类型之间进行转换。 语言编译器还支持将所有其他标准数值类型的 Double 值隐式转换为值。 将任何标准数值类型的值转换为 a Double 是扩大转换,不需要强制转换运算符或转换方法的用户,

    但是,转换 Int64Single 值可能涉及精度损失。 下表列出了每种类型的精度差异:

    类型 最大精度 内部精度
    Double 15 17
    Int64 19 位十进制数字 19 位十进制数字
    Single 7 位十进制数字 9 位十进制数字

    精度问题最常影响 Single 转换为 Double 值的值。 在以下示例中,由相同除法运算生成的两个值不相等,因为其中一个值是转换为 a 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
    
    let value = 0.1
    let result1 = value * 10.
    let mutable result2 = 0.
    for i = 1 to 10 do
        result2 <- result2 + value
    
    printfn $".1 * 10:           {result1:R}"
    printfn $".1 Added 10 times: {result2:R}"
    // 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
    

字段

E

表示由常量指定的自然对数基数,e.

Epsilon

表示大于零的最小正 Double 值。 此字段为常数。

MaxValue

表示 Double 的最大可能值。 此字段为常数。

MinValue

表示 Double 的最小可能值。 此字段为常数。

NaN

表示不是数字 (NaN) 的值。 此字段为常数。

NegativeInfinity

表示负无穷。 此字段为常数。

NegativeZero

表示负零 (-0) 。

Pi

表示圆的周长与其直径的比值,由常数 π 指定。

PositiveInfinity

表示正无穷。 此字段为常数。

Tau

表示一转中的弧度数,由常量 τ 指定。

方法

Abs(Double)

计算值的绝对值。

Acos(Double)

计算值的反余弦值。

Acosh(Double)

计算值的双曲反余弦值。

Asin(Double)

计算值的反正弦值。

Asinh(Double)

计算值的双曲反正弦值。

Atan(Double)

计算值的反正切值。

Atan2(Double, Double)

计算两个值的商的反正切值。

Atanh(Double)

计算值的双曲反正切值。

BitDecrement(Double)

将值递减为小于给定值的最小值。

BitIncrement(Double)

将值递增为与给定值进行比较的最小值。

Cbrt(Double)

计算值的多维数据集根。

Ceiling(Double)

计算值的上限。

Clamp(Double, Double, Double)

将值固定到非独占最小值和最大值。

CompareTo(Double)

将此实例与指定的双精度浮点数进行比较,并返回一个整数,该整数指示此实例的值是小于、等于还是大于指定双精度浮点数的值。

CompareTo(Object)

将此实例与指定对象进行比较,并返回一个整数,该整数指示此实例的值是小于、等于还是大于指定对象的值。

CopySign(Double, Double)

将值的符号复制到另一个值的符号。

Cos(Double)

计算值的余弦值。

Cosh(Double)

计算值的双曲余弦值。

Equals(Double)

返回一个值,该值指示此实例和指定的 Double 对象是否表示相同的值。

Equals(Object)

返回一个值,该值指示此实例是否等于指定的对象。

Exp(Double)

计算 E 提升 到给定电源。

Exp10(Double)
Exp10M1(Double)
Exp2(Double)
Exp2M1(Double)
ExpM1(Double)
Floor(Double)

计算值的下限。

FusedMultiplyAdd(Double, Double, Double)

计算三个值的融合乘法。

GetHashCode()

返回此实例的哈希代码。

GetTypeCode()

返回值类型 TypeCodeDouble

Ieee754Remainder(Double, Double)

计算 IEEE 754 指定的两个值的其余部分。

ILogB(Double)

计算值的整数对数。

IsEvenInteger(Double)
IsFinite(Double)

确定指定值是否为有限值(零、不正常或正常)。

IsInfinity(Double)

返回一个值,该值指示指定数字是计算为负无穷大还是正无穷大。

IsInteger(Double)
IsNaN(Double)

返回一个值,该值指示指定的值是否不为数字 (NaN)。

IsNegative(Double)

确定指定值是否为负值。

IsNegativeInfinity(Double)

返回一个值,通过该值指示指定数字是否计算为负无穷大。

IsNormal(Double)

确定指定值是否正常。

IsOddInteger(Double)
IsPositive(Double)
IsPositiveInfinity(Double)

返回一个值,通过该值指示指定数字是否计算为正无穷大。

IsPow2(Double)

确定值是否为 2 的幂。

IsRealNumber(Double)
IsSubnormal(Double)

确定指定值是否不正常。

Log(Double)

计算值的自然 (base-E 对数。

Log(Double, Double)

计算指定基中的值的对数。

Log10(Double)

计算值的 base-10 对数。

Log10P1(Double)
Log2(Double)

计算值的 log2。

Log2P1(Double)
LogP1(Double)
Max(Double, Double)

将两个值与计算进行比较,该值更大。

MaxMagnitude(Double, Double)

将两个值与计算进行比较,该值更大。

MaxMagnitudeNumber(Double, Double)
MaxNumber(Double, Double)
Min(Double, Double)

比较两个值,计算值越少。

MinMagnitude(Double, Double)

比较两个值,计算值越少。

MinMagnitudeNumber(Double, Double)
MinNumber(Double, Double)
Parse(ReadOnlySpan<Char>, IFormatProvider)

将字符范围分析为值。

Parse(ReadOnlySpan<Char>, NumberStyles, IFormatProvider)

将字符范围(其中包含指定样式和区域性特定格式的数字的字符串表示形式)转换为它的等效双精度浮点数。

Parse(String)

将数字的字符串表示形式转换为它的等效双精度浮点数。

Parse(String, IFormatProvider)

将指定的区域性特定格式的数字的字符串表示形式转换为它的等效双精度浮点数。

Parse(String, NumberStyles)

将指定样式的数字的字符串表示形式转换为它的等效双精度浮点数。

Parse(String, NumberStyles, IFormatProvider)

将指定样式和区域性特定格式的数字的字符串表示形式转换为它的等效双精度浮点数。

Pow(Double, Double)

计算提升到给定功率的值。

ReciprocalEstimate(Double)

计算值的倒数的估计值。

ReciprocalSqrtEstimate(Double)

计算值的倒数平方根的估计值。

Round(Double)

使用默认舍入模式将值舍入到最接近的整数 (ToEven) 。

Round(Double, Int32)

使用默认舍入模式将值舍入为指定数量的小数位数, (ToEven) 。

Round(Double, Int32, MidpointRounding)

使用默认舍入模式将值舍入为指定数量的小数位数, (ToEven) 。

Round(Double, MidpointRounding)

使用指定的舍入模式将值舍入到最接近的整数。

ScaleB(Double, Int32)

计算一个值及其基弧度升至指定功率的乘积。

Sign(Double)

计算值的符号。

Sin(Double)

计算值的正弦值。

SinCos(Double)

计算值的正弦和余弦值。

Sinh(Double)

计算值的双曲正弦值。

Sqrt(Double)

计算值的平方根。

Tan(Double)

计算值的正切值。

Tanh(Double)

计算值的双曲正切值。

ToString()

将此实例的数值转换为其等效的字符串表示形式。

ToString(IFormatProvider)

使用指定的区域性特定格式信息,将此实例的数值转换为它的等效字符串表示形式。

ToString(String)

使用指定的格式,将此实例的数值转换为它的等效字符串表示形式。

ToString(String, IFormatProvider)

使用指定的格式和区域性特定格式信息,将此实例的数值转换为它的等效字符串表示形式。

Truncate(Double)

截断值。

TryFormat(Span<Char>, Int32, ReadOnlySpan<Char>, IFormatProvider)

尝试将当前双精度实例的值的格式设置为提供的字符范围。

TryParse(ReadOnlySpan<Char>, Double)

将指定样式和区域性特定格式的数字的范围表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。

TryParse(ReadOnlySpan<Char>, IFormatProvider, Double)

尝试将字符范围分析为值。

TryParse(ReadOnlySpan<Char>, NumberStyles, IFormatProvider, Double)

将字符范围(其中包含指定样式和区域性特定格式的数字的字符串表示形式)转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。

TryParse(String, Double)

将数字的字符串表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。

TryParse(String, IFormatProvider, Double)
TryParse(String, NumberStyles, IFormatProvider, Double)

将指定样式和区域性特定格式的数字的字符串表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。

运算符

Equality(Double, Double)

返回一个值,该值指示两个指定的 Double 值是否相等。

GreaterThan(Double, Double)

返回一个值,该值指示指定的 Double 值是否大于另一个指定的 Double 值。

GreaterThanOrEqual(Double, Double)

返回一个值,该值指示指定的 Double 值是否大于或等于另一个指定的 Double 值。

Inequality(Double, Double)

返回一个值,该值指示两个指定的 Double 值是否不相等。

LessThan(Double, Double)

返回一个值,该值指示指定的 Double 值是否小于另一个指定的 Double 值。

LessThanOrEqual(Double, Double)

返回一个值,该值指示指定的 Double 值是否小于或等于另一个指定的 Double 值。

显式接口实现

IComparable.CompareTo(Object)

将当前实例与同一类型的另一个对象进行比较,并返回一个整数,该整数指示当前实例在排序顺序中的位置是位于另一个对象之前、之后还是与其位置相同。

IConvertible.GetTypeCode()

返回此实例的 TypeCode

IConvertible.ToBoolean(IFormatProvider)

有关此成员的说明,请参见 ToBoolean(IFormatProvider)

IConvertible.ToByte(IFormatProvider)

有关此成员的说明,请参见 ToByte(IFormatProvider)

IConvertible.ToChar(IFormatProvider)

不支持此转换。 尝试使用此方法将引发 InvalidCastException

IConvertible.ToDateTime(IFormatProvider)

不支持此转换。 尝试使用此方法将引发 InvalidCastException

IConvertible.ToDecimal(IFormatProvider)

有关此成员的说明,请参见 ToDecimal(IFormatProvider)

IConvertible.ToDouble(IFormatProvider)

有关此成员的说明,请参见 ToDouble(IFormatProvider)

IConvertible.ToInt16(IFormatProvider)

有关此成员的说明,请参见 ToInt16(IFormatProvider)

IConvertible.ToInt32(IFormatProvider)

有关此成员的说明,请参见 ToInt32(IFormatProvider)

IConvertible.ToInt64(IFormatProvider)

有关此成员的说明,请参见 ToInt64(IFormatProvider)

IConvertible.ToSByte(IFormatProvider)

有关此成员的说明,请参见 ToSByte(IFormatProvider)

IConvertible.ToSingle(IFormatProvider)

有关此成员的说明,请参见 ToSingle(IFormatProvider)

IConvertible.ToType(Type, IFormatProvider)

有关此成员的说明,请参见 ToType(Type, IFormatProvider)

IConvertible.ToUInt16(IFormatProvider)

有关此成员的说明,请参见 ToUInt16(IFormatProvider)

IConvertible.ToUInt32(IFormatProvider)

有关此成员的说明,请参见 ToUInt32(IFormatProvider)

IConvertible.ToUInt64(IFormatProvider)

有关此成员的说明,请参见 ToUInt64(IFormatProvider)

IFloatingPoint<Double>.GetExponentByteCount()

获取将作为其一部分 TryWriteExponentLittleEndian(Span<Byte>, Int32)写入的字节数。

IFloatingPoint<Double>.GetExponentShortestBitLength()

获取当前指数的最短两个补数表示形式的长度(以位为单位)。

IFloatingPoint<Double>.GetSignificandBitLength()

获取当前符号的长度(以位为单位)。

IFloatingPoint<Double>.GetSignificandByteCount()

获取将作为其一部分 TryWriteSignificandLittleEndian(Span<Byte>, Int32)写入的字节数。

IFloatingPoint<Double>.TryWriteExponentBigEndian(Span<Byte>, Int32)
IFloatingPoint<Double>.TryWriteExponentLittleEndian(Span<Byte>, Int32)

尝试将当前指数(以小端格式)写入给定范围。

IFloatingPoint<Double>.TryWriteSignificandBigEndian(Span<Byte>, Int32)
IFloatingPoint<Double>.TryWriteSignificandLittleEndian(Span<Byte>, Int32)

尝试将当前符号(以小端格式)写入给定范围。

适用于

线程安全性

此类型的所有成员都是线程安全的。 似乎修改实例状态的成员实际上返回使用新值初始化的新实例。 与任何其他类型一样,读取和写入包含此类型的实例的共享变量必须受到锁的保护,以确保线程安全。

另请参阅