Decimal.cs 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
  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. using System.Buffers.Binary;
  5. using System.Diagnostics;
  6. using System.Globalization;
  7. using System.Runtime.CompilerServices;
  8. using System.Runtime.InteropServices;
  9. using System.Runtime.Serialization;
  10. namespace System
  11. {
  12. // Implements the Decimal data type. The Decimal data type can
  13. // represent values ranging from -79,228,162,514,264,337,593,543,950,335 to
  14. // 79,228,162,514,264,337,593,543,950,335 with 28 significant digits. The
  15. // Decimal data type is ideally suited to financial calculations that
  16. // require a large number of significant digits and no round-off errors.
  17. //
  18. // The finite set of values of type Decimal are of the form m
  19. // / 10e, where m is an integer such that
  20. // -296 <; m <; 296, and e is an integer
  21. // between 0 and 28 inclusive.
  22. //
  23. // Contrary to the float and double data types, decimal
  24. // fractional numbers such as 0.1 can be represented exactly in the
  25. // Decimal representation. In the float and double
  26. // representations, such numbers are often infinite fractions, making those
  27. // representations more prone to round-off errors.
  28. //
  29. // The Decimal class implements widening conversions from the
  30. // ubyte, char, short, int, and long types
  31. // to Decimal. These widening conversions never loose any information
  32. // and never throw exceptions. The Decimal class also implements
  33. // narrowing conversions from Decimal to ubyte, char,
  34. // short, int, and long. These narrowing conversions round
  35. // the Decimal value towards zero to the nearest integer, and then
  36. // converts that integer to the destination type. An OverflowException
  37. // is thrown if the result is not within the range of the destination type.
  38. //
  39. // The Decimal class provides a widening conversion from
  40. // Currency to Decimal. This widening conversion never loses any
  41. // information and never throws exceptions. The Currency class provides
  42. // a narrowing conversion from Decimal to Currency. This
  43. // narrowing conversion rounds the Decimal to four decimals and then
  44. // converts that number to a Currency. An OverflowException
  45. // is thrown if the result is not within the range of the Currency type.
  46. //
  47. // The Decimal class provides narrowing conversions to and from the
  48. // float and double types. A conversion from Decimal to
  49. // float or double may loose precision, but will not loose
  50. // information about the overall magnitude of the numeric value, and will never
  51. // throw an exception. A conversion from float or double to
  52. // Decimal throws an OverflowException if the value is not within
  53. // the range of the Decimal type.
  54. [StructLayout(LayoutKind.Sequential)]
  55. [Serializable]
  56. [System.Runtime.Versioning.NonVersionable] // This only applies to field layout
  57. [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
  58. public readonly partial struct Decimal : IFormattable, IComparable, IConvertible, IComparable<decimal>, IEquatable<decimal>, IDeserializationCallback, ISpanFormattable
  59. {
  60. // Sign mask for the flags field. A value of zero in this bit indicates a
  61. // positive Decimal value, and a value of one in this bit indicates a
  62. // negative Decimal value.
  63. //
  64. // Look at OleAut's DECIMAL_NEG constant to check for negative values
  65. // in native code.
  66. private const int SignMask = unchecked((int)0x80000000);
  67. // Scale mask for the flags field. This byte in the flags field contains
  68. // the power of 10 to divide the Decimal value by. The scale byte must
  69. // contain a value between 0 and 28 inclusive.
  70. private const int ScaleMask = 0x00FF0000;
  71. // Number of bits scale is shifted by.
  72. private const int ScaleShift = 16;
  73. // Constant representing the Decimal value 0.
  74. public const decimal Zero = 0m;
  75. // Constant representing the Decimal value 1.
  76. public const decimal One = 1m;
  77. // Constant representing the Decimal value -1.
  78. public const decimal MinusOne = -1m;
  79. // Constant representing the largest possible Decimal value. The value of
  80. // this constant is 79,228,162,514,264,337,593,543,950,335.
  81. public const decimal MaxValue = 79228162514264337593543950335m;
  82. // Constant representing the smallest possible Decimal value. The value of
  83. // this constant is -79,228,162,514,264,337,593,543,950,335.
  84. public const decimal MinValue = -79228162514264337593543950335m;
  85. // The lo, mid, hi, and flags fields contain the representation of the
  86. // Decimal value. The lo, mid, and hi fields contain the 96-bit integer
  87. // part of the Decimal. Bits 0-15 (the lower word) of the flags field are
  88. // unused and must be zero; bits 16-23 contain must contain a value between
  89. // 0 and 28, indicating the power of 10 to divide the 96-bit integer part
  90. // by to produce the Decimal value; bits 24-30 are unused and must be zero;
  91. // and finally bit 31 indicates the sign of the Decimal value, 0 meaning
  92. // positive and 1 meaning negative.
  93. //
  94. // NOTE: Do not change the order in which these fields are declared. The
  95. // native methods in this class rely on this particular order.
  96. // Do not rename (binary serialization).
  97. private readonly int flags;
  98. private readonly int hi;
  99. private readonly int lo;
  100. private readonly int mid;
  101. // Constructs a Decimal from an integer value.
  102. //
  103. public Decimal(int value)
  104. {
  105. if (value >= 0)
  106. {
  107. flags = 0;
  108. }
  109. else
  110. {
  111. flags = SignMask;
  112. value = -value;
  113. }
  114. lo = value;
  115. mid = 0;
  116. hi = 0;
  117. }
  118. // Constructs a Decimal from an unsigned integer value.
  119. //
  120. [CLSCompliant(false)]
  121. public Decimal(uint value)
  122. {
  123. flags = 0;
  124. lo = (int)value;
  125. mid = 0;
  126. hi = 0;
  127. }
  128. // Constructs a Decimal from a long value.
  129. //
  130. public Decimal(long value)
  131. {
  132. if (value >= 0)
  133. {
  134. flags = 0;
  135. }
  136. else
  137. {
  138. flags = SignMask;
  139. value = -value;
  140. }
  141. lo = (int)value;
  142. mid = (int)(value >> 32);
  143. hi = 0;
  144. }
  145. // Constructs a Decimal from an unsigned long value.
  146. //
  147. [CLSCompliant(false)]
  148. public Decimal(ulong value)
  149. {
  150. flags = 0;
  151. lo = (int)value;
  152. mid = (int)(value >> 32);
  153. hi = 0;
  154. }
  155. // Constructs a Decimal from a float value.
  156. //
  157. public Decimal(float value)
  158. {
  159. DecCalc.VarDecFromR4(value, out AsMutable(ref this));
  160. }
  161. // Constructs a Decimal from a double value.
  162. //
  163. public Decimal(double value)
  164. {
  165. DecCalc.VarDecFromR8(value, out AsMutable(ref this));
  166. }
  167. //
  168. // Decimal <==> Currency conversion.
  169. //
  170. // A Currency represents a positive or negative decimal value with 4 digits past the decimal point. The actual Int64 representation used by these methods
  171. // is the currency value multiplied by 10,000. For example, a currency value of $12.99 would be represented by the Int64 value 129,900.
  172. //
  173. public static decimal FromOACurrency(long cy)
  174. {
  175. ulong absoluteCy; // has to be ulong to accommodate the case where cy == long.MinValue.
  176. bool isNegative = false;
  177. if (cy < 0)
  178. {
  179. isNegative = true;
  180. absoluteCy = (ulong)(-cy);
  181. }
  182. else
  183. {
  184. absoluteCy = (ulong)cy;
  185. }
  186. // In most cases, FromOACurrency() produces a Decimal with Scale set to 4. Unless, that is, some of the trailing digits past the decimal point are zero,
  187. // in which case, for compatibility with .Net, we reduce the Scale by the number of zeros. While the result is still numerically equivalent, the scale does
  188. // affect the ToString() value. In particular, it prevents a converted currency value of $12.95 from printing uglily as "12.9500".
  189. int scale = 4;
  190. if (absoluteCy != 0) // For compatibility, a currency of 0 emits the Decimal "0.0000" (scale set to 4).
  191. {
  192. while (scale != 0 && ((absoluteCy % 10) == 0))
  193. {
  194. scale--;
  195. absoluteCy /= 10;
  196. }
  197. }
  198. return new decimal((int)absoluteCy, (int)(absoluteCy >> 32), 0, isNegative, (byte)scale);
  199. }
  200. public static long ToOACurrency(decimal value)
  201. {
  202. return DecCalc.VarCyFromDec(ref AsMutable(ref value));
  203. }
  204. private static bool IsValid(int flags) => (flags & ~(SignMask | ScaleMask)) == 0 && ((uint)(flags & ScaleMask) <= (28 << ScaleShift));
  205. // Constructs a Decimal from an integer array containing a binary
  206. // representation. The bits argument must be a non-null integer
  207. // array with four elements. bits[0], bits[1], and
  208. // bits[2] contain the low, middle, and high 32 bits of the 96-bit
  209. // integer part of the Decimal. bits[3] contains the scale factor
  210. // and sign of the Decimal: bits 0-15 (the lower word) are unused and must
  211. // be zero; bits 16-23 must contain a value between 0 and 28, indicating
  212. // the power of 10 to divide the 96-bit integer part by to produce the
  213. // Decimal value; bits 24-30 are unused and must be zero; and finally bit
  214. // 31 indicates the sign of the Decimal value, 0 meaning positive and 1
  215. // meaning negative.
  216. //
  217. // Note that there are several possible binary representations for the
  218. // same numeric value. For example, the value 1 can be represented as {1,
  219. // 0, 0, 0} (integer value 1 with a scale factor of 0) and equally well as
  220. // {1000, 0, 0, 0x30000} (integer value 1000 with a scale factor of 3).
  221. // The possible binary representations of a particular value are all
  222. // equally valid, and all are numerically equivalent.
  223. //
  224. public Decimal(int[] bits)
  225. {
  226. if (bits == null)
  227. throw new ArgumentNullException(nameof(bits));
  228. if (bits.Length == 4)
  229. {
  230. int f = bits[3];
  231. if (IsValid(f))
  232. {
  233. lo = bits[0];
  234. mid = bits[1];
  235. hi = bits[2];
  236. flags = f;
  237. return;
  238. }
  239. }
  240. throw new ArgumentException(SR.Arg_DecBitCtor);
  241. }
  242. // Constructs a Decimal from its constituent parts.
  243. //
  244. public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
  245. {
  246. if (scale > 28)
  247. throw new ArgumentOutOfRangeException(nameof(scale), SR.ArgumentOutOfRange_DecimalScale);
  248. this.lo = lo;
  249. this.mid = mid;
  250. this.hi = hi;
  251. flags = ((int)scale) << 16;
  252. if (isNegative)
  253. flags |= SignMask;
  254. }
  255. void IDeserializationCallback.OnDeserialization(object sender)
  256. {
  257. // OnDeserialization is called after each instance of this class is deserialized.
  258. // This callback method performs decimal validation after being deserialized.
  259. if (!IsValid(flags))
  260. throw new SerializationException(SR.Overflow_Decimal);
  261. }
  262. // Constructs a Decimal from its constituent parts.
  263. private Decimal(int lo, int mid, int hi, int flags)
  264. {
  265. if (IsValid(flags))
  266. {
  267. this.lo = lo;
  268. this.mid = mid;
  269. this.hi = hi;
  270. this.flags = flags;
  271. return;
  272. }
  273. throw new ArgumentException(SR.Arg_DecBitCtor);
  274. }
  275. private Decimal(in decimal d, int flags)
  276. {
  277. this = d;
  278. this.flags = flags;
  279. }
  280. // Returns the absolute value of the given Decimal. If d is
  281. // positive, the result is d. If d is negative, the result
  282. // is -d.
  283. //
  284. internal static decimal Abs(in decimal d)
  285. {
  286. return new decimal(in d, d.flags & ~SignMask);
  287. }
  288. // Adds two Decimal values.
  289. //
  290. public static decimal Add(decimal d1, decimal d2)
  291. {
  292. DecCalc.DecAddSub(ref AsMutable(ref d1), ref AsMutable(ref d2), false);
  293. return d1;
  294. }
  295. // Rounds a Decimal to an integer value. The Decimal argument is rounded
  296. // towards positive infinity.
  297. public static decimal Ceiling(decimal d)
  298. {
  299. int flags = d.flags;
  300. if ((flags & ScaleMask) != 0)
  301. DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), MidpointRounding.ToPositiveInfinity);
  302. return d;
  303. }
  304. // Compares two Decimal values, returning an integer that indicates their
  305. // relationship.
  306. //
  307. public static int Compare(decimal d1, decimal d2)
  308. {
  309. return DecCalc.VarDecCmp(in d1, in d2);
  310. }
  311. // Compares this object to another object, returning an integer that
  312. // indicates the relationship.
  313. // Returns a value less than zero if this object
  314. // null is considered to be less than any instance.
  315. // If object is not of type Decimal, this method throws an ArgumentException.
  316. //
  317. public int CompareTo(object value)
  318. {
  319. if (value == null)
  320. return 1;
  321. if (!(value is decimal))
  322. throw new ArgumentException(SR.Arg_MustBeDecimal);
  323. decimal other = (decimal)value;
  324. return DecCalc.VarDecCmp(in this, in other);
  325. }
  326. public int CompareTo(decimal value)
  327. {
  328. return DecCalc.VarDecCmp(in this, in value);
  329. }
  330. // Divides two Decimal values.
  331. //
  332. public static decimal Divide(decimal d1, decimal d2)
  333. {
  334. DecCalc.VarDecDiv(ref AsMutable(ref d1), ref AsMutable(ref d2));
  335. return d1;
  336. }
  337. // Checks if this Decimal is equal to a given object. Returns true
  338. // if the given object is a boxed Decimal and its value is equal to the
  339. // value of this Decimal. Returns false otherwise.
  340. //
  341. public override bool Equals(object value)
  342. {
  343. if (value is decimal)
  344. {
  345. decimal other = (decimal)value;
  346. return DecCalc.VarDecCmp(in this, in other) == 0;
  347. }
  348. return false;
  349. }
  350. public bool Equals(decimal value)
  351. {
  352. return DecCalc.VarDecCmp(in this, in value) == 0;
  353. }
  354. // Returns the hash code for this Decimal.
  355. //
  356. public override int GetHashCode() => DecCalc.GetHashCode(in this);
  357. // Compares two Decimal values for equality. Returns true if the two
  358. // Decimal values are equal, or false if they are not equal.
  359. //
  360. public static bool Equals(decimal d1, decimal d2)
  361. {
  362. return DecCalc.VarDecCmp(in d1, in d2) == 0;
  363. }
  364. // Rounds a Decimal to an integer value. The Decimal argument is rounded
  365. // towards negative infinity.
  366. //
  367. public static decimal Floor(decimal d)
  368. {
  369. int flags = d.flags;
  370. if ((flags & ScaleMask) != 0)
  371. DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), MidpointRounding.ToNegativeInfinity);
  372. return d;
  373. }
  374. // Converts this Decimal to a string. The resulting string consists of an
  375. // optional minus sign ("-") followed to a sequence of digits ("0" - "9"),
  376. // optionally followed by a decimal point (".") and another sequence of
  377. // digits.
  378. //
  379. public override string ToString()
  380. {
  381. return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo);
  382. }
  383. public string ToString(string format)
  384. {
  385. return Number.FormatDecimal(this, format, NumberFormatInfo.CurrentInfo);
  386. }
  387. public string ToString(IFormatProvider provider)
  388. {
  389. return Number.FormatDecimal(this, null, NumberFormatInfo.GetInstance(provider));
  390. }
  391. public string ToString(string format, IFormatProvider provider)
  392. {
  393. return Number.FormatDecimal(this, format, NumberFormatInfo.GetInstance(provider));
  394. }
  395. public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
  396. {
  397. return Number.TryFormatDecimal(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
  398. }
  399. // Converts a string to a Decimal. The string must consist of an optional
  400. // minus sign ("-") followed by a sequence of digits ("0" - "9"). The
  401. // sequence of digits may optionally contain a single decimal point (".")
  402. // character. Leading and trailing whitespace characters are allowed.
  403. // Parse also allows a currency symbol, a trailing negative sign, and
  404. // parentheses in the number.
  405. //
  406. public static decimal Parse(string s)
  407. {
  408. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  409. return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo);
  410. }
  411. public static decimal Parse(string s, NumberStyles style)
  412. {
  413. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  414. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  415. return Number.ParseDecimal(s, style, NumberFormatInfo.CurrentInfo);
  416. }
  417. public static decimal Parse(string s, IFormatProvider provider)
  418. {
  419. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  420. return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider));
  421. }
  422. public static decimal Parse(string s, NumberStyles style, IFormatProvider provider)
  423. {
  424. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  425. if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
  426. return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider));
  427. }
  428. public static decimal Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles.Number, IFormatProvider provider = null)
  429. {
  430. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  431. return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider));
  432. }
  433. public static bool TryParse(string s, out decimal result)
  434. {
  435. if (s == null)
  436. {
  437. result = 0;
  438. return false;
  439. }
  440. return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK;
  441. }
  442. public static bool TryParse(ReadOnlySpan<char> s, out decimal result)
  443. {
  444. return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK;
  445. }
  446. public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out decimal result)
  447. {
  448. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  449. if (s == null)
  450. {
  451. result = 0;
  452. return false;
  453. }
  454. return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
  455. }
  456. public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out decimal result)
  457. {
  458. NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  459. return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
  460. }
  461. // Returns a binary representation of a Decimal. The return value is an
  462. // integer array with four elements. Elements 0, 1, and 2 contain the low,
  463. // middle, and high 32 bits of the 96-bit integer part of the Decimal.
  464. // Element 3 contains the scale factor and sign of the Decimal: bits 0-15
  465. // (the lower word) are unused; bits 16-23 contain a value between 0 and
  466. // 28, indicating the power of 10 to divide the 96-bit integer part by to
  467. // produce the Decimal value; bits 24-30 are unused; and finally bit 31
  468. // indicates the sign of the Decimal value, 0 meaning positive and 1
  469. // meaning negative.
  470. //
  471. public static int[] GetBits(decimal d)
  472. {
  473. return new int[] { d.lo, d.mid, d.hi, d.flags };
  474. }
  475. internal static void GetBytes(in decimal d, byte[] buffer)
  476. {
  477. Debug.Assert((buffer != null && buffer.Length >= 16), "[GetBytes]buffer != null && buffer.Length >= 16");
  478. buffer[0] = (byte)d.lo;
  479. buffer[1] = (byte)(d.lo >> 8);
  480. buffer[2] = (byte)(d.lo >> 16);
  481. buffer[3] = (byte)(d.lo >> 24);
  482. buffer[4] = (byte)d.mid;
  483. buffer[5] = (byte)(d.mid >> 8);
  484. buffer[6] = (byte)(d.mid >> 16);
  485. buffer[7] = (byte)(d.mid >> 24);
  486. buffer[8] = (byte)d.hi;
  487. buffer[9] = (byte)(d.hi >> 8);
  488. buffer[10] = (byte)(d.hi >> 16);
  489. buffer[11] = (byte)(d.hi >> 24);
  490. buffer[12] = (byte)d.flags;
  491. buffer[13] = (byte)(d.flags >> 8);
  492. buffer[14] = (byte)(d.flags >> 16);
  493. buffer[15] = (byte)(d.flags >> 24);
  494. }
  495. internal static decimal ToDecimal(ReadOnlySpan<byte> span)
  496. {
  497. Debug.Assert((span.Length >= 16), "span.Length >= 16");
  498. int lo = BinaryPrimitives.ReadInt32LittleEndian(span);
  499. int mid = BinaryPrimitives.ReadInt32LittleEndian(span.Slice(4));
  500. int hi = BinaryPrimitives.ReadInt32LittleEndian(span.Slice(8));
  501. int flags = BinaryPrimitives.ReadInt32LittleEndian(span.Slice(12));
  502. return new decimal(lo, mid, hi, flags);
  503. }
  504. // Returns the larger of two Decimal values.
  505. //
  506. internal static ref readonly decimal Max(in decimal d1, in decimal d2)
  507. {
  508. return ref DecCalc.VarDecCmp(in d1, in d2) >= 0 ? ref d1 : ref d2;
  509. }
  510. // Returns the smaller of two Decimal values.
  511. //
  512. internal static ref readonly decimal Min(in decimal d1, in decimal d2)
  513. {
  514. return ref DecCalc.VarDecCmp(in d1, in d2) < 0 ? ref d1 : ref d2;
  515. }
  516. public static decimal Remainder(decimal d1, decimal d2)
  517. {
  518. DecCalc.VarDecMod(ref AsMutable(ref d1), ref AsMutable(ref d2));
  519. return d1;
  520. }
  521. // Multiplies two Decimal values.
  522. //
  523. public static decimal Multiply(decimal d1, decimal d2)
  524. {
  525. DecCalc.VarDecMul(ref AsMutable(ref d1), ref AsMutable(ref d2));
  526. return d1;
  527. }
  528. // Returns the negated value of the given Decimal. If d is non-zero,
  529. // the result is -d. If d is zero, the result is zero.
  530. //
  531. public static decimal Negate(decimal d)
  532. {
  533. return new decimal(in d, d.flags ^ SignMask);
  534. }
  535. // Rounds a Decimal value to a given number of decimal places. The value
  536. // given by d is rounded to the number of decimal places given by
  537. // decimals. The decimals argument must be an integer between
  538. // 0 and 28 inclusive.
  539. //
  540. // By default a mid-point value is rounded to the nearest even number. If the mode is
  541. // passed in, it can also round away from zero.
  542. public static decimal Round(decimal d) => Round(ref d, 0, MidpointRounding.ToEven);
  543. public static decimal Round(decimal d, int decimals) => Round(ref d, decimals, MidpointRounding.ToEven);
  544. public static decimal Round(decimal d, MidpointRounding mode) => Round(ref d, 0, mode);
  545. public static decimal Round(decimal d, int decimals, MidpointRounding mode) => Round(ref d, decimals, mode);
  546. private static decimal Round(ref decimal d, int decimals, MidpointRounding mode)
  547. {
  548. if ((uint)decimals > 28)
  549. throw new ArgumentOutOfRangeException(nameof(decimals), SR.ArgumentOutOfRange_DecimalRound);
  550. if ((uint)mode > (uint)MidpointRounding.ToPositiveInfinity)
  551. throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode));
  552. int scale = d.Scale - decimals;
  553. if (scale > 0)
  554. DecCalc.InternalRound(ref AsMutable(ref d), (uint)scale, mode);
  555. return d;
  556. }
  557. internal static int Sign(in decimal d) => (d.lo | d.mid | d.hi) == 0 ? 0 : (d.flags >> 31) | 1;
  558. // Subtracts two Decimal values.
  559. //
  560. public static decimal Subtract(decimal d1, decimal d2)
  561. {
  562. DecCalc.DecAddSub(ref AsMutable(ref d1), ref AsMutable(ref d2), true);
  563. return d1;
  564. }
  565. // Converts a Decimal to an unsigned byte. The Decimal value is rounded
  566. // towards zero to the nearest integer value, and the result of this
  567. // operation is returned as a byte.
  568. //
  569. public static byte ToByte(decimal value)
  570. {
  571. uint temp;
  572. try
  573. {
  574. temp = ToUInt32(value);
  575. }
  576. catch (OverflowException)
  577. {
  578. Number.ThrowOverflowException(TypeCode.Byte);
  579. throw;
  580. }
  581. if (temp != (byte)temp) Number.ThrowOverflowException(TypeCode.Byte);
  582. return (byte)temp;
  583. }
  584. // Converts a Decimal to a signed byte. The Decimal value is rounded
  585. // towards zero to the nearest integer value, and the result of this
  586. // operation is returned as a byte.
  587. //
  588. [CLSCompliant(false)]
  589. public static sbyte ToSByte(decimal value)
  590. {
  591. int temp;
  592. try
  593. {
  594. temp = ToInt32(value);
  595. }
  596. catch (OverflowException)
  597. {
  598. Number.ThrowOverflowException(TypeCode.SByte);
  599. throw;
  600. }
  601. if (temp != (sbyte)temp) Number.ThrowOverflowException(TypeCode.SByte);
  602. return (sbyte)temp;
  603. }
  604. // Converts a Decimal to a short. The Decimal value is
  605. // rounded towards zero to the nearest integer value, and the result of
  606. // this operation is returned as a short.
  607. //
  608. public static short ToInt16(decimal value)
  609. {
  610. int temp;
  611. try
  612. {
  613. temp = ToInt32(value);
  614. }
  615. catch (OverflowException)
  616. {
  617. Number.ThrowOverflowException(TypeCode.Int16);
  618. throw;
  619. }
  620. if (temp != (short)temp) Number.ThrowOverflowException(TypeCode.Int16);
  621. return (short)temp;
  622. }
  623. // Converts a Decimal to a double. Since a double has fewer significant
  624. // digits than a Decimal, this operation may produce round-off errors.
  625. //
  626. public static double ToDouble(decimal d)
  627. {
  628. return DecCalc.VarR8FromDec(in d);
  629. }
  630. // Converts a Decimal to an integer. The Decimal value is rounded towards
  631. // zero to the nearest integer value, and the result of this operation is
  632. // returned as an integer.
  633. //
  634. public static int ToInt32(decimal d)
  635. {
  636. Truncate(ref d);
  637. if ((d.hi | d.mid) == 0)
  638. {
  639. int i = d.lo;
  640. if (!d.IsNegative)
  641. {
  642. if (i >= 0) return i;
  643. }
  644. else
  645. {
  646. i = -i;
  647. if (i <= 0) return i;
  648. }
  649. }
  650. throw new OverflowException(SR.Overflow_Int32);
  651. }
  652. // Converts a Decimal to a long. The Decimal value is rounded towards zero
  653. // to the nearest integer value, and the result of this operation is
  654. // returned as a long.
  655. //
  656. public static long ToInt64(decimal d)
  657. {
  658. Truncate(ref d);
  659. if (d.hi == 0)
  660. {
  661. long l = (long)d.Low64;
  662. if (!d.IsNegative)
  663. {
  664. if (l >= 0) return l;
  665. }
  666. else
  667. {
  668. l = -l;
  669. if (l <= 0) return l;
  670. }
  671. }
  672. throw new OverflowException(SR.Overflow_Int64);
  673. }
  674. // Converts a Decimal to an ushort. The Decimal
  675. // value is rounded towards zero to the nearest integer value, and the
  676. // result of this operation is returned as an ushort.
  677. //
  678. [CLSCompliant(false)]
  679. public static ushort ToUInt16(decimal value)
  680. {
  681. uint temp;
  682. try
  683. {
  684. temp = ToUInt32(value);
  685. }
  686. catch (OverflowException)
  687. {
  688. Number.ThrowOverflowException(TypeCode.UInt16);
  689. throw;
  690. }
  691. if (temp != (ushort)temp) Number.ThrowOverflowException(TypeCode.UInt16);
  692. return (ushort)temp;
  693. }
  694. // Converts a Decimal to an unsigned integer. The Decimal
  695. // value is rounded towards zero to the nearest integer value, and the
  696. // result of this operation is returned as an unsigned integer.
  697. //
  698. [CLSCompliant(false)]
  699. public static uint ToUInt32(decimal d)
  700. {
  701. Truncate(ref d);
  702. if ((d.hi | d.mid) == 0)
  703. {
  704. uint i = d.Low;
  705. if (!d.IsNegative || i == 0)
  706. return i;
  707. }
  708. throw new OverflowException(SR.Overflow_UInt32);
  709. }
  710. // Converts a Decimal to an unsigned long. The Decimal
  711. // value is rounded towards zero to the nearest integer value, and the
  712. // result of this operation is returned as a long.
  713. //
  714. [CLSCompliant(false)]
  715. public static ulong ToUInt64(decimal d)
  716. {
  717. Truncate(ref d);
  718. if (d.hi == 0)
  719. {
  720. ulong l = d.Low64;
  721. if (!d.IsNegative || l == 0)
  722. return l;
  723. }
  724. throw new OverflowException(SR.Overflow_UInt64);
  725. }
  726. // Converts a Decimal to a float. Since a float has fewer significant
  727. // digits than a Decimal, this operation may produce round-off errors.
  728. //
  729. public static float ToSingle(decimal d)
  730. {
  731. return DecCalc.VarR4FromDec(in d);
  732. }
  733. // Truncates a Decimal to an integer value. The Decimal argument is rounded
  734. // towards zero to the nearest integer value, corresponding to removing all
  735. // digits after the decimal point.
  736. //
  737. public static decimal Truncate(decimal d)
  738. {
  739. Truncate(ref d);
  740. return d;
  741. }
  742. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  743. private static void Truncate(ref decimal d)
  744. {
  745. int flags = d.flags;
  746. if ((flags & ScaleMask) != 0)
  747. DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), MidpointRounding.ToZero);
  748. }
  749. public static implicit operator decimal(byte value)
  750. {
  751. return new decimal((uint)value);
  752. }
  753. [CLSCompliant(false)]
  754. public static implicit operator decimal(sbyte value)
  755. {
  756. return new decimal(value);
  757. }
  758. public static implicit operator decimal(short value)
  759. {
  760. return new decimal(value);
  761. }
  762. [CLSCompliant(false)]
  763. public static implicit operator decimal(ushort value)
  764. {
  765. return new decimal((uint)value);
  766. }
  767. public static implicit operator decimal(char value)
  768. {
  769. return new decimal((uint)value);
  770. }
  771. public static implicit operator decimal(int value)
  772. {
  773. return new decimal(value);
  774. }
  775. [CLSCompliant(false)]
  776. public static implicit operator decimal(uint value)
  777. {
  778. return new decimal(value);
  779. }
  780. public static implicit operator decimal(long value)
  781. {
  782. return new decimal(value);
  783. }
  784. [CLSCompliant(false)]
  785. public static implicit operator decimal(ulong value)
  786. {
  787. return new decimal(value);
  788. }
  789. public static explicit operator decimal(float value)
  790. {
  791. return new decimal(value);
  792. }
  793. public static explicit operator decimal(double value)
  794. {
  795. return new decimal(value);
  796. }
  797. public static explicit operator byte(decimal value)
  798. {
  799. return ToByte(value);
  800. }
  801. [CLSCompliant(false)]
  802. public static explicit operator sbyte(decimal value)
  803. {
  804. return ToSByte(value);
  805. }
  806. public static explicit operator char(decimal value)
  807. {
  808. ushort temp;
  809. try
  810. {
  811. temp = ToUInt16(value);
  812. }
  813. catch (OverflowException e)
  814. {
  815. throw new OverflowException(SR.Overflow_Char, e);
  816. }
  817. return (char)temp;
  818. }
  819. public static explicit operator short(decimal value)
  820. {
  821. return ToInt16(value);
  822. }
  823. [CLSCompliant(false)]
  824. public static explicit operator ushort(decimal value)
  825. {
  826. return ToUInt16(value);
  827. }
  828. public static explicit operator int(decimal value)
  829. {
  830. return ToInt32(value);
  831. }
  832. [CLSCompliant(false)]
  833. public static explicit operator uint(decimal value)
  834. {
  835. return ToUInt32(value);
  836. }
  837. public static explicit operator long(decimal value)
  838. {
  839. return ToInt64(value);
  840. }
  841. [CLSCompliant(false)]
  842. public static explicit operator ulong(decimal value)
  843. {
  844. return ToUInt64(value);
  845. }
  846. public static explicit operator float(decimal value)
  847. {
  848. return ToSingle(value);
  849. }
  850. public static explicit operator double(decimal value)
  851. {
  852. return ToDouble(value);
  853. }
  854. public static decimal operator +(decimal d)
  855. {
  856. return d;
  857. }
  858. public static decimal operator -(decimal d)
  859. {
  860. return new decimal(in d, d.flags ^ SignMask);
  861. }
  862. public static decimal operator ++(decimal d)
  863. {
  864. return Add(d, One);
  865. }
  866. public static decimal operator --(decimal d)
  867. {
  868. return Subtract(d, One);
  869. }
  870. public static decimal operator +(decimal d1, decimal d2)
  871. {
  872. DecCalc.DecAddSub(ref AsMutable(ref d1), ref AsMutable(ref d2), false);
  873. return d1;
  874. }
  875. public static decimal operator -(decimal d1, decimal d2)
  876. {
  877. DecCalc.DecAddSub(ref AsMutable(ref d1), ref AsMutable(ref d2), true);
  878. return d1;
  879. }
  880. public static decimal operator *(decimal d1, decimal d2)
  881. {
  882. DecCalc.VarDecMul(ref AsMutable(ref d1), ref AsMutable(ref d2));
  883. return d1;
  884. }
  885. public static decimal operator /(decimal d1, decimal d2)
  886. {
  887. DecCalc.VarDecDiv(ref AsMutable(ref d1), ref AsMutable(ref d2));
  888. return d1;
  889. }
  890. public static decimal operator %(decimal d1, decimal d2)
  891. {
  892. DecCalc.VarDecMod(ref AsMutable(ref d1), ref AsMutable(ref d2));
  893. return d1;
  894. }
  895. public static bool operator ==(decimal d1, decimal d2)
  896. {
  897. return DecCalc.VarDecCmp(in d1, in d2) == 0;
  898. }
  899. public static bool operator !=(decimal d1, decimal d2)
  900. {
  901. return DecCalc.VarDecCmp(in d1, in d2) != 0;
  902. }
  903. public static bool operator <(decimal d1, decimal d2)
  904. {
  905. return DecCalc.VarDecCmp(in d1, in d2) < 0;
  906. }
  907. public static bool operator <=(decimal d1, decimal d2)
  908. {
  909. return DecCalc.VarDecCmp(in d1, in d2) <= 0;
  910. }
  911. public static bool operator >(decimal d1, decimal d2)
  912. {
  913. return DecCalc.VarDecCmp(in d1, in d2) > 0;
  914. }
  915. public static bool operator >=(decimal d1, decimal d2)
  916. {
  917. return DecCalc.VarDecCmp(in d1, in d2) >= 0;
  918. }
  919. //
  920. // IConvertible implementation
  921. //
  922. public TypeCode GetTypeCode()
  923. {
  924. return TypeCode.Decimal;
  925. }
  926. bool IConvertible.ToBoolean(IFormatProvider provider)
  927. {
  928. return Convert.ToBoolean(this);
  929. }
  930. char IConvertible.ToChar(IFormatProvider provider)
  931. {
  932. throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Decimal", "Char"));
  933. }
  934. sbyte IConvertible.ToSByte(IFormatProvider provider)
  935. {
  936. return Convert.ToSByte(this);
  937. }
  938. byte IConvertible.ToByte(IFormatProvider provider)
  939. {
  940. return Convert.ToByte(this);
  941. }
  942. short IConvertible.ToInt16(IFormatProvider provider)
  943. {
  944. return Convert.ToInt16(this);
  945. }
  946. ushort IConvertible.ToUInt16(IFormatProvider provider)
  947. {
  948. return Convert.ToUInt16(this);
  949. }
  950. int IConvertible.ToInt32(IFormatProvider provider)
  951. {
  952. return Convert.ToInt32(this);
  953. }
  954. uint IConvertible.ToUInt32(IFormatProvider provider)
  955. {
  956. return Convert.ToUInt32(this);
  957. }
  958. long IConvertible.ToInt64(IFormatProvider provider)
  959. {
  960. return Convert.ToInt64(this);
  961. }
  962. ulong IConvertible.ToUInt64(IFormatProvider provider)
  963. {
  964. return Convert.ToUInt64(this);
  965. }
  966. float IConvertible.ToSingle(IFormatProvider provider)
  967. {
  968. return Convert.ToSingle(this);
  969. }
  970. double IConvertible.ToDouble(IFormatProvider provider)
  971. {
  972. return Convert.ToDouble(this);
  973. }
  974. decimal IConvertible.ToDecimal(IFormatProvider provider)
  975. {
  976. return this;
  977. }
  978. DateTime IConvertible.ToDateTime(IFormatProvider provider)
  979. {
  980. throw new InvalidCastException(SR.Format(SR.InvalidCast_FromTo, "Decimal", "DateTime"));
  981. }
  982. object IConvertible.ToType(Type type, IFormatProvider provider)
  983. {
  984. return Convert.DefaultToType((IConvertible)this, type, provider);
  985. }
  986. }
  987. }