Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Copyright (c) Microsoft Corporation. All rights reserved.
- /*============================================================
- ** Class: BigRational
- **
- ** Purpose:
- ** --------
- ** This class is used to represent an arbitrary precision
- ** BigRational number
- **
- ** A rational number (commonly called a fraction) is a ratio
- ** between two integers. For example (3/6) = (2/4) = (1/2)
- **
- ** Arithmetic
- ** ----------
- ** a/b = c/d, iff ad = bc
- ** a/b + c/d == (ad + bc)/bd
- ** a/b - c/d == (ad - bc)/bd
- ** a/b % c/d == (ad % bc)/bd
- ** a/b * c/d == (ac)/(bd)
- ** a/b / c/d == (ad)/(bc)
- ** -(a/b) == (-a)/b
- ** (a/b)^(-1) == b/a, if a != 0
- **
- ** Reduction Algorithm
- ** ------------------------
- ** Euclid's algorithm is used to simplify the fraction.
- ** Calculating the greatest common divisor of two n-digit
- ** numbers can be found in
- **
- ** O(n(log n)^5 (log log n)) steps as n -> +infinity
- ============================================================*/
- namespace Numerics
- {
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Globalization;
- using System.Numerics;
- using System.Runtime.InteropServices;
- using System.Runtime.Serialization;
- using System.Security.Permissions;
- using System.Text;
- [Serializable]
- [ComVisible(false)]
- public struct BigRational : IComparable, IComparable<BigRational>, IDeserializationCallback, IEquatable<BigRational>, ISerializable
- {
- // ---- SECTION: members supporting exposed properties -------------*
- private BigInteger m_numerator;
- private BigInteger m_denominator;
- private static readonly BigRational s_brZero = new BigRational(BigInteger.Zero);
- private static readonly BigRational s_brOne = new BigRational(BigInteger.One);
- private static readonly BigRational s_brMinusOne = new BigRational(BigInteger.MinusOne);
- // ---- SECTION: members for internal support ---------*
- #region Members for Internal Support
- [StructLayout(LayoutKind.Explicit)]
- internal struct DoubleUlong
- {
- [FieldOffset(0)]
- public double dbl;
- [FieldOffset(0)]
- public ulong uu;
- }
- private const int DoubleMaxScale = 308;
- private static readonly BigInteger s_bnDoublePrecision = BigInteger.Pow(10, DoubleMaxScale);
- private static readonly BigInteger s_bnDoubleMaxValue = (BigInteger)Double.MaxValue;
- private static readonly BigInteger s_bnDoubleMinValue = (BigInteger)Double.MinValue;
- [StructLayout(LayoutKind.Explicit)]
- internal struct DecimalUInt32
- {
- [FieldOffset(0)]
- public Decimal dec;
- [FieldOffset(0)]
- public int flags;
- }
- private const int DecimalScaleMask = 0x00FF0000;
- private const int DecimalSignMask = unchecked((int)0x80000000);
- private const int DecimalMaxScale = 28;
- private static readonly BigInteger s_bnDecimalPrecision = BigInteger.Pow(10, DecimalMaxScale);
- private static readonly BigInteger s_bnDecimalMaxValue = (BigInteger)Decimal.MaxValue;
- private static readonly BigInteger s_bnDecimalMinValue = (BigInteger)Decimal.MinValue;
- private const String c_solidus = @"/";
- #endregion Members for Internal Support
- // ---- SECTION: public properties --------------*
- #region Public Properties
- public static BigRational Zero
- {
- get
- {
- return s_brZero;
- }
- }
- public static BigRational One
- {
- get
- {
- return s_brOne;
- }
- }
- public static BigRational MinusOne
- {
- get
- {
- return s_brMinusOne;
- }
- }
- public Int32 Sign
- {
- get
- {
- return m_numerator.Sign;
- }
- }
- public BigInteger Numerator
- {
- get
- {
- return m_numerator;
- }
- }
- public BigInteger Denominator
- {
- get
- {
- return m_denominator;
- }
- }
- #endregion Public Properties
- // ---- SECTION: public instance methods --------------*
- #region Public Instance Methods
- // GetWholePart() and GetFractionPart()
- //
- // BigRational == Whole, Fraction
- // 0/2 == 0, 0/2
- // 1/2 == 0, 1/2
- // -1/2 == 0, -1/2
- // 1/1 == 1, 0/1
- // -1/1 == -1, 0/1
- // -3/2 == -1, -1/2
- // 3/2 == 1, 1/2
- public BigInteger GetWholePart()
- {
- return BigInteger.Divide(m_numerator, m_denominator);
- }
- public BigRational GetFractionPart()
- {
- return new BigRational(BigInteger.Remainder(m_numerator, m_denominator), m_denominator);
- }
- public override bool Equals(Object obj)
- {
- if (obj == null)
- return false;
- if (!(obj is BigRational))
- return false;
- return this.Equals((BigRational)obj);
- }
- public override int GetHashCode()
- {
- return (m_numerator / Denominator).GetHashCode();
- }
- // IComparable
- int IComparable.CompareTo(Object obj)
- {
- if (obj == null)
- return 1;
- if (!(obj is BigRational))
- throw new ArgumentException("Argument must be of type BigRational", "obj");
- return Compare(this, (BigRational)obj);
- }
- // IComparable<BigRational>
- public int CompareTo(BigRational other)
- {
- return Compare(this, other);
- }
- // Object.ToString
- public override String ToString()
- {
- StringBuilder ret = new StringBuilder();
- ret.Append(m_numerator.ToString("R", CultureInfo.InvariantCulture));
- ret.Append(c_solidus);
- ret.Append(Denominator.ToString("R", CultureInfo.InvariantCulture));
- return ret.ToString();
- }
- // IEquatable<BigRational>
- // a/b = c/d, iff ad = bc
- public Boolean Equals(BigRational other)
- {
- if (this.Denominator == other.Denominator)
- {
- return m_numerator == other.m_numerator;
- }
- else
- {
- return (m_numerator * other.Denominator) == (Denominator * other.m_numerator);
- }
- }
- #endregion Public Instance Methods
- // -------- SECTION: constructors -----------------*
- #region Constructors
- public BigRational(BigInteger numerator)
- {
- m_numerator = numerator;
- m_denominator = BigInteger.One;
- }
- // BigRational(Double)
- public BigRational(Double value)
- {
- if (Double.IsNaN(value))
- {
- throw new ArgumentException("Argument is not a number", "value");
- }
- else if (Double.IsInfinity(value))
- {
- throw new ArgumentException("Argument is infinity", "value");
- }
- bool isFinite;
- int sign;
- int exponent;
- ulong significand;
- SplitDoubleIntoParts(value, out sign, out exponent, out significand, out isFinite);
- if (significand == 0)
- {
- this = BigRational.Zero;
- return;
- }
- m_numerator = significand;
- m_denominator = 1 << 52;
- if (exponent > 0)
- {
- m_numerator = BigInteger.Pow(m_numerator, exponent);
- }
- else if (exponent < 0)
- {
- m_denominator = BigInteger.Pow(m_denominator, -exponent);
- }
- if (sign < 0)
- {
- m_numerator = BigInteger.Negate(m_numerator);
- }
- Simplify();
- }
- // BigRational(Decimal) -
- //
- // The Decimal type represents floating point numbers exactly, with no rounding error.
- // Values such as "0.1" in Decimal are actually representable, and convert cleanly
- // to BigRational as "11/10"
- public BigRational(Decimal value)
- {
- int[] bits = Decimal.GetBits(value);
- if (bits == null || bits.Length != 4 || (bits[3] & ~(DecimalSignMask | DecimalScaleMask)) != 0 || (bits[3] & DecimalScaleMask) > (28 << 16))
- {
- throw new ArgumentException("invalid Decimal", "value");
- }
- if (value == Decimal.Zero)
- {
- this = BigRational.Zero;
- return;
- }
- // build up the numerator
- ulong ul = (((ulong)(uint)bits[2]) << 32) | ((ulong)(uint)bits[1]); // (hi << 32) | (mid)
- m_numerator = (new BigInteger(ul) << 32) | (uint)bits[0]; // (hiMid << 32) | (low)
- bool isNegative = (bits[3] & DecimalSignMask) != 0;
- if (isNegative)
- {
- m_numerator = BigInteger.Negate(m_numerator);
- }
- // build up the denominator
- int scale = (bits[3] & DecimalScaleMask) >> 16; // 0-28, power of 10 to divide numerator by
- m_denominator = BigInteger.Pow(10, scale);
- Simplify();
- }
- public BigRational(BigInteger numerator, BigInteger denominator)
- {
- if (denominator.Sign == 0)
- {
- throw new DivideByZeroException();
- }
- else if (numerator.Sign == 0)
- {
- // 0/m -> 0/1
- m_numerator = BigInteger.Zero;
- m_denominator = BigInteger.One;
- }
- else if (denominator.Sign < 0)
- {
- m_numerator = BigInteger.Negate(numerator);
- m_denominator = BigInteger.Negate(denominator);
- }
- else
- {
- m_numerator = numerator;
- m_denominator = denominator;
- }
- Simplify();
- }
- public BigRational(BigInteger whole, BigInteger numerator, BigInteger denominator)
- {
- if (denominator.Sign == 0)
- {
- throw new DivideByZeroException();
- }
- else if (numerator.Sign == 0 && whole.Sign == 0)
- {
- m_numerator = BigInteger.Zero;
- m_denominator = BigInteger.One;
- }
- else if (denominator.Sign < 0)
- {
- m_denominator = BigInteger.Negate(denominator);
- m_numerator = (BigInteger.Negate(whole) * m_denominator) + BigInteger.Negate(numerator);
- }
- else
- {
- m_denominator = denominator;
- m_numerator = (whole * denominator) + numerator;
- }
- Simplify();
- }
- #endregion Constructors
- // -------- SECTION: public static methods -----------------*
- #region Public Static Methods
- public static BigRational Abs(BigRational r)
- {
- return (r.m_numerator.Sign < 0 ? new BigRational(BigInteger.Abs(r.m_numerator), r.Denominator) : r);
- }
- public static BigRational Negate(BigRational r)
- {
- return new BigRational(BigInteger.Negate(r.m_numerator), r.Denominator);
- }
- public static BigRational Invert(BigRational r)
- {
- return new BigRational(r.Denominator, r.m_numerator);
- }
- public static BigRational Add(BigRational x, BigRational y)
- {
- return x + y;
- }
- public static BigRational Subtract(BigRational x, BigRational y)
- {
- return x - y;
- }
- public static BigRational Multiply(BigRational x, BigRational y)
- {
- return x * y;
- }
- public static BigRational Divide(BigRational dividend, BigRational divisor)
- {
- return dividend / divisor;
- }
- public static BigRational Remainder(BigRational dividend, BigRational divisor)
- {
- return dividend % divisor;
- }
- public static BigRational DivRem(BigRational dividend, BigRational divisor, out BigRational remainder)
- {
- // a/b / c/d == (ad)/(bc)
- // a/b % c/d == (ad % bc)/bd
- // (ad) and (bc) need to be calculated for both the division and the remainder operations.
- BigInteger ad = dividend.m_numerator * divisor.Denominator;
- BigInteger bc = dividend.Denominator * divisor.m_numerator;
- BigInteger bd = dividend.Denominator * divisor.Denominator;
- remainder = new BigRational(ad % bc, bd);
- return new BigRational(ad, bc);
- }
- public static BigRational Pow(BigRational baseValue, BigInteger exponent)
- {
- if (exponent.Sign == 0)
- {
- // 0^0 -> 1
- // n^0 -> 1
- return BigRational.One;
- }
- else if (exponent.Sign < 0)
- {
- if (baseValue == BigRational.Zero)
- {
- throw new ArgumentException("cannot raise zero to a negative power", "baseValue");
- }
- // n^(-e) -> (1/n)^e
- baseValue = BigRational.Invert(baseValue);
- exponent = BigInteger.Negate(exponent);
- }
- BigRational result = baseValue;
- while (exponent > BigInteger.One)
- {
- result = result * baseValue;
- exponent--;
- }
- return result;
- }
- // Least Common Denominator (LCD)
- //
- // The LCD is the least common multiple of the two denominators. For instance, the LCD of
- // {1/2, 1/4} is 4 because the least common multiple of 2 and 4 is 4. Likewise, the LCD
- // of {1/2, 1/3} is 6.
- //
- // To find the LCD:
- //
- // 1) Find the Greatest Common Divisor (GCD) of the denominators
- // 2) Multiply the denominators together
- // 3) Divide the product of the denominators by the GCD
- public static BigInteger LeastCommonDenominator(BigRational x, BigRational y)
- {
- // LCD( a/b, c/d ) == (bd) / gcd(b,d)
- return (x.Denominator * y.Denominator) / BigInteger.GreatestCommonDivisor(x.Denominator, y.Denominator);
- }
- public static int Compare(BigRational r1, BigRational r2)
- {
- // a/b = c/d, iff ad = bc
- return BigInteger.Compare(r1.m_numerator * r2.Denominator, r2.m_numerator * r1.Denominator);
- }
- #endregion Public Static Methods
- #region Operator Overloads
- public static bool operator ==(BigRational x, BigRational y)
- {
- return Compare(x, y) == 0;
- }
- public static bool operator !=(BigRational x, BigRational y)
- {
- return Compare(x, y) != 0;
- }
- public static bool operator <(BigRational x, BigRational y)
- {
- return Compare(x, y) < 0;
- }
- public static bool operator <=(BigRational x, BigRational y)
- {
- return Compare(x, y) <= 0;
- }
- public static bool operator >(BigRational x, BigRational y)
- {
- return Compare(x, y) > 0;
- }
- public static bool operator >=(BigRational x, BigRational y)
- {
- return Compare(x, y) >= 0;
- }
- public static BigRational operator +(BigRational r)
- {
- return r;
- }
- public static BigRational operator -(BigRational r)
- {
- return new BigRational(-r.m_numerator, r.Denominator);
- }
- public static BigRational operator ++(BigRational r)
- {
- return r + BigRational.One;
- }
- public static BigRational operator --(BigRational r)
- {
- return r - BigRational.One;
- }
- public static BigRational operator +(BigRational r1, BigRational r2)
- {
- // a/b + c/d == (ad + bc)/bd
- return new BigRational((r1.m_numerator * r2.Denominator) + (r1.Denominator * r2.m_numerator), (r1.Denominator * r2.Denominator));
- }
- public static BigRational operator -(BigRational r1, BigRational r2)
- {
- // a/b - c/d == (ad - bc)/bd
- return new BigRational((r1.m_numerator * r2.Denominator) - (r1.Denominator * r2.m_numerator), (r1.Denominator * r2.Denominator));
- }
- public static BigRational operator *(BigRational r1, BigRational r2)
- {
- // a/b * c/d == (ac)/(bd)
- return new BigRational((r1.m_numerator * r2.m_numerator), (r1.Denominator * r2.Denominator));
- }
- public static BigRational operator /(BigRational r1, BigRational r2)
- {
- // a/b / c/d == (ad)/(bc)
- return new BigRational((r1.m_numerator * r2.Denominator), (r1.Denominator * r2.m_numerator));
- }
- public static BigRational operator %(BigRational r1, BigRational r2)
- {
- // a/b % c/d == (ad % bc)/bd
- return new BigRational((r1.m_numerator * r2.Denominator) % (r1.Denominator * r2.m_numerator), (r1.Denominator * r2.Denominator));
- }
- #endregion Operator Overloads
- // ----- SECTION: explicit conversions from BigRational to numeric base types ----------------*
- #region explicit conversions from BigRational
- [CLSCompliant(false)]
- public static explicit operator SByte(BigRational value)
- {
- return (SByte)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- [CLSCompliant(false)]
- public static explicit operator UInt16(BigRational value)
- {
- return (UInt16)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- [CLSCompliant(false)]
- public static explicit operator UInt32(BigRational value)
- {
- return (UInt32)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- [CLSCompliant(false)]
- public static explicit operator UInt64(BigRational value)
- {
- return (UInt64)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- public static explicit operator Byte(BigRational value)
- {
- return (Byte)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- public static explicit operator Int16(BigRational value)
- {
- return (Int16)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- public static explicit operator Int32(BigRational value)
- {
- return (Int32)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- public static explicit operator Int64(BigRational value)
- {
- return (Int64)(BigInteger.Divide(value.m_numerator, value.m_denominator));
- }
- public static explicit operator BigInteger(BigRational value)
- {
- return BigInteger.Divide(value.m_numerator, value.m_denominator);
- }
- public static explicit operator Single(BigRational value)
- {
- // The Single value type represents a single-precision 32-bit number with
- // values ranging from negative 3.402823e38 to positive 3.402823e38
- // values that do not fit into this range are returned as Infinity
- return (Single)((Double)value);
- }
- public static explicit operator Double(BigRational value)
- {
- // The Double value type represents a double-precision 64-bit number with
- // values ranging from -1.79769313486232e308 to +1.79769313486232e308
- // values that do not fit into this range are returned as +/-Infinity
- if (SafeCastToDouble(value.m_numerator) && SafeCastToDouble(value.m_denominator))
- {
- return (Double)value.m_numerator / (Double)value.m_denominator;
- }
- // scale the numerator to preseve the fraction part through the integer division
- BigInteger denormalized = (value.m_numerator * s_bnDoublePrecision) / value.m_denominator;
- if (denormalized.IsZero)
- return (value.Sign < 0) ? BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000)) : 0d; // underflow to -+0
- Double result = 0;
- bool isDouble = false;
- int scale = DoubleMaxScale;
- while (scale > 0)
- {
- if (!isDouble)
- {
- if (SafeCastToDouble(denormalized))
- {
- result = (Double)denormalized;
- isDouble = true;
- }
- else
- {
- denormalized = denormalized / 10;
- }
- }
- result = result / 10;
- scale--;
- }
- if (!isDouble)
- return (value.Sign < 0) ? Double.NegativeInfinity : Double.PositiveInfinity;
- else
- return result;
- }
- public static explicit operator Decimal(BigRational value)
- {
- // The Decimal value type represents decimal numbers ranging
- // from +79,228,162,514,264,337,593,543,950,335 to -79,228,162,514,264,337,593,543,950,335
- // the binary representation of a Decimal value is of the form, ((-2^96 to 2^96) / 10^(0 to 28))
- if (SafeCastToDecimal(value.m_numerator) && SafeCastToDecimal(value.m_denominator))
- {
- return (Decimal)value.m_numerator / (Decimal)value.m_denominator;
- }
- // scale the numerator to preseve the fraction part through the integer division
- BigInteger denormalized = (value.m_numerator * s_bnDecimalPrecision) / value.m_denominator;
- if (denormalized.IsZero)
- {
- return Decimal.Zero; // underflow - fraction is too small to fit in a decimal
- }
- for (int scale = DecimalMaxScale; scale >= 0; scale--)
- {
- if (!SafeCastToDecimal(denormalized))
- {
- denormalized = denormalized / 10;
- }
- else
- {
- DecimalUInt32 dec = new DecimalUInt32();
- dec.dec = (Decimal)denormalized;
- dec.flags = (dec.flags & ~DecimalScaleMask) | (scale << 16);
- return dec.dec;
- }
- }
- throw new OverflowException("Value was either too large or too small for a Decimal.");
- }
- #endregion explicit conversions from BigRational
- // ----- SECTION: implicit conversions from numeric base types to BigRational ----------------*
- #region implicit conversions to BigRational
- [CLSCompliant(false)]
- public static implicit operator BigRational(SByte value)
- {
- return new BigRational((BigInteger)value);
- }
- [CLSCompliant(false)]
- public static implicit operator BigRational(UInt16 value)
- {
- return new BigRational((BigInteger)value);
- }
- [CLSCompliant(false)]
- public static implicit operator BigRational(UInt32 value)
- {
- return new BigRational((BigInteger)value);
- }
- [CLSCompliant(false)]
- public static implicit operator BigRational(UInt64 value)
- {
- return new BigRational((BigInteger)value);
- }
- public static implicit operator BigRational(Byte value)
- {
- return new BigRational((BigInteger)value);
- }
- public static implicit operator BigRational(Int16 value)
- {
- return new BigRational((BigInteger)value);
- }
- public static implicit operator BigRational(Int32 value)
- {
- return new BigRational((BigInteger)value);
- }
- public static implicit operator BigRational(Int64 value)
- {
- return new BigRational((BigInteger)value);
- }
- public static implicit operator BigRational(BigInteger value)
- {
- return new BigRational(value);
- }
- public static implicit operator BigRational(Single value)
- {
- return new BigRational((Double)value);
- }
- public static implicit operator BigRational(Double value)
- {
- return new BigRational(value);
- }
- public static implicit operator BigRational(Decimal value)
- {
- return new BigRational(value);
- }
- #endregion implicit conversions to BigRational
- // ----- SECTION: private serialization instance methods ----------------*
- #region serialization
- void IDeserializationCallback.OnDeserialization(Object sender)
- {
- try
- {
- // verify that the deserialized number is well formed
- if (m_denominator.Sign == 0 || m_numerator.Sign == 0)
- {
- // n/0 -> 0/1
- // 0/m -> 0/1
- m_numerator = BigInteger.Zero;
- m_denominator = BigInteger.One;
- }
- else if (m_denominator.Sign < 0)
- {
- m_numerator = BigInteger.Negate(m_numerator);
- m_denominator = BigInteger.Negate(m_denominator);
- }
- Simplify();
- }
- catch (ArgumentException e)
- {
- throw new SerializationException("invalid serialization data", e);
- }
- }
- [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
- void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
- {
- if (info == null)
- {
- throw new ArgumentNullException("info");
- }
- info.AddValue("Numerator", m_numerator);
- info.AddValue("Denominator", m_denominator);
- }
- BigRational(SerializationInfo info, StreamingContext context)
- {
- if (info == null)
- {
- throw new ArgumentNullException("info");
- }
- m_numerator = (BigInteger)info.GetValue("Numerator", typeof(BigInteger));
- m_denominator = (BigInteger)info.GetValue("Denominator", typeof(BigInteger));
- }
- #endregion serialization
- // ----- SECTION: private instance utility methods ----------------*
- #region instance helper methods
- private void Simplify()
- {
- // * if the numerator is {0, +1, -1} then the fraction is already reduced
- // * if the denominator is {+1} then the fraction is already reduced
- if (m_numerator == BigInteger.Zero)
- {
- m_denominator = BigInteger.One;
- }
- BigInteger gcd = BigInteger.GreatestCommonDivisor(m_numerator, m_denominator);
- if (gcd > BigInteger.One)
- {
- m_numerator = m_numerator / gcd;
- m_denominator = Denominator / gcd;
- }
- }
- #endregion instance helper methods
- // ----- SECTION: private static utility methods -----------------*
- #region static helper methods
- private static bool SafeCastToDouble(BigInteger value)
- {
- return s_bnDoubleMinValue <= value && value <= s_bnDoubleMaxValue;
- }
- private static bool SafeCastToDecimal(BigInteger value)
- {
- return s_bnDecimalMinValue <= value && value <= s_bnDecimalMaxValue;
- }
- private static void SplitDoubleIntoParts(double dbl, out int sign, out int exp, out ulong man, out bool isFinite)
- {
- DoubleUlong du;
- du.uu = 0;
- du.dbl = dbl;
- sign = 1 - ((int)(du.uu >> 62) & 2);
- man = du.uu & 0x000FFFFFFFFFFFFF;
- exp = (int)(du.uu >> 52) & 0x7FF;
- if (exp == 0)
- {
- // Denormalized number.
- isFinite = true;
- if (man != 0)
- exp = -1074;
- }
- else if (exp == 0x7FF)
- {
- // NaN or Infinite.
- isFinite = false;
- exp = Int32.MaxValue;
- }
- else
- {
- isFinite = true;
- man |= 0x0010000000000000; // mask in the implied leading 53rd significand bit
- exp -= 1075;
- }
- }
- private static double GetDoubleFromParts(int sign, int exp, ulong man)
- {
- DoubleUlong du;
- du.dbl = 0;
- if (man == 0)
- {
- du.uu = 0;
- }
- else
- {
- // Normalize so that 0x0010 0000 0000 0000 is the highest bit set
- int cbitShift = CbitHighZero(man) - 11;
- if (cbitShift < 0)
- man >>= -cbitShift;
- else
- man <<= cbitShift;
- // Move the point to just behind the leading 1: 0x001.0 0000 0000 0000
- // (52 bits) and skew the exponent (by 0x3FF == 1023)
- exp += 1075;
- if (exp >= 0x7FF)
- {
- // Infinity
- du.uu = 0x7FF0000000000000;
- }
- else if (exp <= 0)
- {
- // Denormalized
- exp--;
- if (exp < -52)
- {
- // Underflow to zero
- du.uu = 0;
- }
- else
- {
- du.uu = man >> -exp;
- }
- }
- else
- {
- // Mask off the implicit high bit
- du.uu = (man & 0x000FFFFFFFFFFFFF) | ((ulong)exp << 52);
- }
- }
- if (sign < 0)
- {
- du.uu |= 0x8000000000000000;
- }
- return du.dbl;
- }
- private static int CbitHighZero(ulong uu)
- {
- if ((uu & 0xFFFFFFFF00000000) == 0)
- return 32 + CbitHighZero((uint)uu);
- return CbitHighZero((uint)(uu >> 32));
- }
- private static int CbitHighZero(uint u)
- {
- if (u == 0)
- return 32;
- int cbit = 0;
- if ((u & 0xFFFF0000) == 0)
- {
- cbit += 16;
- u <<= 16;
- }
- if ((u & 0xFF000000) == 0)
- {
- cbit += 8;
- u <<= 8;
- }
- if ((u & 0xF0000000) == 0)
- {
- cbit += 4;
- u <<= 4;
- }
- if ((u & 0xC0000000) == 0)
- {
- cbit += 2;
- u <<= 2;
- }
- if ((u & 0x80000000) == 0)
- cbit += 1;
- return cbit;
- }
- #endregion static helper methods
- } // BigRational
- } // namespace Numerics
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement