Double.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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. ** Purpose: A representation of an IEEE double precision
  9. ** floating point number.
  10. **
  11. **
  12. ===========================================================*/
  13. using System.Globalization;
  14. using System.Runtime.CompilerServices;
  15. using System.Runtime.InteropServices;
  16. using System.Runtime.Versioning;
  17. using Internal.Runtime.CompilerServices;
  18. namespace System
  19. {
  20. [Serializable]
  21. [StructLayout(LayoutKind.Sequential)]
  22. [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
  23. public readonly struct Double : IComparable, IConvertible, IFormattable, IComparable<double>, IEquatable<double>, ISpanFormattable
  24. {
  25. private readonly double m_value; // Do not rename (binary serialization)
  26. //
  27. // Public Constants
  28. //
  29. public const double MinValue = -1.7976931348623157E+308;
  30. public const double MaxValue = 1.7976931348623157E+308;
  31. // Note Epsilon should be a double whose hex representation is 0x1
  32. // on little endian machines.
  33. public const double Epsilon = 4.9406564584124654E-324;
  34. public const double NegativeInfinity = (double)-1.0 / (double)(0.0);
  35. public const double PositiveInfinity = (double)1.0 / (double)(0.0);
  36. public const double NaN = (double)0.0 / (double)0.0;
  37. // We use this explicit definition to avoid the confusion between 0.0 and -0.0.
  38. internal const double NegativeZero = -0.0;
  39. //
  40. // Constants for manipulating the private bit-representation
  41. //
  42. internal const ulong SignMask = 0x8000_0000_0000_0000;
  43. internal const int SignShift = 63;
  44. internal const int ShiftedSignMask = (int)(SignMask >> SignShift);
  45. internal const ulong ExponentMask = 0x7FF0_0000_0000_0000;
  46. internal const int ExponentShift = 52;
  47. internal const int ShiftedExponentMask = (int)(ExponentMask >> ExponentShift);
  48. internal const ulong SignificandMask = 0x000F_FFFF_FFFF_FFFF;
  49. internal const byte MinSign = 0;
  50. internal const byte MaxSign = 1;
  51. internal const ushort MinExponent = 0x0000;
  52. internal const ushort MaxExponent = 0x07FF;
  53. internal const ulong MinSignificand = 0x0000_0000_0000_0000;
  54. internal const ulong MaxSignificand = 0x000F_FFFF_FFFF_FFFF;
  55. /// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
  56. [NonVersionable]
  57. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  58. public static unsafe bool IsFinite(double d)
  59. {
  60. long bits = BitConverter.DoubleToInt64Bits(d);
  61. return (bits & 0x7FFFFFFFFFFFFFFF) < 0x7FF0000000000000;
  62. }
  63. /// <summary>Determines whether the specified value is infinite.</summary>
  64. [NonVersionable]
  65. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  66. public static unsafe bool IsInfinity(double d)
  67. {
  68. long bits = BitConverter.DoubleToInt64Bits(d);
  69. return (bits & 0x7FFFFFFFFFFFFFFF) == 0x7FF0000000000000;
  70. }
  71. /// <summary>Determines whether the specified value is NaN.</summary>
  72. [NonVersionable]
  73. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  74. public static unsafe bool IsNaN(double d)
  75. {
  76. // A NaN will never equal itself so this is an
  77. // easy and efficient way to check for NaN.
  78. #pragma warning disable CS1718
  79. return d != d;
  80. #pragma warning restore CS1718
  81. }
  82. /// <summary>Determines whether the specified value is negative.</summary>
  83. [NonVersionable]
  84. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  85. public static unsafe bool IsNegative(double d)
  86. {
  87. return BitConverter.DoubleToInt64Bits(d) < 0;
  88. }
  89. /// <summary>Determines whether the specified value is negative infinity.</summary>
  90. [NonVersionable]
  91. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  92. public static bool IsNegativeInfinity(double d)
  93. {
  94. return d == double.NegativeInfinity;
  95. }
  96. /// <summary>Determines whether the specified value is normal.</summary>
  97. [NonVersionable]
  98. // This is probably not worth inlining, it has branches and should be rarely called
  99. public static unsafe bool IsNormal(double d)
  100. {
  101. long bits = BitConverter.DoubleToInt64Bits(d);
  102. bits &= 0x7FFFFFFFFFFFFFFF;
  103. return (bits < 0x7FF0000000000000) && (bits != 0) && ((bits & 0x7FF0000000000000) != 0);
  104. }
  105. /// <summary>Determines whether the specified value is positive infinity.</summary>
  106. [NonVersionable]
  107. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  108. public static bool IsPositiveInfinity(double d)
  109. {
  110. return d == double.PositiveInfinity;
  111. }
  112. /// <summary>Determines whether the specified value is subnormal.</summary>
  113. [NonVersionable]
  114. // This is probably not worth inlining, it has branches and should be rarely called
  115. public static unsafe bool IsSubnormal(double d)
  116. {
  117. long bits = BitConverter.DoubleToInt64Bits(d);
  118. bits &= 0x7FFFFFFFFFFFFFFF;
  119. return (bits < 0x7FF0000000000000) && (bits != 0) && ((bits & 0x7FF0000000000000) == 0);
  120. }
  121. internal static int ExtractExponentFromBits(ulong bits)
  122. {
  123. return (int)(bits >> ExponentShift) & ShiftedExponentMask;
  124. }
  125. internal static ulong ExtractSignificandFromBits(ulong bits)
  126. {
  127. return bits & SignificandMask;
  128. }
  129. // Compares this object to another object, returning an instance of System.Relation.
  130. // Null is considered less than any instance.
  131. //
  132. // If object is not of type Double, this method throws an ArgumentException.
  133. //
  134. // Returns a value less than zero if this object
  135. //
  136. public int CompareTo(object? value)
  137. {
  138. if (value == null)
  139. {
  140. return 1;
  141. }
  142. if (value is double d)
  143. {
  144. if (m_value < d) return -1;
  145. if (m_value > d) return 1;
  146. if (m_value == d) return 0;
  147. // At least one of the values is NaN.
  148. if (IsNaN(m_value))
  149. return IsNaN(d) ? 0 : -1;
  150. else
  151. return 1;
  152. }
  153. throw new ArgumentException(SR.Arg_MustBeDouble);
  154. }
  155. public int CompareTo(double value)
  156. {
  157. if (m_value < value) return -1;
  158. if (m_value > value) return 1;
  159. if (m_value == value) return 0;
  160. // At least one of the values is NaN.
  161. if (IsNaN(m_value))
  162. return IsNaN(value) ? 0 : -1;
  163. else
  164. return 1;
  165. }
  166. // True if obj is another Double with the same value as the current instance. This is
  167. // a method of object equality, that only returns true if obj is also a double.
  168. public override bool Equals(object? obj)
  169. {
  170. if (!(obj is double))
  171. {
  172. return false;
  173. }
  174. double temp = ((double)obj).m_value;
  175. // This code below is written this way for performance reasons i.e the != and == check is intentional.
  176. if (temp == m_value)
  177. {
  178. return true;
  179. }
  180. return IsNaN(temp) && IsNaN(m_value);
  181. }
  182. [NonVersionable]
  183. public static bool operator ==(double left, double right) => left == right;
  184. [NonVersionable]
  185. public static bool operator !=(double left, double right) => left != right;
  186. [NonVersionable]
  187. public static bool operator <(double left, double right) => left < right;
  188. [NonVersionable]
  189. public static bool operator >(double left, double right) => left > right;
  190. [NonVersionable]
  191. public static bool operator <=(double left, double right) => left <= right;
  192. [NonVersionable]
  193. public static bool operator >=(double left, double right) => left >= right;
  194. public bool Equals(double obj)
  195. {
  196. if (obj == m_value)
  197. {
  198. return true;
  199. }
  200. return IsNaN(obj) && IsNaN(m_value);
  201. }
  202. // The hashcode for a double is the absolute value of the integer representation
  203. // of that double.
  204. [MethodImpl(MethodImplOptions.AggressiveInlining)] // 64-bit constants make the IL unusually large that makes the inliner to reject the method
  205. public override int GetHashCode()
  206. {
  207. long bits = Unsafe.As<double, long>(ref Unsafe.AsRef(in m_value));
  208. // Optimized check for IsNan() || IsZero()
  209. if (((bits - 1) & 0x7FFFFFFFFFFFFFFF) >= 0x7FF0000000000000)
  210. {
  211. // Ensure that all NaNs and both zeros have the same hash code
  212. bits &= 0x7FF0000000000000;
  213. }
  214. return unchecked((int)bits) ^ ((int)(bits >> 32));
  215. }
  216. public override string ToString()
  217. {
  218. return Number.FormatDouble(m_value, null, NumberFormatInfo.CurrentInfo);
  219. }
  220. public string ToString(string? format)
  221. {
  222. return Number.FormatDouble(m_value, format, NumberFormatInfo.CurrentInfo);
  223. }
  224. public string ToString(IFormatProvider? provider)
  225. {
  226. return Number.FormatDouble(m_value, null, NumberFormatInfo.GetInstance(provider));
  227. }
  228. public string ToString(string? format, IFormatProvider? provider)
  229. {
  230. return Number.FormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider));
  231. }
  232. public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
  233. {
  234. return Number.TryFormatDouble(m_value, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
  235. }
  236. public static double Parse(string s)
  237. {
  238. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  239. return Number.ParseDouble(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo);
  240. }
  241. public static double Parse(string s, NumberStyles style)
  242. {
  243. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  244. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  245. return Number.ParseDouble(s, style, NumberFormatInfo.CurrentInfo);
  246. }
  247. public static double Parse(string s, IFormatProvider? provider)
  248. {
  249. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  250. return Number.ParseDouble(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
  251. }
  252. public static double Parse(string s, NumberStyles style, IFormatProvider? provider)
  253. {
  254. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  255. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  256. return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider));
  257. }
  258. // Parses a double from a String in the given style. If
  259. // a NumberFormatInfo isn't specified, the current culture's
  260. // NumberFormatInfo is assumed.
  261. //
  262. // This method will not throw an OverflowException, but will return
  263. // PositiveInfinity or NegativeInfinity for a number that is too
  264. // large or too small.
  265. public static double Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands, IFormatProvider? provider = null)
  266. {
  267. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  268. return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider));
  269. }
  270. public static bool TryParse(string? s, out double result)
  271. {
  272. if (s == null)
  273. {
  274. result = 0;
  275. return false;
  276. }
  277. return TryParse((ReadOnlySpan<char>)s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
  278. }
  279. public static bool TryParse(ReadOnlySpan<char> s, out double result)
  280. {
  281. return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result);
  282. }
  283. public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out double result)
  284. {
  285. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  286. if (s == null)
  287. {
  288. result = 0;
  289. return false;
  290. }
  291. return TryParse((ReadOnlySpan<char>)s, style, NumberFormatInfo.GetInstance(provider), out result);
  292. }
  293. public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out double result)
  294. {
  295. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  296. return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result);
  297. }
  298. private static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out double result)
  299. {
  300. return Number.TryParseDouble(s, style, info, out result);
  301. }
  302. //
  303. // IConvertible implementation
  304. //
  305. public TypeCode GetTypeCode()
  306. {
  307. return TypeCode.Double;
  308. }
  309. bool IConvertible.ToBoolean(IFormatProvider? provider)
  310. {
  311. return Convert.ToBoolean(m_value);
  312. }
  313. char IConvertible.ToChar(IFormatProvider? provider)
  314. {
  315. throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Double", "Char"));
  316. }
  317. sbyte IConvertible.ToSByte(IFormatProvider? provider)
  318. {
  319. return Convert.ToSByte(m_value);
  320. }
  321. byte IConvertible.ToByte(IFormatProvider? provider)
  322. {
  323. return Convert.ToByte(m_value);
  324. }
  325. short IConvertible.ToInt16(IFormatProvider? provider)
  326. {
  327. return Convert.ToInt16(m_value);
  328. }
  329. ushort IConvertible.ToUInt16(IFormatProvider? provider)
  330. {
  331. return Convert.ToUInt16(m_value);
  332. }
  333. int IConvertible.ToInt32(IFormatProvider? provider)
  334. {
  335. return Convert.ToInt32(m_value);
  336. }
  337. uint IConvertible.ToUInt32(IFormatProvider? provider)
  338. {
  339. return Convert.ToUInt32(m_value);
  340. }
  341. long IConvertible.ToInt64(IFormatProvider? provider)
  342. {
  343. return Convert.ToInt64(m_value);
  344. }
  345. ulong IConvertible.ToUInt64(IFormatProvider? provider)
  346. {
  347. return Convert.ToUInt64(m_value);
  348. }
  349. float IConvertible.ToSingle(IFormatProvider? provider)
  350. {
  351. return Convert.ToSingle(m_value);
  352. }
  353. double IConvertible.ToDouble(IFormatProvider? provider)
  354. {
  355. return m_value;
  356. }
  357. decimal IConvertible.ToDecimal(IFormatProvider? provider)
  358. {
  359. return Convert.ToDecimal(m_value);
  360. }
  361. DateTime IConvertible.ToDateTime(IFormatProvider? provider)
  362. {
  363. throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Double", "DateTime"));
  364. }
  365. object IConvertible.ToType(Type type, IFormatProvider? provider)
  366. {
  367. return Convert.DefaultToType((IConvertible)this, type, provider);
  368. }
  369. }
  370. }