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