Decimal.cs 39 KB

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