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.
4 
5 /*============================================================
6 **
7 **
8 **
9 ** Purpose: A representation of an IEEE double precision
10 **          floating point number.
11 **
12 **
13 ===========================================================*/
14 
15 using System.Globalization;
16 using System.Runtime.CompilerServices;
17 using System.Runtime.InteropServices;
18 using System.Runtime.Versioning;
19 
20 namespace System
21 {
22     [Serializable]
23     [StructLayout(LayoutKind.Sequential)]
24     [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
25     public struct Double : IComparable, IConvertible, IFormattable, IComparable<Double>, IEquatable<Double>, ISpanFormattable
26     {
27         private double m_value; // Do not rename (binary serialization)
28 
29         //
30         // Public Constants
31         //
32         public const double MinValue = -1.7976931348623157E+308;
33         public const double MaxValue = 1.7976931348623157E+308;
34 
35         // Note Epsilon should be a double whose hex representation is 0x1
36         // on little endian machines.
37         public const double Epsilon = 4.9406564584124654E-324;
38         public const double NegativeInfinity = (double)-1.0 / (double)(0.0);
39         public const double PositiveInfinity = (double)1.0 / (double)(0.0);
40         public const double NaN = (double)0.0 / (double)0.0;
41 
42         // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
43         internal const double NegativeZero = -0.0;
44 
45         /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
46         [NonVersionable]
47         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsFiniteSystem.Double48         public unsafe static bool IsFinite(double d)
49         {
50             var bits = BitConverter.DoubleToInt64Bits(d);
51             return (bits & 0x7FFFFFFFFFFFFFFF) < 0x7FF0000000000000;
52         }
53 
54         /// <summary>Determines whether the specified value is infinite.</summary>
55         [NonVersionable]
56         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsInfinitySystem.Double57         public unsafe static bool IsInfinity(double d)
58         {
59             var bits = BitConverter.DoubleToInt64Bits(d);
60             return (bits & 0x7FFFFFFFFFFFFFFF) == 0x7FF0000000000000;
61         }
62 
63         /// <summary>Determines whether the specified value is NaN.</summary>
64         [NonVersionable]
65         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsNaNSystem.Double66         public unsafe static bool IsNaN(double d)
67         {
68             var bits = BitConverter.DoubleToInt64Bits(d);
69             return (bits & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000;
70         }
71 
72         /// <summary>Determines whether the specified value is negative.</summary>
73         [NonVersionable]
74         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsNegativeSystem.Double75         public unsafe static bool IsNegative(double d)
76         {
77             var bits = unchecked((ulong)BitConverter.DoubleToInt64Bits(d));
78             return (bits & 0x8000000000000000) == 0x8000000000000000;
79         }
80 
81         /// <summary>Determines whether the specified value is negative infinity.</summary>
82         [NonVersionable]
83         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsNegativeInfinitySystem.Double84         public static bool IsNegativeInfinity(double d)
85         {
86             return (d == double.NegativeInfinity);
87         }
88 
89         /// <summary>Determines whether the specified value is normal.</summary>
90         [NonVersionable]
91         // This is probably not worth inlining, it has branches and should be rarely called
IsNormalSystem.Double92         public unsafe static bool IsNormal(double d)
93         {
94             var bits = BitConverter.DoubleToInt64Bits(d);
95             bits &= 0x7FFFFFFFFFFFFFFF;
96             return (bits < 0x7FF0000000000000) && (bits != 0) && ((bits & 0x7FF0000000000000) != 0);
97         }
98 
99         /// <summary>Determines whether the specified value is positive infinity.</summary>
100         [NonVersionable]
101         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsPositiveInfinitySystem.Double102         public static bool IsPositiveInfinity(double d)
103         {
104             return (d == double.PositiveInfinity);
105         }
106 
107         /// <summary>Determines whether the specified value is subnormal.</summary>
108         [NonVersionable]
109         // This is probably not worth inlining, it has branches and should be rarely called
IsSubnormalSystem.Double110         public unsafe static bool IsSubnormal(double d)
111         {
112             var bits = BitConverter.DoubleToInt64Bits(d);
113             bits &= 0x7FFFFFFFFFFFFFFF;
114             return (bits < 0x7FF0000000000000) && (bits != 0) && ((bits & 0x7FF0000000000000) == 0);
115         }
116 
117         // Compares this object to another object, returning an instance of System.Relation.
118         // Null is considered less than any instance.
119         //
120         // If object is not of type Double, this method throws an ArgumentException.
121         //
122         // Returns a value less than zero if this  object
123         //
CompareToSystem.Double124         public int CompareTo(Object value)
125         {
126             if (value == null)
127             {
128                 return 1;
129             }
130             if (value is Double)
131             {
132                 double d = (double)value;
133                 if (m_value < d) return -1;
134                 if (m_value > d) return 1;
135                 if (m_value == d) return 0;
136 
137                 // At least one of the values is NaN.
138                 if (IsNaN(m_value))
139                     return (IsNaN(d) ? 0 : -1);
140                 else
141                     return 1;
142             }
143             throw new ArgumentException(SR.Arg_MustBeDouble);
144         }
145 
CompareToSystem.Double146         public int CompareTo(Double value)
147         {
148             if (m_value < value) return -1;
149             if (m_value > value) return 1;
150             if (m_value == value) return 0;
151 
152             // At least one of the values is NaN.
153             if (IsNaN(m_value))
154                 return (IsNaN(value) ? 0 : -1);
155             else
156                 return 1;
157         }
158 
159         // True if obj is another Double with the same value as the current instance.  This is
160         // a method of object equality, that only returns true if obj is also a double.
EqualsSystem.Double161         public override bool Equals(Object obj)
162         {
163             if (!(obj is Double))
164             {
165                 return false;
166             }
167             double temp = ((Double)obj).m_value;
168             // This code below is written this way for performance reasons i.e the != and == check is intentional.
169             if (temp == m_value)
170             {
171                 return true;
172             }
173             return IsNaN(temp) && IsNaN(m_value);
174         }
175 
176         [NonVersionable]
operator ==System.Double177         public static bool operator ==(Double left, Double right)
178         {
179             return left == right;
180         }
181 
182         [NonVersionable]
operator !=System.Double183         public static bool operator !=(Double left, Double right)
184         {
185             return left != right;
186         }
187 
188         [NonVersionable]
operator <System.Double189         public static bool operator <(Double left, Double right)
190         {
191             return left < right;
192         }
193 
194         [NonVersionable]
operator >System.Double195         public static bool operator >(Double left, Double right)
196         {
197             return left > right;
198         }
199 
200         [NonVersionable]
operator <=System.Double201         public static bool operator <=(Double left, Double right)
202         {
203             return left <= right;
204         }
205 
206         [NonVersionable]
operator >=System.Double207         public static bool operator >=(Double left, Double right)
208         {
209             return left >= right;
210         }
211 
EqualsSystem.Double212         public bool Equals(Double obj)
213         {
214             if (obj == m_value)
215             {
216                 return true;
217             }
218             return IsNaN(obj) && IsNaN(m_value);
219         }
220 
221         //The hashcode for a double is the absolute value of the integer representation
222         //of that double.
223         //
GetHashCodeSystem.Double224         public unsafe override int GetHashCode()
225         {
226             double d = m_value;
227             if (d == 0)
228             {
229                 // Ensure that 0 and -0 have the same hash code
230                 return 0;
231             }
232             long value = *(long*)(&d);
233             return unchecked((int)value) ^ ((int)(value >> 32));
234         }
235 
ToStringSystem.Double236         public override String ToString()
237         {
238             return Number.FormatDouble(m_value, null, NumberFormatInfo.CurrentInfo);
239         }
240 
ToStringSystem.Double241         public String ToString(String format)
242         {
243             return Number.FormatDouble(m_value, format, NumberFormatInfo.CurrentInfo);
244         }
245 
ToStringSystem.Double246         public String ToString(IFormatProvider provider)
247         {
248             return Number.FormatDouble(m_value, null, NumberFormatInfo.GetInstance(provider));
249         }
250 
ToStringSystem.Double251         public String ToString(String format, IFormatProvider provider)
252         {
253             return Number.FormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider));
254         }
255 
TryFormatSystem.Double256         public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
257         {
258             return Number.TryFormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
259         }
260 
ParseSystem.Double261         public static double Parse(String s)
262         {
263             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
264             return Number.ParseDouble(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
265         }
266 
ParseSystem.Double267         public static double Parse(String s, NumberStyles style)
268         {
269             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
270             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
271             return Number.ParseDouble(s, style, NumberFormatInfo.CurrentInfo);
272         }
273 
ParseSystem.Double274         public static double Parse(String s, IFormatProvider provider)
275         {
276             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
277             return Number.ParseDouble(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
278         }
279 
ParseSystem.Double280         public static double Parse(String s, NumberStyles style, IFormatProvider provider)
281         {
282             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
283             if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
284             return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider));
285         }
286 
287         // Parses a double from a String in the given style.  If
288         // a NumberFormatInfo isn't specified, the current culture's
289         // NumberFormatInfo is assumed.
290         //
291         // This method will not throw an OverflowException, but will return
292         // PositiveInfinity or NegativeInfinity for a number that is too
293         // large or too small.
294 
ParseSystem.Double295         public static double Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Integer, IFormatProvider provider = null)
296         {
297             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
298             return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider));
299         }
300 
301 
302 
TryParseSystem.Double303         public static bool TryParse(String s, out double result)
304         {
305             if (s == null)
306             {
307                 result = 0;
308                 return false;
309             }
310 
311             return TryParse((ReadOnlySpan<char>)s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
312         }
313 
TryParseSystem.Double314         public static bool TryParse(ReadOnlySpan<char> s, out double result)
315         {
316             return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
317         }
318 
TryParseSystem.Double319         public static bool TryParse(String s, NumberStyles style, IFormatProvider provider, out double result)
320         {
321             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
322 
323             if (s == null)
324             {
325                 result = 0;
326                 return false;
327             }
328 
329             return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
330         }
331 
TryParseSystem.Double332         public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out double result)
333         {
334             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
335             return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
336         }
337 
TryParseSystem.Double338         private static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out double result)
339         {
340             bool success = Number.TryParseDouble(s, style, info, out result);
341             if (!success)
342             {
343                 ReadOnlySpan<char> sTrim = StringSpanHelpers.Trim(s);
344                 if (StringSpanHelpers.Equals(sTrim, info.PositiveInfinitySymbol))
345                 {
346                     result = PositiveInfinity;
347                 }
348                 else if (StringSpanHelpers.Equals(sTrim, info.NegativeInfinitySymbol))
349                 {
350                     result = NegativeInfinity;
351                 }
352                 else if (StringSpanHelpers.Equals(sTrim, info.NaNSymbol))
353                 {
354                     result = NaN;
355                 }
356                 else
357                 {
358                     return false; // We really failed
359                 }
360             }
361             return true;
362         }
363 
364         //
365         // IConvertible implementation
366         //
367 
GetTypeCodeSystem.Double368         public TypeCode GetTypeCode()
369         {
370             return TypeCode.Double;
371         }
372 
IConvertible.ToBooleanSystem.Double373         bool IConvertible.ToBoolean(IFormatProvider provider)
374         {
375             return Convert.ToBoolean(m_value);
376         }
377 
IConvertible.ToCharSystem.Double378         char IConvertible.ToChar(IFormatProvider provider)
379         {
380             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Double", "Char"));
381         }
382 
IConvertible.ToSByteSystem.Double383         sbyte IConvertible.ToSByte(IFormatProvider provider)
384         {
385             return Convert.ToSByte(m_value);
386         }
387 
IConvertible.ToByteSystem.Double388         byte IConvertible.ToByte(IFormatProvider provider)
389         {
390             return Convert.ToByte(m_value);
391         }
392 
IConvertible.ToInt16System.Double393         short IConvertible.ToInt16(IFormatProvider provider)
394         {
395             return Convert.ToInt16(m_value);
396         }
397 
IConvertible.ToUInt16System.Double398         ushort IConvertible.ToUInt16(IFormatProvider provider)
399         {
400             return Convert.ToUInt16(m_value);
401         }
402 
IConvertible.ToInt32System.Double403         int IConvertible.ToInt32(IFormatProvider provider)
404         {
405             return Convert.ToInt32(m_value);
406         }
407 
IConvertible.ToUInt32System.Double408         uint IConvertible.ToUInt32(IFormatProvider provider)
409         {
410             return Convert.ToUInt32(m_value);
411         }
412 
IConvertible.ToInt64System.Double413         long IConvertible.ToInt64(IFormatProvider provider)
414         {
415             return Convert.ToInt64(m_value);
416         }
417 
IConvertible.ToUInt64System.Double418         ulong IConvertible.ToUInt64(IFormatProvider provider)
419         {
420             return Convert.ToUInt64(m_value);
421         }
422 
IConvertible.ToSingleSystem.Double423         float IConvertible.ToSingle(IFormatProvider provider)
424         {
425             return Convert.ToSingle(m_value);
426         }
427 
IConvertible.ToDoubleSystem.Double428         double IConvertible.ToDouble(IFormatProvider provider)
429         {
430             return m_value;
431         }
432 
IConvertible.ToDecimalSystem.Double433         Decimal IConvertible.ToDecimal(IFormatProvider provider)
434         {
435             return Convert.ToDecimal(m_value);
436         }
437 
IConvertible.ToDateTimeSystem.Double438         DateTime IConvertible.ToDateTime(IFormatProvider provider)
439         {
440             throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Double", "DateTime"));
441         }
442 
IConvertible.ToTypeSystem.Double443         Object IConvertible.ToType(Type type, IFormatProvider provider)
444         {
445             return Convert.DefaultToType((IConvertible)this, type, provider);
446         }
447     }
448 }
449