Advertisement
Guest User

Untitled

a guest
Aug 5th, 2019
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.13 KB | None | 0 0
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. /*============================================================
  3. ** Class: BigRational
  4. **
  5. ** Purpose:
  6. ** --------
  7. ** This class is used to represent an arbitrary precision
  8. ** BigRational number
  9. **
  10. ** A rational number (commonly called a fraction) is a ratio
  11. ** between two integers. For example (3/6) = (2/4) = (1/2)
  12. **
  13. ** Arithmetic
  14. ** ----------
  15. ** a/b = c/d, iff ad = bc
  16. ** a/b + c/d == (ad + bc)/bd
  17. ** a/b - c/d == (ad - bc)/bd
  18. ** a/b % c/d == (ad % bc)/bd
  19. ** a/b * c/d == (ac)/(bd)
  20. ** a/b / c/d == (ad)/(bc)
  21. ** -(a/b) == (-a)/b
  22. ** (a/b)^(-1) == b/a, if a != 0
  23. **
  24. ** Reduction Algorithm
  25. ** ------------------------
  26. ** Euclid's algorithm is used to simplify the fraction.
  27. ** Calculating the greatest common divisor of two n-digit
  28. ** numbers can be found in
  29. **
  30. ** O(n(log n)^5 (log log n)) steps as n -> +infinity
  31. ============================================================*/
  32.  
  33. namespace Numerics
  34. {
  35. using System;
  36. using System.Collections.Generic;
  37. using System.Diagnostics;
  38. using System.Globalization;
  39. using System.Numerics;
  40. using System.Runtime.InteropServices;
  41. using System.Runtime.Serialization;
  42. using System.Security.Permissions;
  43. using System.Text;
  44.  
  45. [Serializable]
  46. [ComVisible(false)]
  47. public struct BigRational : IComparable, IComparable<BigRational>, IDeserializationCallback, IEquatable<BigRational>, ISerializable
  48. {
  49.  
  50. // ---- SECTION: members supporting exposed properties -------------*
  51. private BigInteger m_numerator;
  52. private BigInteger m_denominator;
  53.  
  54. private static readonly BigRational s_brZero = new BigRational(BigInteger.Zero);
  55. private static readonly BigRational s_brOne = new BigRational(BigInteger.One);
  56. private static readonly BigRational s_brMinusOne = new BigRational(BigInteger.MinusOne);
  57.  
  58. // ---- SECTION: members for internal support ---------*
  59. #region Members for Internal Support
  60. [StructLayout(LayoutKind.Explicit)]
  61. internal struct DoubleUlong
  62. {
  63. [FieldOffset(0)]
  64. public double dbl;
  65. [FieldOffset(0)]
  66. public ulong uu;
  67. }
  68. private const int DoubleMaxScale = 308;
  69. private static readonly BigInteger s_bnDoublePrecision = BigInteger.Pow(10, DoubleMaxScale);
  70. private static readonly BigInteger s_bnDoubleMaxValue = (BigInteger)Double.MaxValue;
  71. private static readonly BigInteger s_bnDoubleMinValue = (BigInteger)Double.MinValue;
  72.  
  73. [StructLayout(LayoutKind.Explicit)]
  74. internal struct DecimalUInt32
  75. {
  76. [FieldOffset(0)]
  77. public Decimal dec;
  78. [FieldOffset(0)]
  79. public int flags;
  80. }
  81. private const int DecimalScaleMask = 0x00FF0000;
  82. private const int DecimalSignMask = unchecked((int)0x80000000);
  83. private const int DecimalMaxScale = 28;
  84. private static readonly BigInteger s_bnDecimalPrecision = BigInteger.Pow(10, DecimalMaxScale);
  85. private static readonly BigInteger s_bnDecimalMaxValue = (BigInteger)Decimal.MaxValue;
  86. private static readonly BigInteger s_bnDecimalMinValue = (BigInteger)Decimal.MinValue;
  87.  
  88. private const String c_solidus = @"/";
  89. #endregion Members for Internal Support
  90.  
  91. // ---- SECTION: public properties --------------*
  92. #region Public Properties
  93. public static BigRational Zero
  94. {
  95. get
  96. {
  97. return s_brZero;
  98. }
  99. }
  100.  
  101. public static BigRational One
  102. {
  103. get
  104. {
  105. return s_brOne;
  106. }
  107. }
  108.  
  109. public static BigRational MinusOne
  110. {
  111. get
  112. {
  113. return s_brMinusOne;
  114. }
  115. }
  116.  
  117. public Int32 Sign
  118. {
  119. get
  120. {
  121. return m_numerator.Sign;
  122. }
  123. }
  124.  
  125. public BigInteger Numerator
  126. {
  127. get
  128. {
  129. return m_numerator;
  130. }
  131. }
  132.  
  133. public BigInteger Denominator
  134. {
  135. get
  136. {
  137. return m_denominator;
  138. }
  139. }
  140.  
  141. #endregion Public Properties
  142.  
  143. // ---- SECTION: public instance methods --------------*
  144. #region Public Instance Methods
  145.  
  146. // GetWholePart() and GetFractionPart()
  147. //
  148. // BigRational == Whole, Fraction
  149. // 0/2 == 0, 0/2
  150. // 1/2 == 0, 1/2
  151. // -1/2 == 0, -1/2
  152. // 1/1 == 1, 0/1
  153. // -1/1 == -1, 0/1
  154. // -3/2 == -1, -1/2
  155. // 3/2 == 1, 1/2
  156. public BigInteger GetWholePart()
  157. {
  158. return BigInteger.Divide(m_numerator, m_denominator);
  159. }
  160.  
  161. public BigRational GetFractionPart()
  162. {
  163. return new BigRational(BigInteger.Remainder(m_numerator, m_denominator), m_denominator);
  164. }
  165.  
  166. public override bool Equals(Object obj)
  167. {
  168. if (obj == null)
  169. return false;
  170.  
  171. if (!(obj is BigRational))
  172. return false;
  173. return this.Equals((BigRational)obj);
  174. }
  175.  
  176. public override int GetHashCode()
  177. {
  178. return (m_numerator / Denominator).GetHashCode();
  179. }
  180.  
  181. // IComparable
  182. int IComparable.CompareTo(Object obj)
  183. {
  184. if (obj == null)
  185. return 1;
  186. if (!(obj is BigRational))
  187. throw new ArgumentException("Argument must be of type BigRational", "obj");
  188. return Compare(this, (BigRational)obj);
  189. }
  190.  
  191. // IComparable<BigRational>
  192. public int CompareTo(BigRational other)
  193. {
  194. return Compare(this, other);
  195. }
  196.  
  197. // Object.ToString
  198. public override String ToString()
  199. {
  200. StringBuilder ret = new StringBuilder();
  201. ret.Append(m_numerator.ToString("R", CultureInfo.InvariantCulture));
  202. ret.Append(c_solidus);
  203. ret.Append(Denominator.ToString("R", CultureInfo.InvariantCulture));
  204. return ret.ToString();
  205. }
  206.  
  207. // IEquatable<BigRational>
  208. // a/b = c/d, iff ad = bc
  209. public Boolean Equals(BigRational other)
  210. {
  211. if (this.Denominator == other.Denominator)
  212. {
  213. return m_numerator == other.m_numerator;
  214. }
  215. else
  216. {
  217. return (m_numerator * other.Denominator) == (Denominator * other.m_numerator);
  218. }
  219. }
  220.  
  221. #endregion Public Instance Methods
  222.  
  223. // -------- SECTION: constructors -----------------*
  224. #region Constructors
  225.  
  226. public BigRational(BigInteger numerator)
  227. {
  228. m_numerator = numerator;
  229. m_denominator = BigInteger.One;
  230. }
  231.  
  232. // BigRational(Double)
  233. public BigRational(Double value)
  234. {
  235. if (Double.IsNaN(value))
  236. {
  237. throw new ArgumentException("Argument is not a number", "value");
  238. }
  239. else if (Double.IsInfinity(value))
  240. {
  241. throw new ArgumentException("Argument is infinity", "value");
  242. }
  243.  
  244. bool isFinite;
  245. int sign;
  246. int exponent;
  247. ulong significand;
  248. SplitDoubleIntoParts(value, out sign, out exponent, out significand, out isFinite);
  249.  
  250. if (significand == 0)
  251. {
  252. this = BigRational.Zero;
  253. return;
  254. }
  255.  
  256. m_numerator = significand;
  257. m_denominator = 1 << 52;
  258.  
  259. if (exponent > 0)
  260. {
  261. m_numerator = BigInteger.Pow(m_numerator, exponent);
  262. }
  263. else if (exponent < 0)
  264. {
  265. m_denominator = BigInteger.Pow(m_denominator, -exponent);
  266. }
  267. if (sign < 0)
  268. {
  269. m_numerator = BigInteger.Negate(m_numerator);
  270. }
  271. Simplify();
  272. }
  273.  
  274. // BigRational(Decimal) -
  275. //
  276. // The Decimal type represents floating point numbers exactly, with no rounding error.
  277. // Values such as "0.1" in Decimal are actually representable, and convert cleanly
  278. // to BigRational as "11/10"
  279. public BigRational(Decimal value)
  280. {
  281. int[] bits = Decimal.GetBits(value);
  282. if (bits == null || bits.Length != 4 || (bits[3] & ~(DecimalSignMask | DecimalScaleMask)) != 0 || (bits[3] & DecimalScaleMask) > (28 << 16))
  283. {
  284. throw new ArgumentException("invalid Decimal", "value");
  285. }
  286.  
  287. if (value == Decimal.Zero)
  288. {
  289. this = BigRational.Zero;
  290. return;
  291. }
  292.  
  293. // build up the numerator
  294. ulong ul = (((ulong)(uint)bits[2]) << 32) | ((ulong)(uint)bits[1]); // (hi << 32) | (mid)
  295. m_numerator = (new BigInteger(ul) << 32) | (uint)bits[0]; // (hiMid << 32) | (low)
  296.  
  297. bool isNegative = (bits[3] & DecimalSignMask) != 0;
  298. if (isNegative)
  299. {
  300. m_numerator = BigInteger.Negate(m_numerator);
  301. }
  302.  
  303. // build up the denominator
  304. int scale = (bits[3] & DecimalScaleMask) >> 16; // 0-28, power of 10 to divide numerator by
  305. m_denominator = BigInteger.Pow(10, scale);
  306.  
  307. Simplify();
  308. }
  309.  
  310. public BigRational(BigInteger numerator, BigInteger denominator)
  311. {
  312. if (denominator.Sign == 0)
  313. {
  314. throw new DivideByZeroException();
  315. }
  316. else if (numerator.Sign == 0)
  317. {
  318. // 0/m -> 0/1
  319. m_numerator = BigInteger.Zero;
  320. m_denominator = BigInteger.One;
  321. }
  322. else if (denominator.Sign < 0)
  323. {
  324. m_numerator = BigInteger.Negate(numerator);
  325. m_denominator = BigInteger.Negate(denominator);
  326. }
  327. else
  328. {
  329. m_numerator = numerator;
  330. m_denominator = denominator;
  331. }
  332. Simplify();
  333. }
  334.  
  335. public BigRational(BigInteger whole, BigInteger numerator, BigInteger denominator)
  336. {
  337. if (denominator.Sign == 0)
  338. {
  339. throw new DivideByZeroException();
  340. }
  341. else if (numerator.Sign == 0 && whole.Sign == 0)
  342. {
  343. m_numerator = BigInteger.Zero;
  344. m_denominator = BigInteger.One;
  345. }
  346. else if (denominator.Sign < 0)
  347. {
  348. m_denominator = BigInteger.Negate(denominator);
  349. m_numerator = (BigInteger.Negate(whole) * m_denominator) + BigInteger.Negate(numerator);
  350. }
  351. else
  352. {
  353. m_denominator = denominator;
  354. m_numerator = (whole * denominator) + numerator;
  355. }
  356. Simplify();
  357. }
  358. #endregion Constructors
  359.  
  360. // -------- SECTION: public static methods -----------------*
  361. #region Public Static Methods
  362.  
  363. public static BigRational Abs(BigRational r)
  364. {
  365. return (r.m_numerator.Sign < 0 ? new BigRational(BigInteger.Abs(r.m_numerator), r.Denominator) : r);
  366. }
  367.  
  368. public static BigRational Negate(BigRational r)
  369. {
  370. return new BigRational(BigInteger.Negate(r.m_numerator), r.Denominator);
  371. }
  372.  
  373. public static BigRational Invert(BigRational r)
  374. {
  375. return new BigRational(r.Denominator, r.m_numerator);
  376. }
  377.  
  378. public static BigRational Add(BigRational x, BigRational y)
  379. {
  380. return x + y;
  381. }
  382.  
  383. public static BigRational Subtract(BigRational x, BigRational y)
  384. {
  385. return x - y;
  386. }
  387.  
  388.  
  389. public static BigRational Multiply(BigRational x, BigRational y)
  390. {
  391. return x * y;
  392. }
  393.  
  394. public static BigRational Divide(BigRational dividend, BigRational divisor)
  395. {
  396. return dividend / divisor;
  397. }
  398.  
  399. public static BigRational Remainder(BigRational dividend, BigRational divisor)
  400. {
  401. return dividend % divisor;
  402. }
  403.  
  404. public static BigRational DivRem(BigRational dividend, BigRational divisor, out BigRational remainder)
  405. {
  406. // a/b / c/d == (ad)/(bc)
  407. // a/b % c/d == (ad % bc)/bd
  408.  
  409. // (ad) and (bc) need to be calculated for both the division and the remainder operations.
  410. BigInteger ad = dividend.m_numerator * divisor.Denominator;
  411. BigInteger bc = dividend.Denominator * divisor.m_numerator;
  412. BigInteger bd = dividend.Denominator * divisor.Denominator;
  413.  
  414. remainder = new BigRational(ad % bc, bd);
  415. return new BigRational(ad, bc);
  416. }
  417.  
  418.  
  419. public static BigRational Pow(BigRational baseValue, BigInteger exponent)
  420. {
  421. if (exponent.Sign == 0)
  422. {
  423. // 0^0 -> 1
  424. // n^0 -> 1
  425. return BigRational.One;
  426. }
  427. else if (exponent.Sign < 0)
  428. {
  429. if (baseValue == BigRational.Zero)
  430. {
  431. throw new ArgumentException("cannot raise zero to a negative power", "baseValue");
  432. }
  433. // n^(-e) -> (1/n)^e
  434. baseValue = BigRational.Invert(baseValue);
  435. exponent = BigInteger.Negate(exponent);
  436. }
  437.  
  438. BigRational result = baseValue;
  439. while (exponent > BigInteger.One)
  440. {
  441. result = result * baseValue;
  442. exponent--;
  443. }
  444.  
  445. return result;
  446. }
  447.  
  448. // Least Common Denominator (LCD)
  449. //
  450. // The LCD is the least common multiple of the two denominators. For instance, the LCD of
  451. // {1/2, 1/4} is 4 because the least common multiple of 2 and 4 is 4. Likewise, the LCD
  452. // of {1/2, 1/3} is 6.
  453. //
  454. // To find the LCD:
  455. //
  456. // 1) Find the Greatest Common Divisor (GCD) of the denominators
  457. // 2) Multiply the denominators together
  458. // 3) Divide the product of the denominators by the GCD
  459. public static BigInteger LeastCommonDenominator(BigRational x, BigRational y)
  460. {
  461. // LCD( a/b, c/d ) == (bd) / gcd(b,d)
  462. return (x.Denominator * y.Denominator) / BigInteger.GreatestCommonDivisor(x.Denominator, y.Denominator);
  463. }
  464.  
  465. public static int Compare(BigRational r1, BigRational r2)
  466. {
  467. // a/b = c/d, iff ad = bc
  468. return BigInteger.Compare(r1.m_numerator * r2.Denominator, r2.m_numerator * r1.Denominator);
  469. }
  470. #endregion Public Static Methods
  471.  
  472. #region Operator Overloads
  473. public static bool operator ==(BigRational x, BigRational y)
  474. {
  475. return Compare(x, y) == 0;
  476. }
  477.  
  478. public static bool operator !=(BigRational x, BigRational y)
  479. {
  480. return Compare(x, y) != 0;
  481. }
  482.  
  483. public static bool operator <(BigRational x, BigRational y)
  484. {
  485. return Compare(x, y) < 0;
  486. }
  487.  
  488. public static bool operator <=(BigRational x, BigRational y)
  489. {
  490. return Compare(x, y) <= 0;
  491. }
  492.  
  493. public static bool operator >(BigRational x, BigRational y)
  494. {
  495. return Compare(x, y) > 0;
  496. }
  497.  
  498. public static bool operator >=(BigRational x, BigRational y)
  499. {
  500. return Compare(x, y) >= 0;
  501. }
  502.  
  503. public static BigRational operator +(BigRational r)
  504. {
  505. return r;
  506. }
  507.  
  508. public static BigRational operator -(BigRational r)
  509. {
  510. return new BigRational(-r.m_numerator, r.Denominator);
  511. }
  512.  
  513. public static BigRational operator ++(BigRational r)
  514. {
  515. return r + BigRational.One;
  516. }
  517.  
  518. public static BigRational operator --(BigRational r)
  519. {
  520. return r - BigRational.One;
  521. }
  522.  
  523. public static BigRational operator +(BigRational r1, BigRational r2)
  524. {
  525. // a/b + c/d == (ad + bc)/bd
  526. return new BigRational((r1.m_numerator * r2.Denominator) + (r1.Denominator * r2.m_numerator), (r1.Denominator * r2.Denominator));
  527. }
  528.  
  529. public static BigRational operator -(BigRational r1, BigRational r2)
  530. {
  531. // a/b - c/d == (ad - bc)/bd
  532. return new BigRational((r1.m_numerator * r2.Denominator) - (r1.Denominator * r2.m_numerator), (r1.Denominator * r2.Denominator));
  533. }
  534.  
  535. public static BigRational operator *(BigRational r1, BigRational r2)
  536. {
  537. // a/b * c/d == (ac)/(bd)
  538. return new BigRational((r1.m_numerator * r2.m_numerator), (r1.Denominator * r2.Denominator));
  539. }
  540.  
  541. public static BigRational operator /(BigRational r1, BigRational r2)
  542. {
  543. // a/b / c/d == (ad)/(bc)
  544. return new BigRational((r1.m_numerator * r2.Denominator), (r1.Denominator * r2.m_numerator));
  545. }
  546.  
  547. public static BigRational operator %(BigRational r1, BigRational r2)
  548. {
  549. // a/b % c/d == (ad % bc)/bd
  550. return new BigRational((r1.m_numerator * r2.Denominator) % (r1.Denominator * r2.m_numerator), (r1.Denominator * r2.Denominator));
  551. }
  552. #endregion Operator Overloads
  553.  
  554. // ----- SECTION: explicit conversions from BigRational to numeric base types ----------------*
  555. #region explicit conversions from BigRational
  556. [CLSCompliant(false)]
  557. public static explicit operator SByte(BigRational value)
  558. {
  559. return (SByte)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  560. }
  561.  
  562. [CLSCompliant(false)]
  563. public static explicit operator UInt16(BigRational value)
  564. {
  565. return (UInt16)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  566. }
  567.  
  568. [CLSCompliant(false)]
  569. public static explicit operator UInt32(BigRational value)
  570. {
  571. return (UInt32)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  572. }
  573.  
  574. [CLSCompliant(false)]
  575. public static explicit operator UInt64(BigRational value)
  576. {
  577. return (UInt64)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  578. }
  579.  
  580. public static explicit operator Byte(BigRational value)
  581. {
  582. return (Byte)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  583. }
  584.  
  585. public static explicit operator Int16(BigRational value)
  586. {
  587. return (Int16)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  588. }
  589.  
  590. public static explicit operator Int32(BigRational value)
  591. {
  592. return (Int32)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  593. }
  594.  
  595. public static explicit operator Int64(BigRational value)
  596. {
  597. return (Int64)(BigInteger.Divide(value.m_numerator, value.m_denominator));
  598. }
  599.  
  600. public static explicit operator BigInteger(BigRational value)
  601. {
  602. return BigInteger.Divide(value.m_numerator, value.m_denominator);
  603. }
  604.  
  605. public static explicit operator Single(BigRational value)
  606. {
  607. // The Single value type represents a single-precision 32-bit number with
  608. // values ranging from negative 3.402823e38 to positive 3.402823e38
  609. // values that do not fit into this range are returned as Infinity
  610. return (Single)((Double)value);
  611. }
  612.  
  613. public static explicit operator Double(BigRational value)
  614. {
  615. // The Double value type represents a double-precision 64-bit number with
  616. // values ranging from -1.79769313486232e308 to +1.79769313486232e308
  617. // values that do not fit into this range are returned as +/-Infinity
  618. if (SafeCastToDouble(value.m_numerator) && SafeCastToDouble(value.m_denominator))
  619. {
  620. return (Double)value.m_numerator / (Double)value.m_denominator;
  621. }
  622.  
  623. // scale the numerator to preseve the fraction part through the integer division
  624. BigInteger denormalized = (value.m_numerator * s_bnDoublePrecision) / value.m_denominator;
  625. if (denormalized.IsZero)
  626. return (value.Sign < 0) ? BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000)) : 0d; // underflow to -+0
  627.  
  628. Double result = 0;
  629. bool isDouble = false;
  630. int scale = DoubleMaxScale;
  631.  
  632. while (scale > 0)
  633. {
  634. if (!isDouble)
  635. {
  636. if (SafeCastToDouble(denormalized))
  637. {
  638. result = (Double)denormalized;
  639. isDouble = true;
  640. }
  641. else
  642. {
  643. denormalized = denormalized / 10;
  644. }
  645. }
  646. result = result / 10;
  647. scale--;
  648. }
  649.  
  650. if (!isDouble)
  651. return (value.Sign < 0) ? Double.NegativeInfinity : Double.PositiveInfinity;
  652. else
  653. return result;
  654. }
  655.  
  656. public static explicit operator Decimal(BigRational value)
  657. {
  658. // The Decimal value type represents decimal numbers ranging
  659. // from +79,228,162,514,264,337,593,543,950,335 to -79,228,162,514,264,337,593,543,950,335
  660. // the binary representation of a Decimal value is of the form, ((-2^96 to 2^96) / 10^(0 to 28))
  661. if (SafeCastToDecimal(value.m_numerator) && SafeCastToDecimal(value.m_denominator))
  662. {
  663. return (Decimal)value.m_numerator / (Decimal)value.m_denominator;
  664. }
  665.  
  666. // scale the numerator to preseve the fraction part through the integer division
  667. BigInteger denormalized = (value.m_numerator * s_bnDecimalPrecision) / value.m_denominator;
  668. if (denormalized.IsZero)
  669. {
  670. return Decimal.Zero; // underflow - fraction is too small to fit in a decimal
  671. }
  672. for (int scale = DecimalMaxScale; scale >= 0; scale--)
  673. {
  674. if (!SafeCastToDecimal(denormalized))
  675. {
  676. denormalized = denormalized / 10;
  677. }
  678. else
  679. {
  680. DecimalUInt32 dec = new DecimalUInt32();
  681. dec.dec = (Decimal)denormalized;
  682. dec.flags = (dec.flags & ~DecimalScaleMask) | (scale << 16);
  683. return dec.dec;
  684. }
  685. }
  686. throw new OverflowException("Value was either too large or too small for a Decimal.");
  687. }
  688. #endregion explicit conversions from BigRational
  689.  
  690. // ----- SECTION: implicit conversions from numeric base types to BigRational ----------------*
  691. #region implicit conversions to BigRational
  692.  
  693. [CLSCompliant(false)]
  694. public static implicit operator BigRational(SByte value)
  695. {
  696. return new BigRational((BigInteger)value);
  697. }
  698.  
  699. [CLSCompliant(false)]
  700. public static implicit operator BigRational(UInt16 value)
  701. {
  702. return new BigRational((BigInteger)value);
  703. }
  704.  
  705. [CLSCompliant(false)]
  706. public static implicit operator BigRational(UInt32 value)
  707. {
  708. return new BigRational((BigInteger)value);
  709. }
  710.  
  711. [CLSCompliant(false)]
  712. public static implicit operator BigRational(UInt64 value)
  713. {
  714. return new BigRational((BigInteger)value);
  715. }
  716.  
  717. public static implicit operator BigRational(Byte value)
  718. {
  719. return new BigRational((BigInteger)value);
  720. }
  721.  
  722. public static implicit operator BigRational(Int16 value)
  723. {
  724. return new BigRational((BigInteger)value);
  725. }
  726.  
  727. public static implicit operator BigRational(Int32 value)
  728. {
  729. return new BigRational((BigInteger)value);
  730. }
  731.  
  732. public static implicit operator BigRational(Int64 value)
  733. {
  734. return new BigRational((BigInteger)value);
  735. }
  736.  
  737. public static implicit operator BigRational(BigInteger value)
  738. {
  739. return new BigRational(value);
  740. }
  741.  
  742. public static implicit operator BigRational(Single value)
  743. {
  744. return new BigRational((Double)value);
  745. }
  746.  
  747. public static implicit operator BigRational(Double value)
  748. {
  749. return new BigRational(value);
  750. }
  751.  
  752. public static implicit operator BigRational(Decimal value)
  753. {
  754. return new BigRational(value);
  755. }
  756.  
  757. #endregion implicit conversions to BigRational
  758.  
  759. // ----- SECTION: private serialization instance methods ----------------*
  760. #region serialization
  761. void IDeserializationCallback.OnDeserialization(Object sender)
  762. {
  763. try
  764. {
  765. // verify that the deserialized number is well formed
  766. if (m_denominator.Sign == 0 || m_numerator.Sign == 0)
  767. {
  768. // n/0 -> 0/1
  769. // 0/m -> 0/1
  770. m_numerator = BigInteger.Zero;
  771. m_denominator = BigInteger.One;
  772. }
  773. else if (m_denominator.Sign < 0)
  774. {
  775. m_numerator = BigInteger.Negate(m_numerator);
  776. m_denominator = BigInteger.Negate(m_denominator);
  777. }
  778. Simplify();
  779. }
  780. catch (ArgumentException e)
  781. {
  782. throw new SerializationException("invalid serialization data", e);
  783. }
  784. }
  785.  
  786. [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  787. void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
  788. {
  789. if (info == null)
  790. {
  791. throw new ArgumentNullException("info");
  792. }
  793.  
  794. info.AddValue("Numerator", m_numerator);
  795. info.AddValue("Denominator", m_denominator);
  796. }
  797.  
  798. BigRational(SerializationInfo info, StreamingContext context)
  799. {
  800. if (info == null)
  801. {
  802. throw new ArgumentNullException("info");
  803. }
  804.  
  805. m_numerator = (BigInteger)info.GetValue("Numerator", typeof(BigInteger));
  806. m_denominator = (BigInteger)info.GetValue("Denominator", typeof(BigInteger));
  807. }
  808. #endregion serialization
  809.  
  810. // ----- SECTION: private instance utility methods ----------------*
  811. #region instance helper methods
  812. private void Simplify()
  813. {
  814. // * if the numerator is {0, +1, -1} then the fraction is already reduced
  815. // * if the denominator is {+1} then the fraction is already reduced
  816. if (m_numerator == BigInteger.Zero)
  817. {
  818. m_denominator = BigInteger.One;
  819. }
  820.  
  821. BigInteger gcd = BigInteger.GreatestCommonDivisor(m_numerator, m_denominator);
  822. if (gcd > BigInteger.One)
  823. {
  824. m_numerator = m_numerator / gcd;
  825. m_denominator = Denominator / gcd;
  826. }
  827. }
  828. #endregion instance helper methods
  829.  
  830. // ----- SECTION: private static utility methods -----------------*
  831. #region static helper methods
  832. private static bool SafeCastToDouble(BigInteger value)
  833. {
  834. return s_bnDoubleMinValue <= value && value <= s_bnDoubleMaxValue;
  835. }
  836.  
  837. private static bool SafeCastToDecimal(BigInteger value)
  838. {
  839. return s_bnDecimalMinValue <= value && value <= s_bnDecimalMaxValue;
  840. }
  841.  
  842. private static void SplitDoubleIntoParts(double dbl, out int sign, out int exp, out ulong man, out bool isFinite)
  843. {
  844. DoubleUlong du;
  845. du.uu = 0;
  846. du.dbl = dbl;
  847.  
  848. sign = 1 - ((int)(du.uu >> 62) & 2);
  849. man = du.uu & 0x000FFFFFFFFFFFFF;
  850. exp = (int)(du.uu >> 52) & 0x7FF;
  851. if (exp == 0)
  852. {
  853. // Denormalized number.
  854. isFinite = true;
  855. if (man != 0)
  856. exp = -1074;
  857. }
  858. else if (exp == 0x7FF)
  859. {
  860. // NaN or Infinite.
  861. isFinite = false;
  862. exp = Int32.MaxValue;
  863. }
  864. else
  865. {
  866. isFinite = true;
  867. man |= 0x0010000000000000; // mask in the implied leading 53rd significand bit
  868. exp -= 1075;
  869. }
  870. }
  871.  
  872. private static double GetDoubleFromParts(int sign, int exp, ulong man)
  873. {
  874. DoubleUlong du;
  875. du.dbl = 0;
  876.  
  877. if (man == 0)
  878. {
  879. du.uu = 0;
  880. }
  881. else
  882. {
  883. // Normalize so that 0x0010 0000 0000 0000 is the highest bit set
  884. int cbitShift = CbitHighZero(man) - 11;
  885. if (cbitShift < 0)
  886. man >>= -cbitShift;
  887. else
  888. man <<= cbitShift;
  889.  
  890. // Move the point to just behind the leading 1: 0x001.0 0000 0000 0000
  891. // (52 bits) and skew the exponent (by 0x3FF == 1023)
  892. exp += 1075;
  893.  
  894. if (exp >= 0x7FF)
  895. {
  896. // Infinity
  897. du.uu = 0x7FF0000000000000;
  898. }
  899. else if (exp <= 0)
  900. {
  901. // Denormalized
  902. exp--;
  903. if (exp < -52)
  904. {
  905. // Underflow to zero
  906. du.uu = 0;
  907. }
  908. else
  909. {
  910. du.uu = man >> -exp;
  911. }
  912. }
  913. else
  914. {
  915. // Mask off the implicit high bit
  916. du.uu = (man & 0x000FFFFFFFFFFFFF) | ((ulong)exp << 52);
  917. }
  918. }
  919.  
  920. if (sign < 0)
  921. {
  922. du.uu |= 0x8000000000000000;
  923. }
  924.  
  925. return du.dbl;
  926. }
  927.  
  928. private static int CbitHighZero(ulong uu)
  929. {
  930. if ((uu & 0xFFFFFFFF00000000) == 0)
  931. return 32 + CbitHighZero((uint)uu);
  932. return CbitHighZero((uint)(uu >> 32));
  933. }
  934.  
  935. private static int CbitHighZero(uint u)
  936. {
  937. if (u == 0)
  938. return 32;
  939.  
  940. int cbit = 0;
  941. if ((u & 0xFFFF0000) == 0)
  942. {
  943. cbit += 16;
  944. u <<= 16;
  945. }
  946. if ((u & 0xFF000000) == 0)
  947. {
  948. cbit += 8;
  949. u <<= 8;
  950. }
  951. if ((u & 0xF0000000) == 0)
  952. {
  953. cbit += 4;
  954. u <<= 4;
  955. }
  956. if ((u & 0xC0000000) == 0)
  957. {
  958. cbit += 2;
  959. u <<= 2;
  960. }
  961. if ((u & 0x80000000) == 0)
  962. cbit += 1;
  963. return cbit;
  964. }
  965.  
  966. #endregion static helper methods
  967. } // BigRational
  968. } // namespace Numerics
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement