{"id":259,"date":"2020-12-05T16:53:10","date_gmt":"2020-12-05T16:53:10","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=259"},"modified":"2021-06-15T18:10:39","modified_gmt":"2021-06-15T18:10:39","slug":"bigrational-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2020\/12\/05\/bigrational-cs\/","title":{"rendered":"BigRational.cs"},"content":{"rendered":"\n<p>C# Arbitrary Precision Signed Big Rational Numbers<\/p>\n\n\n\n<p>Updated: Jun-11,2021<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.Numerics;\nusing System.Runtime.InteropServices;\nusing System.Text;\n[DebuggerDisplay(\"{\" + nameof(DDisplay) + \"}\")]\n[Serializable]\npublic struct BigRational : IComparable, IComparable&lt;BigRational>, IEquatable&lt;BigRational>\n{\n    [StructLayout(LayoutKind.Explicit)]\n    internal struct DoubleUlong\n    {\n        [FieldOffset(0)] public double dbl;\n        [FieldOffset(0)] public ulong  uu;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Change here if more then 2048 bits are specified\n    \/\/\/ &lt;\/summary>\n    private const float DecimalMaxScale = 2048f \/ 64f * 20f;\n    private static readonly BigInteger DecimalPrecision = BigInteger.Pow(10, (int)DecimalMaxScale);\n    private const           int        DoubleMaxScale   = 308;\n    public static BigRational Pi = new(\n        \"3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798162478513934506898440362801792706010179987216806726188740140466033567581311679376075335101609659171030644576233653027450257182803484658351860927270133809030914436823660262931162576284703194589395221866245992710817555393680237554917047871708932985106840785074833639247080859264327721882027979677397953754604196915619381410505600288856897761875941052867609089114345150157869223684881643245943313338421018485091403977277400743970527492816321894223953257584787737337170568053925027217102844351208765657302025589127695185039186644597240030541171074757870137431100579097277905612641495178817964173941740654985445918326928220945355416048444887050935562696866696019631573868714587428709669938320262709342763\");\n    public static           BigRational   E               = GetE(MaxFactorials);\n    private static readonly BigInteger    DoublePrecision = BigInteger.Pow(10, DoubleMaxScale);\n    private static readonly BigInteger    DoubleMaxValue  = (BigInteger)double.MaxValue;\n    private static readonly BigInteger    DoubleMinValue  = (BigInteger)double.MinValue;\n    private static          BigRational[] Factorials;\n    static BigRational()\n    {\n    }\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\n    private string DDisplay => AsDecimal(this);\n    [StructLayout(LayoutKind.Explicit)]\n    internal struct DecimalUInt32\n    {\n        [FieldOffset(0)] public decimal dec;\n        [FieldOffset(0)] public int     flags;\n    }\n    private const           int        DecimalScaleMask = 0x00FF0000;\n    private const           int        DecimalSignMask  = unchecked((int)0x80000000);\n    private const           int        MaxFactorials    = 100;\n    private static readonly BigInteger DecimalMaxValue  = (BigInteger)decimal.MaxValue;\n    private static readonly BigInteger DecimalMinValue  = (BigInteger)decimal.MinValue;\n    private const           string     Solidus          = @\"\/\";\n    public static BigRational Zero\n    {\n        get;\n    } = new(BigInteger.Zero);\n    public static BigRational One\n    {\n        get;\n    } = new(BigInteger.One);\n    public static BigRational MinusOne\n    {\n        get;\n    } = new(BigInteger.MinusOne);\n    public int Sign => Numerator.Sign;\n    public BigInteger Numerator\n    {\n        get;\n        private set;\n    }\n    public BigInteger Denominator\n    {\n        get;\n        private set;\n    }\n    public BigInteger WholePart => BigInteger.Divide(Numerator, Denominator);\n    public bool IsFractionalPart\n    {\n        get\n        {\n            var fp = FractionPart;\n            return fp.Numerator != 0 || fp.Denominator != 1;\n        }\n    }\n    public BigInteger GetUnscaledAsDecimal => Numerator * DecimalPrecision \/ Denominator;\n    public BigInteger Remainder            => Numerator                    % Denominator;\n    public int DecimalPlaces\n    {\n        get\n        {\n            var a       = GetUnscaledAsDecimal;\n            var dPlaces = 0;\n            if (a.Sign == 0)\n                return 1;\n            if (a.Sign &lt; 0)\n                try\n                {\n                    a = -a;\n                }\n                catch (Exception ex)\n                {\n                    return 0;\n                }\n            var biRadix = new BigInteger(10);\n            while (a > 0)\n                try\n                {\n                    a \/= biRadix;\n                    dPlaces++;\n                }\n                catch (Exception ex)\n                {\n                    break;\n                }\n            return dPlaces;\n        }\n    }\n    public static string AsDecimal(BigRational value)\n    {\n        var asd = new BigDecimal(value);\n        return asd.ToString();\n    }\n    public static string CleanAsDecimal(BigRational value)\n    {\n        var fpas = AsDecimal(value);\n        var rs   = fpas.Reverse();\n        var fas  = \"\";\n        foreach (var c in rs)\n            if (c == '0')\n                continue;\n            else\n                fas += c;\n        return fas.Reverse();\n    }\n    public BigRational FractionPart\n    {\n        get\n        {\n            var rem = BigInteger.Remainder(Numerator, Denominator);\n            return new BigRational(rem, Denominator);\n        }\n    }\n    public override bool Equals(object obj)\n    {\n        if (obj == null)\n            return false;\n        if (!(obj is BigRational))\n            return false;\n        return Equals((BigRational)obj);\n    }\n    public override int GetHashCode()\n    {\n        return (Numerator \/ Denominator).GetHashCode();\n    }\n    int IComparable.CompareTo(object obj)\n    {\n        if (obj == null)\n            return 1;\n        if (!(obj is BigRational))\n            throw new ArgumentException();\n        return Compare(this, (BigRational)obj);\n    }\n    public int CompareTo(BigRational other)\n    {\n        return Compare(this, other);\n    }\n    public bool Equals(BigRational other)\n    {\n        if (Denominator == other.Denominator)\n            return Numerator == other.Numerator;\n        return Numerator * other.Denominator == Denominator * other.Numerator;\n    }\n    public BigRational(BigInteger numerator)\n    {\n        Numerator   = numerator;\n        Denominator = BigInteger.One;\n    }\n    public BigRational(string n, string d)\n    {\n        Numerator   = new BigInteger().BigIntegerBase10(n);\n        Denominator = new BigInteger().BigIntegerBase10(d);\n    }\n    public BigRational(string value)\n    {\n        if (!value.ContainsOnly(\"0123456789+-.eE\"))\n            throw new Exception(\n                $\"Input value must only contain these '0123456789+-.eE', value'{value}\");\n        var v1 = new BigDecimal(value);\n        var (unscaledValue, scale) = v1.ToByteArrays();\n        if (v1 == BigDecimal.Zero)\n        {\n            this = Zero;\n            return;\n        }\n        Numerator   = new BigInteger(unscaledValue);\n        Denominator = BigInteger.Pow(10, BitConverter.ToInt32(scale, 0));\n        Simplify();\n    }\n    public static bool TryParse(string parse, out BigRational result)\n    {\n        result = default;\n        if (!parse.ContainsOnly(\"0123456789+-.eE\"))\n            throw new Exception(\n                $\"Input value must only contain these '0123456789+-.eE', value'{parse}\");\n        try\n        {\n            result = new BigRational(parse);\n        }\n        catch\n        {\n            return false;\n        }\n        return true;\n    }\n    public BigRational(double value) : this((decimal)value)\n    {\n    }\n    public BigRational(BigDecimal value)\n    {\n        var bits = value.ToByteArrays();\n        if (value == BigDecimal.Zero)\n        {\n            this = Zero;\n            return;\n        }\n        Numerator   = new BigInteger(bits.unscaledValue);\n        Denominator = BigInteger.Pow(10, BitConverter.ToInt32(bits.scale, 0));\n        Simplify();\n    }\n    public BigRational(decimal value)\n    {\n        var bits = decimal.GetBits(value);\n        if (bits                                              == null || bits.Length != 4 ||\n            (bits[3] &amp; ~(DecimalSignMask | DecimalScaleMask)) != 0    ||\n            (bits[3] &amp; DecimalScaleMask)                      > 28 &lt;&lt; 16)\n            throw new ArgumentException();\n        if (value == decimal.Zero)\n        {\n            this = Zero;\n            return;\n        }\n        var ul = ((ulong)(uint)bits[2] &lt;&lt; 32) | (uint)bits[1];\n        Numerator = (new BigInteger(ul) &lt;&lt; 32) | (uint)bits[0];\n        var isNegative = (bits[3] &amp; DecimalSignMask) != 0;\n        if (isNegative)\n            Numerator = BigInteger.Negate(Numerator);\n        var scale = (bits[3] &amp; DecimalScaleMask) >> 16;\n        Denominator = BigInteger.Pow(10, scale);\n        Simplify();\n    }\n    public BigRational(BigInteger numerator, BigInteger denominator)\n    {\n        if (denominator.Sign == 0)\n            throw new DivideByZeroException();\n        if (numerator.Sign == 0)\n        {\n            Numerator   = BigInteger.Zero;\n            Denominator = BigInteger.One;\n        }\n        else if (denominator.Sign &lt; 0)\n        {\n            Numerator   = BigInteger.Negate(numerator);\n            Denominator = BigInteger.Negate(denominator);\n        }\n        else\n        {\n            Numerator   = numerator;\n            Denominator = denominator;\n        }\n        Simplify();\n    }\n    public BigRational(BigInteger whole, BigInteger numerator, BigInteger denominator)\n    {\n        if (denominator.Sign == 0)\n            throw new DivideByZeroException();\n        if (numerator.Sign == 0 &amp;&amp; whole.Sign == 0)\n        {\n            Numerator   = BigInteger.Zero;\n            Denominator = BigInteger.One;\n        }\n        else if (denominator.Sign &lt; 0)\n        {\n            Denominator = BigInteger.Negate(denominator);\n            Numerator   = BigInteger.Negate(whole) * Denominator + BigInteger.Negate(numerator);\n        }\n        else\n        {\n            Denominator = denominator;\n            Numerator   = whole * denominator + numerator;\n        }\n        Simplify();\n    }\n    public static BigRational Abs(BigRational r)\n    {\n        return r.Numerator.Sign &lt; 0\n            ? new BigRational(BigInteger.Abs(r.Numerator), r.Denominator)\n            : r;\n    }\n    public static BigRational Negate(BigRational r)\n    {\n        return new BigRational(BigInteger.Negate(r.Numerator), r.Denominator);\n    }\n    public static BigRational Invert(BigRational r)\n    {\n        return new BigRational(r.Denominator, r.Numerator);\n    }\n    public static BigRational Add(BigRational x, BigRational y)\n    {\n        return x + y;\n    }\n    public static BigRational Subtract(BigRational x, BigRational y)\n    {\n        return x - y;\n    }\n    public static BigRational Multiply(BigRational x, BigRational y)\n    {\n        return x * y;\n    }\n    public static BigRational Divide(BigRational dividend, BigRational divisor)\n    {\n        return dividend \/ divisor;\n    }\n    public static BigRational DivRem(BigRational dividend,\n        BigRational                              divisor,\n        out BigRational                          remainder)\n    {\n        var ad = dividend.Numerator   * divisor.Denominator;\n        var bc = dividend.Denominator * divisor.Numerator;\n        var bd = dividend.Denominator * divisor.Denominator;\n        remainder = new BigRational(ad % bc, bd);\n        return new BigRational(ad, bc);\n    }\n    public static BigInteger LeastCommonDenominator(BigRational x, BigRational y)\n    {\n        return x.Denominator * y.Denominator \/\n               BigInteger.GreatestCommonDivisor(x.Denominator, y.Denominator);\n    }\n    public static int Compare(BigRational r1, BigRational r2)\n    {\n        return BigInteger.Compare(r1.Numerator * r2.Denominator, r2.Numerator * r1.Denominator);\n    }\n    public static bool operator ==(BigRational x, BigRational y)\n    {\n        return Compare(x, y) == 0;\n    }\n    public static bool operator !=(BigRational x, BigRational y)\n    {\n        return Compare(x, y) != 0;\n    }\n    public static bool operator &lt;(BigRational x, BigRational y)\n    {\n        return Compare(x, y) &lt; 0;\n    }\n    public static bool operator &lt;=(BigRational x, BigRational y)\n    {\n        return Compare(x, y) &lt;= 0;\n    }\n    public static bool operator >(BigRational x, BigRational y)\n    {\n        return Compare(x, y) > 0;\n    }\n    public static bool operator >=(BigRational x, BigRational y)\n    {\n        return Compare(x, y) >= 0;\n    }\n    public static BigRational operator +(BigRational r)\n    {\n        return r;\n    }\n    public static BigRational operator -(BigRational r)\n    {\n        return new BigRational(-r.Numerator, r.Denominator);\n    }\n    public static BigRational operator ++(BigRational r)\n    {\n        return r + One;\n    }\n    public static BigRational operator --(BigRational r)\n    {\n        return r - One;\n    }\n    public static BigRational operator +(BigRational r1, BigRational r2)\n    {\n        return new BigRational(r1.Numerator * r2.Denominator + r1.Denominator * r2.Numerator,\n            r1.Denominator * r2.Denominator);\n    }\n    public static BigRational operator -(BigRational r1, BigRational r2)\n    {\n        return new BigRational(r1.Numerator * r2.Denominator - r1.Denominator * r2.Numerator,\n            r1.Denominator * r2.Denominator);\n    }\n    public static BigRational operator *(BigRational r1, BigRational r2)\n    {\n        return new BigRational(r1.Numerator * r2.Numerator, r1.Denominator * r2.Denominator);\n    }\n    public static BigRational operator \/(BigRational r1, BigRational r2)\n    {\n        return new BigRational(r1.Numerator * r2.Denominator, r1.Denominator * r2.Numerator);\n    }\n    public static BigRational operator %(BigRational r1, BigRational r2)\n    {\n        return new BigRational(r1.Numerator * r2.Denominator % (r1.Denominator * r2.Numerator),\n            r1.Denominator                                   * r2.Denominator);\n    }\n    public static explicit operator sbyte(BigRational value)\n    {\n        return (sbyte)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator ushort(BigRational value)\n    {\n        return (ushort)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator uint(BigRational value)\n    {\n        return (uint)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator ulong(BigRational value)\n    {\n        return (ulong)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator byte(BigRational value)\n    {\n        return (byte)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator short(BigRational value)\n    {\n        return (short)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator int(BigRational value)\n    {\n        return (int)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator long(BigRational value)\n    {\n        return (long)BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator BigInteger(BigRational value)\n    {\n        return BigInteger.Divide(value.Numerator, value.Denominator);\n    }\n    public static explicit operator float(BigRational value)\n    {\n        return (float)(double)value;\n    }\n    public static explicit operator double(BigRational value)\n    {\n        if (SafeCastToDouble(value.Numerator) &amp;&amp; SafeCastToDouble(value.Denominator))\n            return (double)value.Numerator \/ (double)value.Denominator;\n        var denormalized = value.Numerator * DoublePrecision \/ value.Denominator;\n        if (denormalized.IsZero)\n            return value.Sign &lt; 0\n                ? BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000))\n                : 0d;\n        double result   = 0;\n        var    isDouble = false;\n        var    scale    = DoubleMaxScale;\n        while (scale > 0)\n        {\n            if (!isDouble)\n                if (SafeCastToDouble(denormalized))\n                {\n                    result   = (double)denormalized;\n                    isDouble = true;\n                }\n                else\n                {\n                    denormalized = denormalized \/ 10;\n                }\n            result = result \/ 10;\n            scale--;\n        }\n        if (!isDouble)\n            return value.Sign &lt; 0 ? double.NegativeInfinity : double.PositiveInfinity;\n        return result;\n    }\n    public static explicit operator BigDecimal(BigRational value)\n    {\n        var denormalized = value.Numerator * DecimalPrecision \/ value.Denominator;\n        return new BigDecimal(denormalized, (int)DecimalMaxScale);\n    }\n    public static explicit operator decimal(BigRational value)\n    {\n        if (SafeCastToDecimal(value.Numerator) &amp;&amp; SafeCastToDecimal(value.Denominator))\n            return (decimal)value.Numerator \/ (decimal)value.Denominator;\n        var denormalized = value.Numerator * DecimalPrecision \/ value.Denominator;\n        if (denormalized.IsZero)\n            return decimal.Zero;\n        for (var scale = (int)DecimalMaxScale; scale >= 0; scale--)\n            if (!SafeCastToDecimal(denormalized))\n            {\n                denormalized \/= 10;\n            }\n            else\n            {\n                var dec = new DecimalUInt32();\n                dec.dec   = (decimal)denormalized;\n                dec.flags = (dec.flags &amp; ~DecimalScaleMask) | (scale &lt;&lt; 16);\n                return dec.dec;\n            }\n        throw new OverflowException();\n    }\n    public static implicit operator BigRational(sbyte value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(ushort value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(uint value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(ulong value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(byte value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(short value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(int value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(long value)\n    {\n        return new BigRational((BigInteger)value);\n    }\n    public static implicit operator BigRational(BigInteger value)\n    {\n        return new BigRational(value);\n    }\n    public static implicit operator BigRational(string value)\n    {\n        return new BigRational(value);\n    }\n    public static implicit operator BigRational(float value)\n    {\n        return new BigRational(value);\n    }\n    public static implicit operator BigRational(double value)\n    {\n        return new BigRational(value);\n    }\n    public static implicit operator BigRational(decimal value)\n    {\n        return new BigRational(value);\n    }\n    public static implicit operator BigRational(BigDecimal value)\n    {\n        return new BigRational(value);\n    }\n    private void Simplify()\n    {\n        if (Numerator == BigInteger.Zero)\n            Denominator = BigInteger.One;\n        var gcd = BigInteger.GreatestCommonDivisor(Numerator, Denominator);\n        if (gcd > BigInteger.One)\n        {\n            Numerator   = Numerator   \/ gcd;\n            Denominator = Denominator \/ gcd;\n        }\n    }\n    private static bool SafeCastToDouble(BigInteger value)\n    {\n        return DoubleMinValue &lt;= value &amp;&amp; value &lt;= DoubleMaxValue;\n    }\n    private static bool SafeCastToDecimal(BigInteger value)\n    {\n        return DecimalMinValue &lt;= value &amp;&amp; value &lt;= DecimalMaxValue;\n    }\n    private static void SplitDoubleIntoParts(double dbl,\n        out int                                     sign,\n        out int                                     exp,\n        out ulong                                   man,\n        out bool                                    isFinite)\n    {\n        DoubleUlong du;\n        du.uu  = 0;\n        du.dbl = dbl;\n        sign   = 1 - ((int)(du.uu >> 62) &amp; 2);\n        man    = du.uu              &amp; 0x000FFFFFFFFFFFFF;\n        exp    = (int)(du.uu >> 52) &amp; 0x7FF;\n        if (exp == 0)\n        {\n            isFinite = true;\n            if (man != 0)\n                exp = -1074;\n        }\n        else if (exp == 0x7FF)\n        {\n            isFinite = false;\n            exp      = int.MaxValue;\n        }\n        else\n        {\n            isFinite =  true;\n            man      |= 0x0010000000000000;\n            exp      -= 1075;\n        }\n    }\n    public static double GetDoubleFromParts(int sign, int exp, ulong man)\n    {\n        DoubleUlong du;\n        du.dbl = 0;\n        if (man == 0)\n        {\n            du.uu = 0;\n        }\n        else\n        {\n            var cbitShift = CbitHighZero(man) - 11;\n            if (cbitShift &lt; 0)\n                man >>= -cbitShift;\n            else\n                man &lt;&lt;= cbitShift;\n            exp += 1075;\n            if (exp >= 0x7FF)\n            {\n                du.uu = 0x7FF0000000000000;\n            }\n            else if (exp &lt;= 0)\n            {\n                exp--;\n                if (exp &lt; -52)\n                    du.uu = 0;\n                else\n                    du.uu = man >> -exp;\n            }\n            else\n            {\n                du.uu = (man &amp; 0x000FFFFFFFFFFFFF) | ((ulong)exp &lt;&lt; 52);\n            }\n        }\n        if (sign &lt; 0)\n            du.uu |= 0x8000000000000000;\n        return du.dbl;\n    }\n    private static int CbitHighZero(ulong uu)\n    {\n        if ((uu &amp; 0xFFFFFFFF00000000) == 0)\n            return 32 + CbitHighZero((uint)uu);\n        return CbitHighZero((uint)(uu >> 32));\n    }\n    private static int CbitHighZero(uint u)\n    {\n        if (u == 0)\n            return 32;\n        var cbit = 0;\n        if ((u &amp; 0xFFFF0000) == 0)\n        {\n            cbit +=  16;\n            u    &lt;&lt;= 16;\n        }\n        if ((u &amp; 0xFF000000) == 0)\n        {\n            cbit +=  8;\n            u    &lt;&lt;= 8;\n        }\n        if ((u &amp; 0xF0000000) == 0)\n        {\n            cbit +=  4;\n            u    &lt;&lt;= 4;\n        }\n        if ((u &amp; 0xC0000000) == 0)\n        {\n            cbit +=  2;\n            u    &lt;&lt;= 2;\n        }\n        if ((u &amp; 0x80000000) == 0)\n            cbit += 1;\n        return cbit;\n    }\n    private static (BigRational High, BigRational Low) SqrtLimits(BigInteger number)\n    {\n        if (number == BigInteger.Zero) return (0, 0);\n        var high = number >> 1;\n        var low  = BigInteger.Zero;\n        while (high > low + 1)\n        {\n            var n = (high + low) >> 1;\n            var p = n * n;\n            if (number &lt; p)\n                high = n;\n            else if (number > p)\n                low = n;\n            else\n                break;\n        }\n        return (high, low);\n    }\n    public static BigRational Sqrt(BigRational value)\n    {\n        if (value == 0) return 0;\n        var         hl = SqrtLimits(value.WholePart);\n        BigRational n  = 0, p = 0;\n        if (hl.High == 0 &amp;&amp; hl.Low == 0)\n            return 0;\n        var high = hl.High;\n        var low  = hl.Low;\n        var d    = DecimalPrecision;\n        var pp   = 1 \/ (BigRational)d;\n        while (high > low + pp)\n        {\n            n = (high + low) \/ 2;\n            p = n            * n;\n            if (value &lt; p)\n                high = n;\n            else if (value > p)\n                low = n;\n            else\n                break;\n        }\n        var r = value == p ? n : low;\n        return r;\n    }\n    public BigRational Sqrt()\n    {\n        return Sqrt(this);\n    }\n    public static BigRational ArcTangent(BigRational v, int n)\n    {\n        var retVal = v;\n        for (var i = 1; i &lt; n; i++)\n        {\n            var powRat = Pow(v, 2 * i + 1);\n            retVal += new BigRational(powRat.Numerator * (BigInteger)Math.Pow(-1d, i),\n                (2 * i + 1)                            * powRat.Denominator);\n        }\n        return retVal;\n    }\n    public static BigRational Reciprocal(BigRational v)\n    {\n        return new BigRational(v.Denominator, v.Numerator);\n    }\n    public static BigRational Round(BigRational number, int decimalPlaces)\n    {\n        BigRational power = BigInteger.Pow(10, decimalPlaces);\n        number *= power;\n        return number >= 0 ? (BigInteger)(number + 0.5) \/ power : (BigInteger)(number - 0.5) \/ power;\n    }\n    public void Round(int decimalPlaces)\n    {\n        var         number = this;\n        BigRational power  = BigInteger.Pow(10, decimalPlaces);\n        number *= power;\n        var n = number >= 0 ? (BigInteger)(number + 0.5) \/ power : (BigInteger)(number - 0.5) \/ power;\n        Numerator   = n.Numerator;\n        Denominator = n.Denominator;\n    }\n    public static BigRational Pow(BigRational v, int e)\n    {\n        if (e &lt; 1) throw new ArgumentException(\"Powers must be greater than or equal to one.\");\n        var retVal = new BigRational(v.Numerator, v.Denominator);\n        for (var i = 1; i &lt; e; i++)\n        {\n            retVal.Numerator   *= v.Numerator;\n            retVal.Denominator *= v.Denominator;\n        }\n        return retVal;\n    }\n    public static BigRational Min(BigRational r, BigRational l)\n    {\n        return l &lt; r ? l : r;\n    }\n    public static BigRational Max(BigRational r, BigRational l)\n    {\n        return l > r ? l : r;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Set Pi before call\n    \/\/\/ &lt;\/summary>\n    public static BigRational ToRadians(BigRational degrees)\n    {\n        return degrees * Pi \/ 180;\n    }\n    \/\/\/ &lt;summary>\n    \/\/\/     Set Pi before call\n    \/\/\/ &lt;\/summary>\n    public static BigRational ToDegrees(BigRational rads)\n    {\n        return rads * 180 \/ Pi;\n    }\n    private static BigRational Factorial(BigRational x)\n    {\n        BigRational r = 1;\n        BigRational c = 1;\n        while (c &lt;= x)\n        {\n            r *= c;\n            c++;\n        }\n        return r;\n    }\n    public static BigRational Exp(BigRational x)\n    {\n        BigRational r  = 0;\n        BigRational r1 = 0;\n        var         k  = 0;\n        while (true)\n        {\n            r += Pow(x, k) \/ Factorial(k);\n            if (r == r1)\n                break;\n            r1 = r;\n            k++;\n        }\n        return r;\n    }\n    public static BigRational Sine(BigRational ar, int n)\n    {\n        if (Factorials == null)\n        {\n            Factorials = new BigRational[MaxFactorials];\n            for (var i = 0; i &lt; MaxFactorials; i++)\n                Factorials[i] = new BigRational();\n            for (var i = 1; i &lt; MaxFactorials + 1; i++)\n                Factorials[i - 1] = Factorial(i);\n        }\n        var sin = ar;\n        for (var i = 1; i &lt;= n; i++)\n        {\n            var trm = Pow(ar, i * 2 + 1);\n            trm \/= Factorials[i * 2];\n            if ((i &amp; 1) == 1)\n                sin -= trm;\n            else\n                sin += trm;\n        }\n        return sin;\n    }\n    public static BigRational Atan(BigRational ar, int n)\n    {\n        var atan = ar;\n        for (var i = 1; i &lt;= n; i++)\n        {\n            var trm = Pow(ar, i * 2 + 1);\n            trm \/= i * 2;\n            if ((i &amp; 1) == 1)\n                atan -= trm;\n            else\n                atan += trm;\n        }\n        return atan;\n    }\n    public static BigRational Cosine(BigRational ar, int n)\n    {\n        if (Factorials == null)\n        {\n            Factorials = new BigRational[MaxFactorials];\n            for (var i = 0; i &lt; MaxFactorials; i++)\n                Factorials[i] = new BigRational();\n            for (var i = 1; i &lt; MaxFactorials + 1; i++)\n                Factorials[i - 1] = Factorial(i);\n        }\n        BigRational cos = 1.0;\n        for (var i = 1; i &lt;= n; i++)\n        {\n            var trm = Pow(ar, i * 2);\n            trm \/= Factorials[i * 2 - 1];\n            if ((i &amp; 1) == 1)\n                cos -= trm;\n            else\n                cos += trm;\n        }\n        return cos;\n    }\n    public static BigRational Tangent(BigRational ar, int n)\n    {\n        return Sine(ar, n) \/ Cosine(ar, n);\n    }\n    public static BigRational CoTangent(BigRational ar, int n)\n    {\n        return Cosine(ar, n) \/ Sine(ar, n);\n    }\n    public static BigRational Secant(BigRational ar, int n)\n    {\n        return 1.0 \/ Cosine(ar, n);\n    }\n    public static BigRational CoSecant(BigRational ar, int n)\n    {\n        return 1.0 \/ Sine(ar, n);\n    }\n    private static BigRational GetE(int n)\n    {\n        BigRational e = 1.0;\n        var         c = n;\n        while (c > 0)\n        {\n            BigRational f = 0;\n            if (c == 1)\n            {\n                f = 1;\n            }\n            else\n            {\n                var i = c - 1;\n                f = c;\n                while (i > 0)\n                {\n                    f *= i;\n                    i--;\n                }\n            }\n            c--;\n            e += 1.0 \/ f;\n        }\n        return e;\n    }\n    public static BigRational NthRoot(BigRational value, int nth)\n    {\n        BigRational lx;\n        var         a = value;\n        var         n = nth;\n        BigRational s = 1.0;\n        do\n        {\n            var t = s;\n            lx = a \/ Pow(s, n - 1);\n            var r = (n        - 1) * s;\n            s = (lx + r) \/ n;\n        } while (lx != s);\n        return s;\n    }\n    public static BigRational LogN(BigRational value)\n    {\n        BigRational a;\n        var         p = value;\n        BigRational n = 0.0;\n        while (p >= E)\n        {\n            p \/= E;\n            n++;\n        }\n        n += p \/ E;\n        p =  value;\n        do\n        {\n            a = n;\n            var lx = p         \/ Exp(n - 1.0);\n            var r  = (n - 1.0) * E;\n            n = (lx + r) \/ E;\n        } while (n != a);\n        return n;\n    }\n    public static BigRational Log(BigRational n, int b)\n    {\n        return LogN(n) \/ LogN(b);\n    }\n    private static int ConversionIterations(BigRational v)\n    {\n        return (int)((DecimalMaxScale + 1) \/ (2 * Math.Log10((double)Reciprocal(v))));\n    }\n    public static BigRational GetPI()\n    {\n        var oneFifth         = new BigRational(1, 5);\n        var oneTwoThirtyNine = new BigRational(1, 239);\n        var arcTanOneFifth   = ArcTangent(oneFifth, ConversionIterations(oneFifth));\n        var arcTanOneTwoThirtyNine =\n            ArcTangent(oneTwoThirtyNine, ConversionIterations(oneTwoThirtyNine));\n        return arcTanOneFifth * 16 - arcTanOneTwoThirtyNine * 4;\n    }\n    public override string ToString()\n    {\n        var ret = new StringBuilder();\n        ret.Append(Numerator.ToString(\"R\", CultureInfo.InvariantCulture));\n        ret.Append(Solidus);\n        ret.Append(Denominator.ToString(\"R\", CultureInfo.InvariantCulture));\n        return ret.ToString();\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>C# Arbitrary Precision Signed Big Rational Numbers Updated: Jun-11,2021<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[132,38,131,128],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/259"}],"collection":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/comments?post=259"}],"version-history":[{"count":3,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/259\/revisions"}],"predecessor-version":[{"id":439,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/259\/revisions\/439"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}