1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*============================================================
9 ** Purpose: A representation of an IEEE double precision
10 ** floating point number.
13 ===========================================================*/
15 using System
.Globalization
;
16 using System
.Runtime
.CompilerServices
;
17 using System
.Runtime
.InteropServices
;
18 using System
.Runtime
.Versioning
;
20 using Internal
.Runtime
.CompilerServices
;
25 [StructLayout(LayoutKind
.Sequential
)]
26 [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
27 public readonly struct Double
: IComparable
, IConvertible
, IFormattable
, IComparable
<double>, IEquatable
<double>, ISpanFormattable
29 private readonly double m_value
; // Do not rename (binary serialization)
34 public const double MinValue
= -1.7976931348623157E+308;
35 public const double MaxValue
= 1.7976931348623157E+308;
37 // Note Epsilon should be a double whose hex representation is 0x1
38 // on little endian machines.
39 public const double Epsilon
= 4.9406564584124654E-324;
40 public const double NegativeInfinity
= (double)-1.0 / (double)(0.0);
41 public const double PositiveInfinity
= (double)1.0 / (double)(0.0);
42 public const double NaN
= (double)0.0 / (double)0.0;
44 // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
45 internal const double NegativeZero
= -0.0;
48 // Constants for manipulating the private bit-representation
51 internal const ulong SignMask
= 0x8000_
0000_
0000_
0000;
52 internal const int SignShift
= 63;
53 internal const int ShiftedSignMask
= (int)(SignMask
>> SignShift
);
55 internal const ulong ExponentMask
= 0x7FF0_
0000_
0000_
0000;
56 internal const int ExponentShift
= 52;
57 internal const int ShiftedExponentMask
= (int)(ExponentMask
>> ExponentShift
);
59 internal const ulong SignificandMask
= 0x000F_FFFF_FFFF_FFFF
;
61 internal const byte MinSign
= 0;
62 internal const byte MaxSign
= 1;
64 internal const ushort MinExponent
= 0x0000;
65 internal const ushort MaxExponent
= 0x07FF;
67 internal const ulong MinSignificand
= 0x0000_
0000_
0000_
0000;
68 internal const ulong MaxSignificand
= 0x000F_FFFF_FFFF_FFFF
;
70 /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
72 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
73 public static unsafe bool IsFinite(double d
)
75 long bits
= BitConverter
.DoubleToInt64Bits(d
);
76 return (bits
& 0x7FFFFFFFFFFFFFFF) < 0x7FF0000000000000;
79 /// <summary>Determines whether the specified value is infinite.</summary>
81 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
82 public static unsafe bool IsInfinity(double d
)
84 long bits
= BitConverter
.DoubleToInt64Bits(d
);
85 return (bits
& 0x7FFFFFFFFFFFFFFF) == 0x7FF0000000000000;
88 /// <summary>Determines whether the specified value is NaN.</summary>
90 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
91 public static unsafe bool IsNaN(double d
)
93 long bits
= BitConverter
.DoubleToInt64Bits(d
);
94 return (bits
& 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000;
97 /// <summary>Determines whether the specified value is negative.</summary>
99 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
100 public static unsafe bool IsNegative(double d
)
102 return BitConverter
.DoubleToInt64Bits(d
) < 0;
105 /// <summary>Determines whether the specified value is negative infinity.</summary>
107 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
108 public static bool IsNegativeInfinity(double d
)
110 return d
== double.NegativeInfinity
;
113 /// <summary>Determines whether the specified value is normal.</summary>
115 // This is probably not worth inlining, it has branches and should be rarely called
116 public static unsafe bool IsNormal(double d
)
118 long bits
= BitConverter
.DoubleToInt64Bits(d
);
119 bits
&= 0x7FFFFFFFFFFFFFFF;
120 return (bits
< 0x7FF0000000000000) && (bits
!= 0) && ((bits
& 0x7FF0000000000000) != 0);
123 /// <summary>Determines whether the specified value is positive infinity.</summary>
125 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
126 public static bool IsPositiveInfinity(double d
)
128 return d
== double.PositiveInfinity
;
131 /// <summary>Determines whether the specified value is subnormal.</summary>
133 // This is probably not worth inlining, it has branches and should be rarely called
134 public static unsafe bool IsSubnormal(double d
)
136 long bits
= BitConverter
.DoubleToInt64Bits(d
);
137 bits
&= 0x7FFFFFFFFFFFFFFF;
138 return (bits
< 0x7FF0000000000000) && (bits
!= 0) && ((bits
& 0x7FF0000000000000) == 0);
141 internal static int ExtractExponentFromBits(ulong bits
)
143 return (int)(bits
>> ExponentShift
) & ShiftedExponentMask
;
146 internal static ulong ExtractSignificandFromBits(ulong bits
)
148 return bits
& SignificandMask
;
151 // Compares this object to another object, returning an instance of System.Relation.
152 // Null is considered less than any instance.
154 // If object is not of type Double, this method throws an ArgumentException.
156 // Returns a value less than zero if this object
158 public int CompareTo(object? value)
165 if (value is double d
)
167 if (m_value
< d
) return -1;
168 if (m_value
> d
) return 1;
169 if (m_value
== d
) return 0;
171 // At least one of the values is NaN.
173 return IsNaN(d
) ? 0 : -1;
178 throw new ArgumentException(SR
.Arg_MustBeDouble
);
181 public int CompareTo(double value)
183 if (m_value
< value) return -1;
184 if (m_value
> value) return 1;
185 if (m_value
== value) return 0;
187 // At least one of the values is NaN.
189 return IsNaN(value) ? 0 : -1;
194 // True if obj is another Double with the same value as the current instance. This is
195 // a method of object equality, that only returns true if obj is also a double.
196 public override bool Equals(object? obj
)
198 if (!(obj
is double))
202 double temp
= ((double)obj
).m_value
;
203 // This code below is written this way for performance reasons i.e the != and == check is intentional.
208 return IsNaN(temp
) && IsNaN(m_value
);
212 public static bool operator ==(double left
, double right
) => left
== right
;
215 public static bool operator !=(double left
, double right
) => left
!= right
;
218 public static bool operator <(double left
, double right
) => left
< right
;
221 public static bool operator >(double left
, double right
) => left
> right
;
224 public static bool operator <=(double left
, double right
) => left
<= right
;
227 public static bool operator >=(double left
, double right
) => left
>= right
;
229 public bool Equals(double obj
)
235 return IsNaN(obj
) && IsNaN(m_value
);
238 // The hashcode for a double is the absolute value of the integer representation
240 [MethodImpl(MethodImplOptions
.AggressiveInlining
)] // 64-bit constants make the IL unusually large that makes the inliner to reject the method
241 public override int GetHashCode()
243 long bits
= Unsafe
.As
<double, long>(ref Unsafe
.AsRef(in m_value
));
245 // Optimized check for IsNan() || IsZero()
246 if (((bits
- 1) & 0x7FFFFFFFFFFFFFFF) >= 0x7FF0000000000000)
248 // Ensure that all NaNs and both zeros have the same hash code
249 bits
&= 0x7FF0000000000000;
252 return unchecked((int)bits
) ^
((int)(bits
>> 32));
255 public override string ToString()
257 return Number
.FormatDouble(m_value
, null, NumberFormatInfo
.CurrentInfo
);
260 public string ToString(string? format
)
262 return Number
.FormatDouble(m_value
, format
, NumberFormatInfo
.CurrentInfo
);
265 public string ToString(IFormatProvider
? provider
)
267 return Number
.FormatDouble(m_value
, null, NumberFormatInfo
.GetInstance(provider
));
270 public string ToString(string? format
, IFormatProvider
? provider
)
272 return Number
.FormatDouble(m_value
, format
, NumberFormatInfo
.GetInstance(provider
));
275 public bool TryFormat(Span
<char> destination
, out int charsWritten
, ReadOnlySpan
<char> format
= default, IFormatProvider
? provider
= null)
277 return Number
.TryFormatDouble(m_value
, format
, NumberFormatInfo
.GetInstance(provider
), destination
, out charsWritten
);
280 public static double Parse(string s
)
282 if (s
== null) ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.s
);
283 return Number
.ParseDouble(s
, NumberStyles
.Float
| NumberStyles
.AllowThousands
, NumberFormatInfo
.CurrentInfo
);
286 public static double Parse(string s
, NumberStyles style
)
288 NumberFormatInfo
.ValidateParseStyleFloatingPoint(style
);
289 if (s
== null) ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.s
);
290 return Number
.ParseDouble(s
, style
, NumberFormatInfo
.CurrentInfo
);
293 public static double Parse(string s
, IFormatProvider
? provider
)
295 if (s
== null) ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.s
);
296 return Number
.ParseDouble(s
, NumberStyles
.Float
| NumberStyles
.AllowThousands
, NumberFormatInfo
.GetInstance(provider
));
299 public static double Parse(string s
, NumberStyles style
, IFormatProvider
? provider
)
301 NumberFormatInfo
.ValidateParseStyleFloatingPoint(style
);
302 if (s
== null) ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.s
);
303 return Number
.ParseDouble(s
, style
, NumberFormatInfo
.GetInstance(provider
));
306 // Parses a double from a String in the given style. If
307 // a NumberFormatInfo isn't specified, the current culture's
308 // NumberFormatInfo is assumed.
310 // This method will not throw an OverflowException, but will return
311 // PositiveInfinity or NegativeInfinity for a number that is too
312 // large or too small.
314 public static double Parse(ReadOnlySpan
<char> s
, NumberStyles style
= NumberStyles
.Float
| NumberStyles
.AllowThousands
, IFormatProvider
? provider
= null)
316 NumberFormatInfo
.ValidateParseStyleFloatingPoint(style
);
317 return Number
.ParseDouble(s
, style
, NumberFormatInfo
.GetInstance(provider
));
320 public static bool TryParse(string? s
, out double result
)
328 return TryParse((ReadOnlySpan
<char>)s
, NumberStyles
.Float
| NumberStyles
.AllowThousands
, NumberFormatInfo
.CurrentInfo
, out result
);
331 public static bool TryParse(ReadOnlySpan
<char> s
, out double result
)
333 return TryParse(s
, NumberStyles
.Float
| NumberStyles
.AllowThousands
, NumberFormatInfo
.CurrentInfo
, out result
);
336 public static bool TryParse(string? s
, NumberStyles style
, IFormatProvider
? provider
, out double result
)
338 NumberFormatInfo
.ValidateParseStyleFloatingPoint(style
);
346 return TryParse((ReadOnlySpan
<char>)s
, style
, NumberFormatInfo
.GetInstance(provider
), out result
);
349 public static bool TryParse(ReadOnlySpan
<char> s
, NumberStyles style
, IFormatProvider
? provider
, out double result
)
351 NumberFormatInfo
.ValidateParseStyleFloatingPoint(style
);
352 return TryParse(s
, style
, NumberFormatInfo
.GetInstance(provider
), out result
);
355 private static bool TryParse(ReadOnlySpan
<char> s
, NumberStyles style
, NumberFormatInfo info
, out double result
)
357 return Number
.TryParseDouble(s
, style
, info
, out result
);
361 // IConvertible implementation
364 public TypeCode
GetTypeCode()
366 return TypeCode
.Double
;
369 bool IConvertible
.ToBoolean(IFormatProvider
? provider
)
371 return Convert
.ToBoolean(m_value
);
374 char IConvertible
.ToChar(IFormatProvider
? provider
)
376 throw new InvalidCastException(SR
.Format(SR
.InvalidCast_FromTo
, "Double", "Char"));
379 sbyte IConvertible
.ToSByte(IFormatProvider
? provider
)
381 return Convert
.ToSByte(m_value
);
384 byte IConvertible
.ToByte(IFormatProvider
? provider
)
386 return Convert
.ToByte(m_value
);
389 short IConvertible
.ToInt16(IFormatProvider
? provider
)
391 return Convert
.ToInt16(m_value
);
394 ushort IConvertible
.ToUInt16(IFormatProvider
? provider
)
396 return Convert
.ToUInt16(m_value
);
399 int IConvertible
.ToInt32(IFormatProvider
? provider
)
401 return Convert
.ToInt32(m_value
);
404 uint IConvertible
.ToUInt32(IFormatProvider
? provider
)
406 return Convert
.ToUInt32(m_value
);
409 long IConvertible
.ToInt64(IFormatProvider
? provider
)
411 return Convert
.ToInt64(m_value
);
414 ulong IConvertible
.ToUInt64(IFormatProvider
? provider
)
416 return Convert
.ToUInt64(m_value
);
419 float IConvertible
.ToSingle(IFormatProvider
? provider
)
421 return Convert
.ToSingle(m_value
);
424 double IConvertible
.ToDouble(IFormatProvider
? provider
)
429 decimal IConvertible
.ToDecimal(IFormatProvider
? provider
)
431 return Convert
.ToDecimal(m_value
);
434 DateTime IConvertible
.ToDateTime(IFormatProvider
? provider
)
436 throw new InvalidCastException(SR
.Format(SR
.InvalidCast_FromTo
, "Double", "DateTime"));
439 object IConvertible
.ToType(Type type
, IFormatProvider
? provider
)
441 return Convert
.DefaultToType((IConvertible
)this, type
, provider
);