Improve Dictionary TryGetValue size/perfomance (dotnet/coreclr#27195)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Double.cs
blob58d50285dd2bb9f52252651277b74355a81b94f2
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 /*============================================================
6 **
7 **
8 **
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;
22 namespace System
24 [Serializable]
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)
32 // Public Constants
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>
71 [NonVersionable]
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>
80 [NonVersionable]
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>
89 [NonVersionable]
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>
98 [NonVersionable]
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>
106 [NonVersionable]
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>
114 [NonVersionable]
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>
124 [NonVersionable]
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>
132 [NonVersionable]
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)
160 if (value == null)
162 return 1;
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.
172 if (IsNaN(m_value))
173 return IsNaN(d) ? 0 : -1;
174 else
175 return 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.
188 if (IsNaN(m_value))
189 return IsNaN(value) ? 0 : -1;
190 else
191 return 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))
200 return false;
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.
204 if (temp == m_value)
206 return true;
208 return IsNaN(temp) && IsNaN(m_value);
211 [NonVersionable]
212 public static bool operator ==(double left, double right) => left == right;
214 [NonVersionable]
215 public static bool operator !=(double left, double right) => left != right;
217 [NonVersionable]
218 public static bool operator <(double left, double right) => left < right;
220 [NonVersionable]
221 public static bool operator >(double left, double right) => left > right;
223 [NonVersionable]
224 public static bool operator <=(double left, double right) => left <= right;
226 [NonVersionable]
227 public static bool operator >=(double left, double right) => left >= right;
229 public bool Equals(double obj)
231 if (obj == m_value)
233 return true;
235 return IsNaN(obj) && IsNaN(m_value);
238 // The hashcode for a double is the absolute value of the integer representation
239 // of that double.
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)
322 if (s == null)
324 result = 0;
325 return false;
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);
340 if (s == null)
342 result = 0;
343 return false;
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)
426 return m_value;
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);