PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/mono-2.10.8/mcs/class/corlib/System/Decimal.cs

#
C# | 1457 lines | 1137 code | 210 blank | 110 comment | 286 complexity | e2a55220ba99fbf086d4f892e24074e8 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, LGPL-2.1, LGPL-2.0
  1. //
  2. // System.Decimal.cs
  3. //
  4. // Represents a floating-point decimal data type with up to 29
  5. // significant digits, suitable for financial and commercial calculations.
  6. //
  7. // Author:
  8. // Martin Weindel (martin.weindel@t-online.de)
  9. //
  10. // (C) 2001 Martin Weindel
  11. //
  12. //
  13. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System;
  35. using System.Globalization;
  36. using System.Text;
  37. using System.Runtime.CompilerServices;
  38. using System.Runtime.ConstrainedExecution;
  39. using System.Runtime.Serialization;
  40. #if MSTEST
  41. using System.Runtime.InteropServices;
  42. #endif
  43. namespace System
  44. {
  45. /// <summary>
  46. /// Represents a floating-point decimal data type with up to 29 significant
  47. /// digits, suitable for financial and commercial calculations
  48. /// </summary>
  49. [Serializable]
  50. [System.Runtime.InteropServices.ComVisible (true)]
  51. public struct Decimal: IFormattable, IConvertible, IComparable, IComparable<Decimal>, IEquatable <Decimal>
  52. #if NET_4_0
  53. , IDeserializationCallback
  54. #endif
  55. {
  56. public const decimal MinValue = -79228162514264337593543950335m;
  57. public const decimal MaxValue = 79228162514264337593543950335m;
  58. public const decimal MinusOne = -1;
  59. public const decimal One = 1;
  60. public const decimal Zero = 0;
  61. private static readonly Decimal MaxValueDiv10 = MaxValue / 10;
  62. // some constants
  63. private const uint MAX_SCALE = 28;
  64. private const uint SIGN_FLAG = 0x80000000;
  65. private const int SCALE_SHIFT = 16;
  66. private const uint RESERVED_SS32_BITS = 0x7F00FFFF;
  67. // internal representation of decimal
  68. private uint flags;
  69. private uint hi;
  70. private uint lo;
  71. private uint mid;
  72. public Decimal (int lo, int mid, int hi, bool isNegative, byte scale)
  73. {
  74. unchecked
  75. {
  76. this.lo = (uint) lo;
  77. this.mid = (uint) mid;
  78. this.hi = (uint) hi;
  79. if (scale > MAX_SCALE)
  80. throw new ArgumentOutOfRangeException (Locale.GetText ("scale must be between 0 and 28"));
  81. flags = scale;
  82. flags <<= SCALE_SHIFT;
  83. if (isNegative) flags |= SIGN_FLAG;
  84. }
  85. }
  86. public Decimal (int value)
  87. {
  88. unchecked
  89. {
  90. hi = mid = 0;
  91. if (value < 0)
  92. {
  93. flags = SIGN_FLAG;
  94. lo = ((uint)~value) + 1;
  95. }
  96. else
  97. {
  98. flags = 0;
  99. lo = (uint) value;
  100. }
  101. }
  102. }
  103. [CLSCompliant(false)]
  104. public Decimal (uint value)
  105. {
  106. lo = value;
  107. flags = hi = mid = 0;
  108. }
  109. public Decimal (long value)
  110. {
  111. unchecked
  112. {
  113. hi = 0;
  114. if (value < 0)
  115. {
  116. flags = SIGN_FLAG;
  117. ulong u = ((ulong)~value) + 1;
  118. lo = (uint)u;
  119. mid = (uint)(u >> 32);
  120. }
  121. else
  122. {
  123. flags = 0;
  124. ulong u = (ulong)value;
  125. lo = (uint)u;
  126. mid = (uint)(u >> 32);
  127. }
  128. }
  129. }
  130. [CLSCompliant(false)]
  131. public Decimal (ulong value)
  132. {
  133. unchecked
  134. {
  135. flags = hi = 0;
  136. lo = (uint)value;
  137. mid = (uint)(value >> 32);
  138. }
  139. }
  140. public Decimal (float value)
  141. {
  142. #if false
  143. //
  144. // We cant use the double2decimal method
  145. // because it incorrectly turns the floating point
  146. // value 1.23456789E-25F which should be:
  147. // 0.0000000000000000000000001235
  148. // into the incorrect:
  149. // 0.0000000000000000000000001234
  150. //
  151. // The code currently parses the double value 0.6 as
  152. // 0.600000000000000
  153. //
  154. // And we have a patch for that called (trim
  155. if (double2decimal (out this, value, 7) != 0)
  156. throw new OverflowException ();
  157. #else
  158. if (value > (float)Decimal.MaxValue || value < (float)Decimal.MinValue ||
  159. float.IsNaN (value) || float.IsNegativeInfinity (value) || float.IsPositiveInfinity (value)) {
  160. throw new OverflowException (Locale.GetText (
  161. "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
  162. }
  163. // we must respect the precision (double2decimal doesn't)
  164. Decimal d = Decimal.Parse (value.ToString (CultureInfo.InvariantCulture),
  165. NumberStyles.Float, CultureInfo.InvariantCulture);
  166. flags = d.flags;
  167. hi = d.hi;
  168. lo = d.lo;
  169. mid = d.mid;
  170. #endif
  171. }
  172. public Decimal (double value)
  173. {
  174. #if false
  175. //
  176. // We cant use the double2decimal method
  177. // because it incorrectly turns the floating point
  178. // value 1.23456789E-25F which should be:
  179. // 0.0000000000000000000000001235
  180. // into the incorrect:
  181. // 0.0000000000000000000000001234
  182. //
  183. // The code currently parses the double value 0.6 as
  184. // 0.600000000000000
  185. //
  186. // And we have a patch for that called (trim
  187. if (double2decimal (out this, value, 15) != 0)
  188. throw new OverflowException ();
  189. #else
  190. if (value > (double)Decimal.MaxValue || value < (double)Decimal.MinValue ||
  191. double.IsNaN (value) || double.IsNegativeInfinity (value) || double.IsPositiveInfinity (value)) {
  192. throw new OverflowException (Locale.GetText (
  193. "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
  194. }
  195. // we must respect the precision (double2decimal doesn't)
  196. Decimal d = Decimal.Parse (value.ToString (CultureInfo.InvariantCulture),
  197. NumberStyles.Float, CultureInfo.InvariantCulture);
  198. flags = d.flags;
  199. hi = d.hi;
  200. lo = d.lo;
  201. mid = d.mid;
  202. #endif
  203. }
  204. public Decimal (int[] bits)
  205. {
  206. if (bits == null)
  207. {
  208. throw new ArgumentNullException (Locale.GetText ("Bits is a null reference"));
  209. }
  210. if (bits.GetLength(0) != 4)
  211. {
  212. throw new ArgumentException (Locale.GetText ("bits does not contain four values"));
  213. }
  214. unchecked {
  215. lo = (uint) bits[0];
  216. mid = (uint) bits[1];
  217. hi = (uint) bits[2];
  218. flags = (uint) bits[3];
  219. byte scale = (byte)(flags >> SCALE_SHIFT);
  220. if (scale > MAX_SCALE || (flags & RESERVED_SS32_BITS) != 0)
  221. {
  222. throw new ArgumentException (Locale.GetText ("Invalid bits[3]"));
  223. }
  224. }
  225. }
  226. public static decimal FromOACurrency (long cy)
  227. {
  228. return (decimal)cy / (decimal)10000;
  229. }
  230. public static int[] GetBits (Decimal d)
  231. {
  232. unchecked
  233. {
  234. return new int[] { (int)d.lo, (int)d.mid, (int)d.hi, (int)d.flags };
  235. }
  236. }
  237. public static Decimal Negate (Decimal d)
  238. {
  239. d.flags ^= SIGN_FLAG;
  240. return d;
  241. }
  242. public static Decimal Add (Decimal d1, Decimal d2)
  243. {
  244. if (decimalIncr (ref d1, ref d2) == 0)
  245. return d1;
  246. else
  247. throw new OverflowException (Locale.GetText ("Overflow on adding decimal number"));
  248. }
  249. public static Decimal Subtract (Decimal d1, Decimal d2)
  250. {
  251. d2.flags ^= SIGN_FLAG;
  252. int result = decimalIncr (ref d1, ref d2);
  253. if (result == 0)
  254. return d1;
  255. else
  256. throw new OverflowException (Locale.GetText ("Overflow on subtracting decimal numbers ("+result+")"));
  257. }
  258. public override int GetHashCode ()
  259. {
  260. return (int) (flags ^ hi ^ lo ^ mid);
  261. }
  262. public static Decimal operator + (Decimal d1, Decimal d2)
  263. {
  264. return Add (d1, d2);
  265. }
  266. public static Decimal operator -- (Decimal d)
  267. {
  268. return Add(d, MinusOne);
  269. }
  270. public static Decimal operator ++ (Decimal d)
  271. {
  272. return Add (d, One);
  273. }
  274. public static Decimal operator - (Decimal d1, Decimal d2)
  275. {
  276. return Subtract (d1, d2);
  277. }
  278. public static Decimal operator - (Decimal d)
  279. {
  280. return Negate (d);
  281. }
  282. public static Decimal operator + (Decimal d)
  283. {
  284. return d;
  285. }
  286. public static Decimal operator * (Decimal d1, Decimal d2)
  287. {
  288. return Multiply (d1, d2);
  289. }
  290. public static Decimal operator / (Decimal d1, Decimal d2)
  291. {
  292. return Divide (d1, d2);
  293. }
  294. public static Decimal operator % (Decimal d1, Decimal d2)
  295. {
  296. return Remainder (d1, d2);
  297. }
  298. private static ulong u64 (Decimal value)
  299. {
  300. ulong result;
  301. decimalFloorAndTrunc (ref value, 0);
  302. if (decimal2UInt64 (ref value, out result) != 0) {
  303. throw new System.OverflowException ();
  304. }
  305. return result;
  306. }
  307. private static long s64 (Decimal value)
  308. {
  309. long result;
  310. decimalFloorAndTrunc (ref value, 0);
  311. if (decimal2Int64 (ref value, out result) != 0) {
  312. throw new System.OverflowException ();
  313. }
  314. return result;
  315. }
  316. public static explicit operator byte (Decimal value)
  317. {
  318. ulong result = u64 (value);
  319. return checked ((byte) result);
  320. }
  321. [CLSCompliant (false)]
  322. public static explicit operator sbyte (Decimal value)
  323. {
  324. long result = s64 (value);
  325. return checked ((sbyte) result);
  326. }
  327. public static explicit operator char (Decimal value)
  328. {
  329. ulong result = u64 (value);
  330. return checked ((char) result);
  331. }
  332. public static explicit operator short (Decimal value)
  333. {
  334. long result = s64 (value);
  335. return checked ((short) result);
  336. }
  337. [CLSCompliant (false)]
  338. public static explicit operator ushort (Decimal value)
  339. {
  340. ulong result = u64 (value);
  341. return checked ((ushort) result);
  342. }
  343. public static explicit operator int (Decimal value)
  344. {
  345. long result = s64 (value);
  346. return checked ((int) result);
  347. }
  348. [CLSCompliant(false)]
  349. public static explicit operator uint (Decimal value)
  350. {
  351. ulong result = u64 (value);
  352. return checked ((uint) result);
  353. }
  354. public static explicit operator long (Decimal value)
  355. {
  356. return s64 (value);
  357. }
  358. [CLSCompliant(false)]
  359. public static explicit operator ulong (Decimal value)
  360. {
  361. return u64 (value);
  362. }
  363. public static implicit operator Decimal (byte value)
  364. {
  365. return new Decimal (value);
  366. }
  367. [CLSCompliant(false)]
  368. public static implicit operator Decimal (sbyte value)
  369. {
  370. return new Decimal (value);
  371. }
  372. public static implicit operator Decimal (short value)
  373. {
  374. return new Decimal (value);
  375. }
  376. [CLSCompliant(false)]
  377. public static implicit operator Decimal (ushort value)
  378. {
  379. return new Decimal (value);
  380. }
  381. public static implicit operator Decimal (char value)
  382. {
  383. return new Decimal (value);
  384. }
  385. public static implicit operator Decimal (int value)
  386. {
  387. return new Decimal (value);
  388. }
  389. [CLSCompliant(false)]
  390. public static implicit operator Decimal (uint value)
  391. {
  392. return new Decimal (value);
  393. }
  394. public static implicit operator Decimal (long value)
  395. {
  396. return new Decimal (value);
  397. }
  398. [CLSCompliant(false)]
  399. public static implicit operator Decimal (ulong value)
  400. {
  401. return new Decimal (value);
  402. }
  403. public static explicit operator Decimal (float value)
  404. {
  405. return new Decimal (value);
  406. }
  407. public static explicit operator Decimal (double value)
  408. {
  409. return new Decimal (value);
  410. }
  411. public static explicit operator float (Decimal value)
  412. {
  413. return (float) (double) value;
  414. }
  415. public static explicit operator double (Decimal value)
  416. {
  417. return decimal2double (ref value);
  418. }
  419. public static bool operator != (Decimal d1, Decimal d2)
  420. {
  421. return !Equals (d1, d2);
  422. }
  423. public static bool operator == (Decimal d1, Decimal d2)
  424. {
  425. return Equals (d1, d2);
  426. }
  427. public static bool operator > (Decimal d1, Decimal d2)
  428. {
  429. return Compare (d1, d2) > 0;
  430. }
  431. public static bool operator >= (Decimal d1, Decimal d2)
  432. {
  433. return Compare (d1, d2) >= 0;
  434. }
  435. public static bool operator < (Decimal d1, Decimal d2)
  436. {
  437. return Compare (d1, d2) < 0;
  438. }
  439. public static bool operator <= (Decimal d1, Decimal d2)
  440. {
  441. return Compare (d1, d2) <= 0;
  442. }
  443. public static bool Equals (Decimal d1, Decimal d2)
  444. {
  445. return Compare (d1, d2) == 0;
  446. }
  447. public override bool Equals (object value)
  448. {
  449. if (!(value is Decimal))
  450. return false;
  451. return Equals ((Decimal) value, this);
  452. }
  453. // avoid unmanaged call
  454. private bool IsZero ()
  455. {
  456. return ((hi == 0) && (lo == 0) && (mid == 0));
  457. }
  458. // avoid unmanaged call
  459. private bool IsNegative ()
  460. {
  461. return ((flags & 0x80000000) == 0x80000000);
  462. }
  463. public static Decimal Floor (Decimal d)
  464. {
  465. decimalFloorAndTrunc (ref d, 1);
  466. return d;
  467. }
  468. public static Decimal Truncate (Decimal d)
  469. {
  470. decimalFloorAndTrunc (ref d, 0);
  471. return d;
  472. }
  473. public static Decimal Round (Decimal d, int decimals)
  474. {
  475. return Round (d, decimals, MidpointRounding.ToEven);
  476. }
  477. public static Decimal Round (Decimal d, int decimals, MidpointRounding mode)
  478. {
  479. if ((mode != MidpointRounding.ToEven) && (mode != MidpointRounding.AwayFromZero))
  480. throw new ArgumentException ("The value '" + mode + "' is not valid for this usage of the type MidpointRounding.", "mode");
  481. if (decimals < 0 || decimals > 28) {
  482. throw new ArgumentOutOfRangeException ("decimals", "[0,28]");
  483. }
  484. bool negative = d.IsNegative ();
  485. if (negative)
  486. d.flags ^= SIGN_FLAG;
  487. // Moved from Math.cs because it's easier to fix the "sign"
  488. // issue here :( as the logic is OK only for positive numbers
  489. decimal p = (decimal) Math.Pow (10, decimals);
  490. decimal int_part = Decimal.Floor (d);
  491. decimal dec_part = d - int_part;
  492. dec_part *= 10000000000000000000000000000M;
  493. dec_part = Decimal.Floor(dec_part);
  494. dec_part /= (10000000000000000000000000000M / p);
  495. dec_part = Math.Round (dec_part, mode);
  496. dec_part /= p;
  497. decimal result = int_part + dec_part;
  498. // that fixes the precision/scale (which we must keep for output)
  499. // (moved and adapted from System.Data.SqlTypes.SqlMoney)
  500. long scaleDiff = decimals - ((result.flags & 0x7FFF0000) >> 16);
  501. // integrify
  502. if (scaleDiff > 0) {
  503. // note: here we always work with positive numbers
  504. while (scaleDiff > 0) {
  505. if (result > MaxValueDiv10)
  506. break;
  507. result *= 10;
  508. scaleDiff--;
  509. }
  510. }
  511. else if (scaleDiff < 0) {
  512. while (scaleDiff < 0) {
  513. result /= 10;
  514. scaleDiff++;
  515. }
  516. }
  517. result.flags = (uint)((decimals - scaleDiff) << SCALE_SHIFT);
  518. if (negative)
  519. result.flags ^= SIGN_FLAG;
  520. return result;
  521. }
  522. public static Decimal Round (Decimal d)
  523. {
  524. return Math.Round (d);
  525. }
  526. public static Decimal Round (Decimal d, MidpointRounding mode)
  527. {
  528. return Math.Round (d, mode);
  529. }
  530. public static Decimal Multiply (Decimal d1, Decimal d2)
  531. {
  532. if (d1.IsZero () || d2.IsZero ())
  533. return Decimal.Zero;
  534. if (decimalMult (ref d1, ref d2) != 0)
  535. throw new OverflowException ();
  536. return d1;
  537. }
  538. public static Decimal Divide (Decimal d1, Decimal d2)
  539. {
  540. if (d2.IsZero ())
  541. throw new DivideByZeroException ();
  542. if (d1.IsZero ())
  543. return Decimal.Zero;
  544. d1.flags ^= SIGN_FLAG;
  545. d1.flags ^= SIGN_FLAG;
  546. Decimal result;
  547. if (decimalDiv (out result, ref d1, ref d2) != 0)
  548. throw new OverflowException ();
  549. return result;
  550. }
  551. public static Decimal Remainder (Decimal d1, Decimal d2)
  552. {
  553. if (d2.IsZero ())
  554. throw new DivideByZeroException ();
  555. if (d1.IsZero ())
  556. return Decimal.Zero;
  557. bool negative = d1.IsNegative ();
  558. if (negative)
  559. d1.flags ^= SIGN_FLAG;
  560. if (d2.IsNegative ())
  561. d2.flags ^= SIGN_FLAG;
  562. Decimal result;
  563. if (d1 == d2) {
  564. return Decimal.Zero;
  565. }
  566. else if (d2 > d1) {
  567. result = d1;
  568. }
  569. else {
  570. if (decimalDiv (out result, ref d1, ref d2) != 0)
  571. throw new OverflowException ();
  572. result = Decimal.Truncate (result);
  573. // FIXME: not really performant here
  574. result = d1 - result * d2;
  575. }
  576. if (negative)
  577. result.flags ^= SIGN_FLAG;
  578. return result;
  579. }
  580. [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
  581. public static int Compare (Decimal d1, Decimal d2)
  582. {
  583. return decimalCompare (ref d1, ref d2);
  584. }
  585. public int CompareTo (object value)
  586. {
  587. if (value == null)
  588. return 1;
  589. if (!(value is Decimal))
  590. throw new ArgumentException (Locale.GetText ("Value is not a System.Decimal"));
  591. return Compare (this, (Decimal)value);
  592. }
  593. public int CompareTo (Decimal value)
  594. {
  595. return Compare (this, value);
  596. }
  597. public bool Equals (Decimal value)
  598. {
  599. return Equals (value, this);
  600. }
  601. public static Decimal Ceiling (Decimal d)
  602. {
  603. return Math.Ceiling (d);
  604. }
  605. public static Decimal Parse (string s)
  606. {
  607. return Parse (s, NumberStyles.Number, null);
  608. }
  609. public static Decimal Parse (string s, NumberStyles style)
  610. {
  611. return Parse (s, style, null);
  612. }
  613. public static Decimal Parse (string s, IFormatProvider provider)
  614. {
  615. return Parse (s, NumberStyles.Number, provider);
  616. }
  617. static void ThrowAtPos (int pos)
  618. {
  619. throw new FormatException (String.Format (Locale.GetText ("Invalid character at position {0}"), pos));
  620. }
  621. static void ThrowInvalidExp ()
  622. {
  623. throw new FormatException (Locale.GetText ("Invalid exponent"));
  624. }
  625. private static string stripStyles (string s, NumberStyles style, NumberFormatInfo nfi,
  626. out int decPos, out bool isNegative, out bool expFlag, out int exp, bool throwex)
  627. {
  628. isNegative = false;
  629. expFlag = false;
  630. exp = 0;
  631. decPos = -1;
  632. bool hasSign = false;
  633. bool hasOpeningParentheses = false;
  634. bool hasDecimalPoint = false;
  635. bool allowedLeadingWhiteSpace = ((style & NumberStyles.AllowLeadingWhite) != 0);
  636. bool allowedTrailingWhiteSpace = ((style & NumberStyles.AllowTrailingWhite) != 0);
  637. bool allowedLeadingSign = ((style & NumberStyles.AllowLeadingSign) != 0);
  638. bool allowedTrailingSign = ((style & NumberStyles.AllowTrailingSign) != 0);
  639. bool allowedParentheses = ((style & NumberStyles.AllowParentheses) != 0);
  640. bool allowedThousands = ((style & NumberStyles.AllowThousands) != 0);
  641. bool allowedDecimalPoint = ((style & NumberStyles.AllowDecimalPoint) != 0);
  642. bool allowedExponent = ((style & NumberStyles.AllowExponent) != 0);
  643. /* get rid of currency symbol */
  644. bool hasCurrency = false;
  645. if ((style & NumberStyles.AllowCurrencySymbol) != 0)
  646. {
  647. int index = s.IndexOf (nfi.CurrencySymbol);
  648. if (index >= 0)
  649. {
  650. s = s.Remove (index, nfi.CurrencySymbol.Length);
  651. hasCurrency = true;
  652. }
  653. }
  654. string decimalSep = (hasCurrency) ? nfi.CurrencyDecimalSeparator : nfi.NumberDecimalSeparator;
  655. string groupSep = (hasCurrency) ? nfi.CurrencyGroupSeparator : nfi.NumberGroupSeparator;
  656. int pos = 0;
  657. int len = s.Length;
  658. StringBuilder sb = new StringBuilder (len);
  659. // leading
  660. while (pos < len)
  661. {
  662. char ch = s[pos];
  663. if (Char.IsDigit (ch))
  664. {
  665. break; // end of leading
  666. }
  667. else if (allowedLeadingWhiteSpace && Char.IsWhiteSpace (ch))
  668. {
  669. pos++;
  670. }
  671. else if (allowedParentheses && ch == '(' && !hasSign && !hasOpeningParentheses)
  672. {
  673. hasOpeningParentheses = true;
  674. hasSign = true;
  675. isNegative = true;
  676. pos++;
  677. }
  678. else if (allowedLeadingSign && ch == nfi.NegativeSign[0] && !hasSign)
  679. {
  680. int slen = nfi.NegativeSign.Length;
  681. if (slen == 1 || s.IndexOf (nfi.NegativeSign, pos, slen) == pos)
  682. {
  683. hasSign = true;
  684. isNegative = true;
  685. pos += slen;
  686. }
  687. }
  688. else if (allowedLeadingSign && ch == nfi.PositiveSign[0] && !hasSign)
  689. {
  690. int slen = nfi.PositiveSign.Length;
  691. if (slen == 1 || s.IndexOf (nfi.PositiveSign, pos, slen) == pos)
  692. {
  693. hasSign = true;
  694. pos += slen;
  695. }
  696. }
  697. else if (allowedDecimalPoint && ch == decimalSep[0])
  698. {
  699. int slen = decimalSep.Length;
  700. if (slen != 1 && s.IndexOf (decimalSep, pos, slen) != pos)
  701. {
  702. if (throwex)
  703. ThrowAtPos (pos);
  704. else
  705. return null;
  706. }
  707. break;
  708. }
  709. else
  710. {
  711. if (throwex)
  712. ThrowAtPos (pos);
  713. else
  714. return null;
  715. }
  716. }
  717. if (pos == len) {
  718. if (throwex)
  719. throw new FormatException (Locale.GetText ("No digits found"));
  720. else
  721. return null;
  722. }
  723. // digits
  724. while (pos < len)
  725. {
  726. char ch = s[pos];
  727. if (Char.IsDigit (ch))
  728. {
  729. sb.Append(ch);
  730. pos++;
  731. }
  732. else if (allowedThousands && ch == groupSep[0] && ch != decimalSep [0])
  733. {
  734. int slen = groupSep.Length;
  735. if (slen != 1 && s.IndexOf(groupSep, pos, slen) != pos)
  736. {
  737. if (throwex)
  738. ThrowAtPos (pos);
  739. else
  740. return null;
  741. }
  742. pos += slen;
  743. }
  744. else if (allowedDecimalPoint && ch == decimalSep[0] && !hasDecimalPoint)
  745. {
  746. int slen = decimalSep.Length;
  747. if (slen == 1 || s.IndexOf(decimalSep, pos, slen) == pos)
  748. {
  749. decPos = sb.Length;
  750. hasDecimalPoint = true;
  751. pos += slen;
  752. }
  753. }
  754. else
  755. {
  756. break;
  757. }
  758. }
  759. // exponent
  760. if (pos < len)
  761. {
  762. char ch = s[pos];
  763. if (allowedExponent && Char.ToUpperInvariant (ch) == 'E')
  764. {
  765. expFlag = true;
  766. pos++;
  767. if (pos >= len){
  768. if (throwex)
  769. ThrowInvalidExp ();
  770. else
  771. return null;
  772. }
  773. ch = s[pos];
  774. bool isNegativeExp = false;
  775. if (ch == nfi.PositiveSign[0])
  776. {
  777. int slen = nfi.PositiveSign.Length;
  778. if (slen == 1 || s.IndexOf (nfi.PositiveSign, pos, slen) == pos)
  779. {
  780. pos += slen;
  781. if (pos >= len) {
  782. if (throwex)
  783. ThrowInvalidExp ();
  784. else
  785. return null;
  786. }
  787. }
  788. }
  789. else if (ch == nfi.NegativeSign[0])
  790. {
  791. int slen = nfi.NegativeSign.Length;
  792. if (slen == 1 || s.IndexOf (nfi.NegativeSign, pos, slen) == pos)
  793. {
  794. pos += slen;
  795. if (pos >= len) {
  796. if (throwex)
  797. ThrowInvalidExp ();
  798. else
  799. return null;
  800. }
  801. isNegativeExp = true;
  802. }
  803. }
  804. ch = s[pos];
  805. if (!Char.IsDigit(ch)) {
  806. if (throwex)
  807. ThrowInvalidExp ();
  808. else
  809. return null;
  810. }
  811. exp = ch - '0';
  812. pos++;
  813. while (pos < len && Char.IsDigit (s[pos]))
  814. {
  815. exp *= 10;
  816. exp += s[pos] - '0';
  817. pos++;
  818. }
  819. if (isNegativeExp) exp *= -1;
  820. }
  821. }
  822. // trailing
  823. while (pos < len)
  824. {
  825. char ch = s[pos];
  826. if (allowedTrailingWhiteSpace && Char.IsWhiteSpace (ch))
  827. {
  828. pos++;
  829. }
  830. else if (allowedParentheses && ch == ')' && hasOpeningParentheses)
  831. {
  832. hasOpeningParentheses = false;
  833. pos++;
  834. }
  835. else if (allowedTrailingSign && ch == nfi.NegativeSign[0] && !hasSign)
  836. {
  837. int slen = nfi.NegativeSign.Length;
  838. if (slen == 1 || s.IndexOf (nfi.NegativeSign, pos, slen) == pos)
  839. {
  840. hasSign = true;
  841. isNegative = true;
  842. pos += slen;
  843. }
  844. }
  845. else if (allowedTrailingSign && ch == nfi.PositiveSign[0] && !hasSign)
  846. {
  847. int slen = nfi.PositiveSign.Length;
  848. if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos)
  849. {
  850. hasSign = true;
  851. pos += slen;
  852. }
  853. }
  854. else
  855. {
  856. // trailing zero characters are allowed
  857. if (ch == 0){
  858. while (++pos < len && s [pos] == 0)
  859. ;
  860. if (pos == len)
  861. break;
  862. }
  863. if (throwex)
  864. ThrowAtPos (pos);
  865. else
  866. return null;
  867. }
  868. }
  869. if (hasOpeningParentheses) {
  870. if (throwex)
  871. throw new FormatException (Locale.GetText ("Closing Parentheses not found"));
  872. else
  873. return null;
  874. }
  875. if (!hasDecimalPoint)
  876. decPos = sb.Length;
  877. return sb.ToString ();
  878. }
  879. public static Decimal Parse (string s, NumberStyles style, IFormatProvider provider)
  880. {
  881. if (s == null)
  882. throw new ArgumentNullException ("s");
  883. if ((style & NumberStyles.AllowHexSpecifier) != 0)
  884. throw new ArgumentException ("Decimal.TryParse does not accept AllowHexSpecifier", "style");
  885. Decimal result;
  886. PerformParse (s, style, provider, out result, true);
  887. return result;
  888. }
  889. public static bool TryParse (string s, out Decimal result)
  890. {
  891. if (s == null){
  892. result = 0;
  893. return false;
  894. }
  895. return PerformParse (s, NumberStyles.Number, null, out result, false);
  896. }
  897. public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out decimal result)
  898. {
  899. if (s == null || (style & NumberStyles.AllowHexSpecifier) != 0){
  900. result = 0;
  901. return false;
  902. }
  903. return PerformParse (s, style, provider, out result, false);
  904. }
  905. static bool PerformParse (string s, NumberStyles style, IFormatProvider provider, out Decimal res, bool throwex)
  906. {
  907. NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
  908. int iDecPos, exp;
  909. bool isNegative, expFlag;
  910. s = stripStyles(s, style, nfi, out iDecPos, out isNegative, out expFlag, out exp, throwex);
  911. if (s == null){
  912. res = 0;
  913. return false;
  914. }
  915. if (iDecPos < 0){
  916. if (throwex)
  917. throw new Exception (Locale.GetText ("Error in System.Decimal.Parse"));
  918. res = 0;
  919. return false;
  920. }
  921. // first we remove leading 0
  922. int len = s.Length;
  923. int i = 0;
  924. while ((i < iDecPos) && (s [i] == '0'))
  925. i++;
  926. if ((i > 1) && (len > 1)) {
  927. s = s.Substring (i, len - i);
  928. iDecPos -= i;
  929. }
  930. // first 0. may not be here but is part of the maximum length
  931. int max = ((iDecPos == 0) ? 27 : 28);
  932. len = s.Length;
  933. if (len >= max + 1) {
  934. // number lower than MaxValue (base-less) can have better precision
  935. if (String.Compare (s, 0, "79228162514264337593543950335", 0, max + 1,
  936. false, CultureInfo.InvariantCulture) <= 0) {
  937. max++;
  938. }
  939. }
  940. // then we trunc the string
  941. if ((len > max) && (iDecPos < len)) {
  942. int round = (s [max] - '0');
  943. s = s.Substring (0, max);
  944. bool addone = false;
  945. if (round > 5) {
  946. addone = true;
  947. }
  948. else if (round == 5) {
  949. if (isNegative) {
  950. addone = true;
  951. }
  952. else {
  953. // banker rounding applies :(
  954. int previous = (s [max - 1] - '0');
  955. addone = ((previous & 0x01) == 0x01);
  956. }
  957. }
  958. if (addone) {
  959. char[] array = s.ToCharArray ();
  960. int p = max - 1;
  961. while (p >= 0) {
  962. int b = (array [p] - '0');
  963. if (array [p] != '9') {
  964. array [p] = (char)(b + '1');
  965. break;
  966. }
  967. else {
  968. array [p--] = '0';
  969. }
  970. }
  971. if ((p == -1) && (array [0] == '0')) {
  972. iDecPos++;
  973. s = "1".PadRight (iDecPos, '0');
  974. }
  975. else
  976. s = new String (array);
  977. }
  978. }
  979. Decimal result;
  980. // always work in positive (rounding issues)
  981. if (string2decimal (out result, s, (uint)iDecPos, 0) != 0){
  982. if (throwex)
  983. throw new OverflowException ();
  984. res = 0;
  985. return false;
  986. }
  987. if (expFlag) {
  988. if (decimalSetExponent (ref result, exp) != 0){
  989. if (throwex)
  990. throw new OverflowException ();
  991. res = 0;
  992. return false;
  993. }
  994. }
  995. if (isNegative)
  996. result.flags ^= SIGN_FLAG;
  997. res = result;
  998. return true;
  999. }
  1000. public TypeCode GetTypeCode ()
  1001. {
  1002. return TypeCode.Decimal;
  1003. }
  1004. public static byte ToByte (decimal value)
  1005. {
  1006. if (value > Byte.MaxValue || value < Byte.MinValue)
  1007. throw new OverflowException (Locale.GetText (
  1008. "Value is greater than Byte.MaxValue or less than Byte.MinValue"));
  1009. // return truncated value
  1010. return (byte)(Decimal.Truncate (value));
  1011. }
  1012. public static double ToDouble (decimal d)
  1013. {
  1014. return Convert.ToDouble (d);
  1015. }
  1016. public static short ToInt16 (decimal value)
  1017. {
  1018. if (value > Int16.MaxValue || value < Int16.MinValue)
  1019. throw new OverflowException (Locale.GetText (
  1020. "Value is greater than Int16.MaxValue or less than Int16.MinValue"));
  1021. // return truncated value
  1022. return (Int16)(Decimal.Truncate (value));
  1023. }
  1024. public static int ToInt32 (decimal d)
  1025. {
  1026. if (d > Int32.MaxValue || d < Int32.MinValue)
  1027. throw new OverflowException (Locale.GetText (
  1028. "Value is greater than Int32.MaxValue or less than Int32.MinValue"));
  1029. // return truncated value
  1030. return (Int32)(Decimal.Truncate (d));
  1031. }
  1032. public static long ToInt64 (decimal d)
  1033. {
  1034. if (d > Int64.MaxValue || d < Int64.MinValue)
  1035. throw new OverflowException (Locale.GetText (
  1036. "Value is greater than Int64.MaxValue or less than Int64.MinValue"));
  1037. // return truncated value
  1038. return (Int64)(Decimal.Truncate (d));
  1039. }
  1040. public static long ToOACurrency (decimal value)
  1041. {
  1042. return (long) (value * 10000);
  1043. }
  1044. [CLSCompliant(false)]
  1045. public static sbyte ToSByte (decimal value)
  1046. {
  1047. if (value > SByte.MaxValue || value < SByte.MinValue)
  1048. throw new OverflowException (Locale.GetText (
  1049. "Value is greater than SByte.MaxValue or less than SByte.MinValue"));
  1050. // return truncated value
  1051. return (SByte)(Decimal.Truncate (value));
  1052. }
  1053. public static float ToSingle (decimal d)
  1054. {
  1055. return Convert.ToSingle (d);
  1056. }
  1057. [CLSCompliant(false)]
  1058. public static ushort ToUInt16 (decimal value)
  1059. {
  1060. if (value > UInt16.MaxValue || value < UInt16.MinValue)
  1061. throw new OverflowException (Locale.GetText (
  1062. "Value is greater than UInt16.MaxValue or less than UInt16.MinValue"));
  1063. // return truncated value
  1064. return (UInt16)(Decimal.Truncate (value));
  1065. }
  1066. [CLSCompliant(false)]
  1067. public static uint ToUInt32 (decimal d)
  1068. {
  1069. if (d > UInt32.MaxValue || d < UInt32.MinValue)
  1070. throw new OverflowException (Locale.GetText (
  1071. "Value is greater than UInt32.MaxValue or less than UInt32.MinValue"));
  1072. // return truncated value
  1073. return (UInt32)(Decimal.Truncate (d));
  1074. }
  1075. [CLSCompliant(false)]
  1076. public static ulong ToUInt64 (decimal d)
  1077. {
  1078. if (d > UInt64.MaxValue || d < UInt64.MinValue)
  1079. throw new OverflowException (Locale.GetText (
  1080. "Value is greater than UInt64.MaxValue or less than UInt64.MinValue"));
  1081. // return truncated value
  1082. return (UInt64)(Decimal.Truncate (d));
  1083. }
  1084. object IConvertible.ToType (Type targetType, IFormatProvider provider)
  1085. {
  1086. if (targetType == null)
  1087. throw new ArgumentNullException ("targetType");
  1088. return Convert.ToType (this, targetType, provider, false);
  1089. }
  1090. bool IConvertible.ToBoolean (IFormatProvider provider)
  1091. {
  1092. return Convert.ToBoolean (this);
  1093. }
  1094. byte IConvertible.ToByte (IFormatProvider provider)
  1095. {
  1096. return Convert.ToByte (this);
  1097. }
  1098. char IConvertible.ToChar (IFormatProvider provider)
  1099. {
  1100. throw new InvalidCastException ();
  1101. }
  1102. DateTime IConvertible.ToDateTime (IFormatProvider provider)
  1103. {
  1104. throw new InvalidCastException ();
  1105. }
  1106. decimal IConvertible.ToDecimal (IFormatProvider provider)
  1107. {
  1108. return this;
  1109. }
  1110. double IConvertible.ToDouble (IFormatProvider provider)
  1111. {
  1112. return Convert.ToDouble (this);
  1113. }
  1114. short IConvertible.ToInt16 (IFormatProvider provider)
  1115. {
  1116. return Convert.ToInt16 (this);
  1117. }
  1118. int IConvertible.ToInt32 (IFormatProvider provider)
  1119. {
  1120. return Convert.ToInt32 (this);
  1121. }
  1122. long IConvertible.ToInt64 (IFormatProvider provider)
  1123. {
  1124. return Convert.ToInt64 (this);
  1125. }
  1126. sbyte IConvertible.ToSByte (IFormatProvider provider)
  1127. {
  1128. return Convert.ToSByte (this);
  1129. }
  1130. float IConvertible.ToSingle (IFormatProvider provider)
  1131. {
  1132. return Convert.ToSingle (this);
  1133. }
  1134. ushort IConvertible.ToUInt16 (IFormatProvider provider)
  1135. {
  1136. return Convert.ToUInt16 (this);
  1137. }
  1138. uint IConvertible.ToUInt32 (IFormatProvider provider)
  1139. {
  1140. return Convert.ToUInt32 (this);
  1141. }
  1142. ulong IConvertible.ToUInt64 (IFormatProvider provider)
  1143. {
  1144. return Convert.ToUInt64 (this);
  1145. }
  1146. public string ToString (string format, IFormatProvider provider)
  1147. {
  1148. return NumberFormatter.NumberToString (format, this, provider);
  1149. }
  1150. public override string ToString ()
  1151. {
  1152. return ToString ("G", null);
  1153. }
  1154. public string ToString (string format)
  1155. {
  1156. return ToString (format, null);
  1157. }
  1158. public string ToString (IFormatProvider provider)
  1159. {
  1160. return ToString ("G", provider);
  1161. }
  1162. #if NET_4_0
  1163. void IDeserializationCallback.OnDeserialization(object sender)
  1164. {
  1165. }
  1166. #endif
  1167. #if !MSTEST
  1168. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1169. private static extern int decimal2UInt64 (ref Decimal val, out ulong result);
  1170. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1171. private static extern int decimal2Int64 (ref Decimal val, out long result);
  1172. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1173. private static extern int double2decimal (out Decimal erg, double val, int digits);
  1174. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1175. private static extern int decimalIncr (ref Decimal d1, ref Decimal d2);
  1176. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1177. internal static extern int decimal2string (ref Decimal val,
  1178. int digits, int decimals, char[] bufDigits, int bufSize, out int decPos, out int sign);
  1179. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1180. internal static extern int string2decimal (out Decimal val, String sDigits, uint decPos, int sign);
  1181. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1182. internal static extern int decimalSetExponent (ref Decimal val, int exp);
  1183. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1184. private static extern double decimal2double (ref Decimal val);
  1185. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1186. private static extern void decimalFloorAndTrunc (ref Decimal val, int floorFlag);
  1187. // [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1188. // private static extern void decimalRound (ref Decimal val, int decimals);
  1189. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1190. private static extern int decimalMult (ref Decimal pd1, ref Decimal pd2);
  1191. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1192. private static extern int decimalDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
  1193. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1194. private static extern int decimalIntDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
  1195. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1196. private static extern int decimalCompare (ref Decimal d1, ref Decimal d2);
  1197. #else
  1198. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1199. [DllImport("libdec", EntryPoint="decimal2UInt64")]
  1200. private static extern int decimal2UInt64 (ref Decimal val, out ulong result);
  1201. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1202. [DllImport("libdec", EntryPoint="decimal2Int64")]
  1203. private static extern int decimal2Int64 (ref Decimal val, out long result);
  1204. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1205. [DllImport("libdec", EntryPoint="double2decimal")]
  1206. private static extern int double2decimal (out Decimal erg, double val, int digits);
  1207. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1208. [DllImport("libdec", EntryPoint="decimalIncr")]
  1209. private static extern int decimalIncr (ref Decimal d1, ref Decimal d2);
  1210. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1211. [DllImport("libdec", EntryPoint="decimal2string")]
  1212. internal static extern int decimal2string (ref Decimal val,
  1213. int digits, int decimals,
  1214. [MarshalAs(UnmanagedType.LPWStr)]StringBuilder bufDigits,
  1215. int bufSize, out int decPos, out int sign);
  1216. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1217. [DllImport("libdec", EntryPoint="string2decimal")]
  1218. internal static extern int string2decimal (out Decimal val,
  1219. [MarshalAs(UnmanagedType.LPWStr)]String sDigits,
  1220. uint decPos, int sign);
  1221. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1222. [DllImport("libdec", EntryPoint="decimalSetExponent")]
  1223. internal static extern int decimalSetExponent (ref Decimal val, int exp);
  1224. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1225. [DllImport("libdec", EntryPoint="decimal2double")]
  1226. private static extern double decimal2double (ref Decimal val);
  1227. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1228. [DllImport("libdec", EntryPoint="decimalFloorAndTrunc")]
  1229. private static extern void decimalFloorAndTrunc (ref Decimal val, int floorFlag);
  1230. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1231. [DllImport("libdec", EntryPoint="decimalRound")]
  1232. private static extern void decimalRound (ref Decimal val, int decimals);
  1233. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1234. [DllImport("libdec", EntryPoint="decimalMult")]
  1235. private static extern int decimalMult (ref Decimal pd1, ref Decimal pd2);
  1236. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1237. [DllImport("libdec", EntryPoint="decimalDiv")]
  1238. private static extern int decimalDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
  1239. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1240. [DllImport("libdec", EntryPoint="decimalIntDiv")]
  1241. private static extern int decimalIntDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
  1242. //![MethodImplAttribute(MethodImplOptions.InternalCall)]
  1243. [DllImport("libdec", EntryPoint="decimalCompare")]
  1244. private static extern int decimalCompare (ref Decimal d1, ref Decimal d2);
  1245. #endif
  1246. }
  1247. }