public void Dividing_3_values_is_the_same_as_dividing_by_the_product(Rational x, NonZeroRational y, NonZeroRational z) { Rational y_ = y, z_ = z; Assert.Equal(x / (y_ * z_), x / y_ / z_); Assert.Equal(Rational.Divide(x, Rational.Multiply(y_, z_)), Rational.Divide(Rational.Divide(x, y_), z_)); }
public void Division_is_the_same_as_multiplying_by_reciprocal(Rational x, NonZeroRational y) { var expected = x * y.Item.Invert(); Assert.Equal(expected, x / y); Assert.Equal(expected, Rational.Divide(x, y)); }
public void Case1() { Rational divisor = Math.Pow(Int64.MaxValue, 2); Rational[] dividends = { Rational.Multiply((Rational)Single.MaxValue, 2), Rational.Parse("90612345123875509091827560007100099"), Rational.One, Rational.Multiply(Int32.MaxValue, Int64.MaxValue), divisor + Rational.One }; // Divide each dividend by divisor in three different ways. foreach (Rational dividend in dividends) { Rational quotient; Rational remainder = 0; Console.WriteLine("Dividend: {0:N0}", dividend); Console.WriteLine("Divisor: {0:N0}", divisor); Console.WriteLine("Results:"); Console.WriteLine(" Using Divide method: {0:N0}", Rational.Divide(dividend, divisor)); Console.WriteLine(" Using Division operator: {0:N0}", dividend / divisor); (quotient, remainder) = Math.DivRem(dividend, divisor); Console.WriteLine(" Using DivRem method: {0:N0}, remainder {1:N0}", quotient, remainder); Console.WriteLine(); } }
static void Main(string[] args) { Console.WriteLine("Enter two integers (numerator and denominator): "); int num = int.Parse(Console.ReadLine()); int denom = int.Parse(Console.ReadLine()); var rationalOne = new Rational(); rationalOne.SetFraction(num, denom); Console.WriteLine("Enter two more integers: "); num = int.Parse(Console.ReadLine()); denom = int.Parse(Console.ReadLine()); var rationalTwo = new Rational(); rationalTwo.SetFraction(num, denom); Console.WriteLine("\nHow many digits to you want to display in past the decimal?"); int digits = int.Parse(Console.ReadLine()); Console.WriteLine("\nReduced first fraction: "); Console.WriteLine($"{rationalOne.ToRationalString()}"); Console.WriteLine("Reduced second fraction: "); Console.WriteLine($"{rationalTwo.ToRationalString()}"); Console.WriteLine($"Added rational numbers = {Rational.Add(rationalOne.ToFloat(), rationalTwo.ToFloat())}"); Console.WriteLine($"Subtracted rational numbers = {Rational.Subtract(rationalOne.ToFloat(), rationalTwo.ToFloat())}"); Console.WriteLine($"Multiplied rational numbers = {Rational.Multiply(rationalOne.ToFloat(), rationalTwo.ToFloat())}"); Console.WriteLine($"Divided rational numbers = {Rational.Divide(rationalOne.ToFloat(), rationalTwo.ToFloat())}"); Console.WriteLine("\nPress any key to end program."); Console.ReadKey(); }
internal override Rational Op(Rational lhs, Rational rhs) { return(lhs.Divide(rhs)); }
public void Dividing_with_NaN_returns_NaN(Rational x) { Assert.Equal(Rational.NaN, x / Rational.NaN); Assert.Equal(Rational.NaN, Rational.Divide(x, Rational.NaN)); }
public void Dividing_the_sum_is_the_same_as_dividing_each_and_then_adding_the_result(NonZeroRational x, Rational y, Rational z) { Assert.Equal((y + z) / x, (y / x) + (z / x)); Assert.Equal(Rational.Divide(Rational.Add(y, z), x), Rational.Add(Rational.Divide(y, x), Rational.Divide(z, x))); }
public void Cannot_divide_by_zero(Rational x) { Assert.Throws <DivideByZeroException>(() => x / Rational.Zero); Assert.Throws <DivideByZeroException>(() => Rational.Divide(x, Rational.Zero)); }
public void Divide_by_itself_returns_1(NonZeroRational x) { Assert.Equal(Rational.One, x.Item / x); Assert.Equal(Rational.One, Rational.Divide(x, x)); }
public void Divide_by_1_returns_the_same_value(Rational x) { Assert.Equal(x, x / Rational.One); Assert.Equal(x, Rational.Divide(x, Rational.One)); }
public static BigDecimal Log(int n, MathContext mc) { /* the value is undefined if x is negative. */ if (n <= 0) throw new ArithmeticException("Cannot take log of negative " + n); if (n == 1) return BigDecimal.Zero; if (n == 2) { if (mc.Precision < Log2.Precision) return Log2.Round(mc); /* Broadhurst <a href="http://arxiv.org/abs/math/9803067">arXiv:math/9803067</a> * Error propagation: the error in log(2) is twice the error in S(2,-5,...). */ int[] a = {2, -5, -2, -7, -2, -5, 2, -3}; BigDecimal S = BroadhurstBbp(2, 1, a, new MathContext(1 + mc.Precision)); S = S.Multiply(new BigDecimal(8)); S = Sqrt(DivideRound(S, 3)); return S.Round(mc); } if (n == 3) { /* summation of a series roughly proportional to (7/500)^k. Estimate count * of terms to estimate the precision (drop the favorable additional * 1/k here): 0.013^k <= 10^(-precision), so k*log10(0.013) <= -precision * so k>= precision/1.87. */ var kmax = (int) (mc.Precision/1.87); var mcloc = new MathContext(mc.Precision + 1 + (int) (System.Math.Log10(kmax*0.693/1.098))); BigDecimal log3 = MultiplyRound(Log(2, mcloc), 19); /* log3 is roughly 1, so absolute and relative error are the same. The * result will be divided by 12, so a conservative error is the one * already found in mc */ double eps = PrecisionToError(1.098, mc.Precision)/kmax; var r = new Rational(7153, 524288); var pk = new Rational(7153, 524288); for (int k = 1;; k++) { Rational tmp = pk.Divide(k); if (tmp.ToDouble() < eps) break; /* how many digits of tmp do we need in the sum? */ mcloc = new MathContext(ErrorToPrecision(tmp.ToDouble(), eps)); BigDecimal c = pk.Divide(k).ToBigDecimal(mcloc); if (k%2 != 0) log3 = log3.Add(c); else log3 = log3.Subtract(c); pk = pk.Multiply(r); } log3 = DivideRound(log3, 12); return log3.Round(mc); } if (n == 5) { /* summation of a series roughly proportional to (7/160)^k. Estimate count * of terms to estimate the precision (drop the favorable additional * 1/k here): 0.046^k <= 10^(-precision), so k*log10(0.046) <= -precision * so k>= precision/1.33. */ var kmax = (int) (mc.Precision/1.33); var mcloc = new MathContext(mc.Precision + 1 + (int) (System.Math.Log10(kmax*0.693/1.609))); BigDecimal log5 = MultiplyRound(Log(2, mcloc), 14); /* log5 is roughly 1.6, so absolute and relative error are the same. The * result will be divided by 6, so a conservative error is the one * already found in mc */ double eps = PrecisionToError(1.6, mc.Precision)/kmax; var r = new Rational(759, 16384); var pk = new Rational(759, 16384); for (int k = 1;; k++) { Rational tmp = pk.Divide(k); if (tmp.ToDouble() < eps) break; /* how many digits of tmp do we need in the sum? */ mcloc = new MathContext(ErrorToPrecision(tmp.ToDouble(), eps)); BigDecimal c = pk.Divide(k).ToBigDecimal(mcloc); log5 = log5.Subtract(c); pk = pk.Multiply(r); } log5 = DivideRound(log5, 6); return log5.Round(mc); } if (n == 7) { /* summation of a series roughly proportional to (1/8)^k. Estimate count * of terms to estimate the precision (drop the favorable additional * 1/k here): 0.125^k <= 10^(-precision), so k*log10(0.125) <= -precision * so k>= precision/0.903. */ var kmax = (int) (mc.Precision/0.903); var mcloc = new MathContext(mc.Precision + 1 + (int) (System.Math.Log10(kmax*3*0.693/1.098))); BigDecimal log7 = MultiplyRound(Log(2, mcloc), 3); /* log7 is roughly 1.9, so absolute and relative error are the same. */ double eps = PrecisionToError(1.9, mc.Precision)/kmax; var r = new Rational(1, 8); var pk = new Rational(1, 8); for (int k = 1;; k++) { Rational tmp = pk.Divide(k); if (tmp.ToDouble() < eps) break; /* how many digits of tmp do we need in the sum? */ mcloc = new MathContext(ErrorToPrecision(tmp.ToDouble(), eps)); BigDecimal c = pk.Divide(k).ToBigDecimal(mcloc); log7 = log7.Subtract(c); pk = pk.Multiply(r); } return log7.Round(mc); } else { /* At this point one could either forward to the log(BigDecimal) signature (implemented) * or decompose n into Ifactors and use an implemenation of all the prime bases. * Estimate of the result; convert the mc argument to an absolute error eps * log(n+errn) = log(n)+errn/n = log(n)+eps */ double res = System.Math.Log(n); double eps = PrecisionToError(res, mc.Precision); /* errn = eps*n, convert absolute error in result to requirement on absolute error in input */ eps *= n; /* Convert this absolute requirement of error in n to a relative error in n */ var mcloc = new MathContext(1 + ErrorToPrecision(n, eps)); /* Padd n with a number of zeros to trigger the required accuracy in * the standard signature method */ BigDecimal nb = ScalePrecision(new BigDecimal(n), mcloc); return Log(nb); } }
private static BigDecimal BroadhurstBbp(int n, int p, int[] a, MathContext mc) { /* Explore the actual magnitude of the result first with a quick estimate. */ double x = 0.0; for (int k = 1; k < 10; k++) x += a[(k - 1)%8]/System.Math.Pow(2d, p*(k + 1)/2d)/System.Math.Pow(k, n); /* Convert the relative precision and estimate of the result into an absolute precision. */ double eps = PrecisionToError(x, mc.Precision); /* Divide this through the number of terms in the sum to account for error accumulation * The divisor 2^(p(k+1)/2) means that on the average each 8th term in k has shrunk by * relative to the 8th predecessor by 1/2^(4p). 1/2^(4pc) = 10^(-precision) with c the 8term * cycles yields c=log_2( 10^precision)/4p = 3.3*precision/4p with k=8c */ var kmax = (int) (6.6*mc.Precision/p); /* Now eps is the absolute error in each term */ eps /= kmax; BigDecimal res = BigDecimal.Zero; for (int c = 0;; c++) { var r = new Rational(); for (int k = 0; k < 8; k++) { var tmp = new Rational(BigInteger.ValueOf(a[k]), (BigInteger.ValueOf((1 + 8*c + k))).Pow(n)); /* floor( (pk+p)/2) */ int pk1h = p*(2 + 8*c + k)/2; tmp = tmp.Divide(BigInteger.One.ShiftLeft(pk1h)); r = r.Add(tmp); } if (System.Math.Abs(r.ToDouble()) < eps) break; var mcloc = new MathContext(1 + ErrorToPrecision(r.ToDouble(), eps)); res = res.Add(r.ToBigDecimal(mcloc)); } return res.Round(mc); }
public static BigDecimal Zeta(int n, MathContext mc) { if (n <= 0) throw new NotSupportedException("Zeta at negative argument " + n + " not supported"); if (n == 1) throw new ArithmeticException("Pole at zeta(1) "); if (n%2 == 0) { /* Even indices. Abramowitz-Stegun 23.2.16. Start with 2^(n-1)*B(n)/n! */ Rational b = Bernoulli.Default[n].Abs(); b = b.Divide(Factorial.Default[n]); b = b.Multiply(BigInteger.One.ShiftLeft(n - 1)); /* to be multiplied by pi^n. Absolute error in the result of pi^n is n times * error in pi times pi^(n-1). Relative error is n*error(pi)/pi, requested by mc. * Need one more digit in pi if n=10, two digits if n=100 etc, and add one extra digit. */ var mcpi = new MathContext(mc.Precision + (int) (System.Math.Log10(10.0*n))); BigDecimal piton = PiRound(mcpi).Pow(n, mc); return MultiplyRound(piton, b); } if (n == 3) { /* Broadhurst BBP <a href="http://arxiv.org/abs/math/9803067">arXiv:math/9803067</a> * Error propagation: S31 is roughly 0.087, S33 roughly 0.131 */ int[] a31 = {1, -7, -1, 10, -1, -7, 1, 0}; int[] a33 = {1, 1, -1, -2, -1, 1, 1, 0}; BigDecimal S31 = BroadhurstBbp(3, 1, a31, mc); BigDecimal S33 = BroadhurstBbp(3, 3, a33, mc); S31 = S31.Multiply(new BigDecimal(48)); S33 = S33.Multiply(new BigDecimal(32)); return S31.Add(S33).Divide(new BigDecimal(7), mc); } if (n == 5) { /* Broadhurst BBP <a href=http://arxiv.org/abs/math/9803067">arXiv:math/9803067</a> * Error propagation: S51 is roughly -11.15, S53 roughly 22.165, S55 is roughly 0.031 * 9*2048*S51/6265 = -3.28. 7*2038*S53/61651= 5.07. 738*2048*S55/61651= 0.747. * The result is of the order 1.03, so we add 2 digits to S51 and S52 and one digit to S55. */ int[] a51 = {31, -1614, -31, -6212, -31, -1614, 31, 74552}; int[] a53 = {173, 284, -173, -457, -173, 284, 173, -111}; int[] a55 = {1, 0, -1, -1, -1, 0, 1, 1}; BigDecimal S51 = BroadhurstBbp(5, 1, a51, new MathContext(2 + mc.Precision)); BigDecimal S53 = BroadhurstBbp(5, 3, a53, new MathContext(2 + mc.Precision)); BigDecimal S55 = BroadhurstBbp(5, 5, a55, new MathContext(1 + mc.Precision)); S51 = S51.Multiply(new BigDecimal(18432)); S53 = S53.Multiply(new BigDecimal(14336)); S55 = S55.Multiply(new BigDecimal(1511424)); return S51.Add(S53).Subtract(S55).Divide(new BigDecimal(62651), mc); } /* Cohen et al Exp Math 1 (1) (1992) 25 */ var betsum = new Rational(); var bern = new Bernoulli(); var fact = new Factorial(); for (int npr = 0; npr <= (n + 1)/2; npr++) { Rational b = bern[2*npr].Multiply(bern[n + 1 - 2*npr]); b = b.Divide(fact[2*npr]).Divide(fact[n + 1 - 2*npr]); b = b.Multiply(1 - 2*npr); if (npr%2 == 0) betsum = betsum.Add(b); else betsum = betsum.Subtract(b); } betsum = betsum.Divide(n - 1); /* The first term, including the facor (2pi)^n, is essentially most * of the result, near one. The second term below is roughly in the range 0.003 to 0.009. * So the precision here is matching the precisionn requested by mc, and the precision * requested for 2*pi is in absolute terms adjusted. */ var mcloc = new MathContext(2 + mc.Precision + (int) (System.Math.Log10(n))); BigDecimal ftrm = PiRound(mcloc).Multiply(new BigDecimal(2)); ftrm = ftrm.Pow(n); ftrm = MultiplyRound(ftrm, betsum.ToBigDecimal(mcloc)); var exps = new BigDecimal(0); /* the basic accuracy of the accumulated terms before multiplication with 2 */ double eps = System.Math.Pow(10d, -mc.Precision); if (n%4 == 3) { /* since the argument n is at least 7 here, the drop * of the terms is at rather constant pace at least 10^-3, for example * 0.0018, 0.2e-7, 0.29e-11, 0.74e-15 etc for npr=1,2,3.... We want 2 times these terms * fall below eps/10. */ int kmax = mc.Precision/3; eps /= kmax; /* need an error of eps for 2/(exp(2pi)-1) = 0.0037 * The absolute error is 4*exp(2pi)*err(pi)/(exp(2pi)-1)^2=0.0075*err(pi) */ BigDecimal exp2p = PiRound(new MathContext(3 + ErrorToPrecision(3.14, eps/0.0075))); exp2p = Exp(exp2p.Multiply(new BigDecimal(2))); BigDecimal c = exp2p.Subtract(BigDecimal.One); exps = DivideRound(1, c); for (int npr = 2; npr <= kmax; npr++) { /* the error estimate above for npr=1 is the worst case of * the absolute error created by an error in 2pi. So we can * safely re-use the exp2p value computed above without * reassessment of its error. */ c = PowRound(exp2p, npr).Subtract(BigDecimal.One); c = MultiplyRound(c, (BigInteger.ValueOf(npr)).Pow(n)); c = DivideRound(1, c); exps = exps.Add(c); } } else { /* since the argument n is at least 9 here, the drop * of the terms is at rather constant pace at least 10^-3, for example * 0.0096, 0.5e-7, 0.3e-11, 0.6e-15 etc. We want these terms * fall below eps/10. */ int kmax = (1 + mc.Precision)/3; eps /= kmax; /* need an error of eps for 2/(exp(2pi)-1)*(1+4*Pi/8/(1-exp(-2pi)) = 0.0096 * at k=7 or = 0.00766 at k=13 for example. * The absolute error is 0.017*err(pi) at k=9, 0.013*err(pi) at k=13, 0.012 at k=17 */ BigDecimal twop = PiRound(new MathContext(3 + ErrorToPrecision(3.14, eps/0.017))); twop = twop.Multiply(new BigDecimal(2)); BigDecimal exp2p = Exp(twop); BigDecimal c = exp2p.Subtract(BigDecimal.One); exps = DivideRound(1, c); c = BigDecimal.One.Subtract(DivideRound(1, exp2p)); c = DivideRound(twop, c).Multiply(new BigDecimal(2)); c = DivideRound(c, n - 1).Add(BigDecimal.One); exps = MultiplyRound(exps, c); for (int npr = 2; npr <= kmax; npr++) { c = PowRound(exp2p, npr).Subtract(BigDecimal.One); c = MultiplyRound(c, (BigInteger.ValueOf(npr)).Pow(n)); BigDecimal d = DivideRound(1, exp2p.Pow(npr)); d = BigDecimal.One.Subtract(d); d = DivideRound(twop, d).Multiply(new BigDecimal(2*npr)); d = DivideRound(d, n - 1).Add(BigDecimal.One); d = DivideRound(d, c); exps = exps.Add(d); } } exps = exps.Multiply(new BigDecimal(2)); return ftrm.Subtract(exps, mc); }
public void Case1() { Rational divisor = Math.Pow(Int64.MaxValue, 2); Rational[] dividends = { Rational.Multiply((Rational)Single.MaxValue, 2), Rational.Parse("90612345123875509091827560007100099"), Rational.One, Rational.Multiply(Int32.MaxValue, Int64.MaxValue), divisor + Rational.One }; // Divide each dividend by divisor in three different ways. foreach (Rational dividend in dividends) { Rational quotient; Rational remainder = 0; Console.WriteLine("Dividend: {0:N0}", dividend); Console.WriteLine("Divisor: {0:N0}", divisor); Console.WriteLine("Results:"); Console.WriteLine(" Using Divide method: {0:N10}", Rational.Divide(dividend, divisor)); Console.WriteLine(" Using Division operator: {0:N10}", dividend / divisor); (quotient, remainder) = Math.DivRem(dividend, divisor); Console.WriteLine(" Using DivRem method: {0:N10}, remainder {0:N10}", quotient, remainder); Console.WriteLine(); } //TODO:680,564,693,277,057,719,623,408,366,969,033,850,880/85,070,591,730,234,615,847,396,907,784,232,501,249の結果をラウンドした時に繰り上がってしまう // The example displays the following output: // Dividend: 680,564,693,277,057,719,623,408,366,969,033,850,880 // Divisor: 85,070,591,730,234,615,847,396,907,784,232,501,249 // Results: // Using Divide method: 7 // Using Division operator: 7 // Using DivRem method: 7, remainder 85,070,551,165,415,408,691,630,012,479,406,342,137 // // Dividend: 90,612,345,123,875,509,091,827,560,007,100,099 // Divisor: 85,070,591,730,234,615,847,396,907,784,232,501,249 // Results: // Using Divide method: 0 // Using Division operator: 0 // Using DivRem method: 0, remainder 90,612,345,123,875,509,091,827,560,007,100,099 // // Dividend: 1 // Divisor: 85,070,591,730,234,615,847,396,907,784,232,501,249 // Results: // Using Divide method: 0 // Using Division operator: 0 // Using DivRem method: 0, remainder 1 // // Dividend: 19,807,040,619,342,712,359,383,728,129 // Divisor: 85,070,591,730,234,615,847,396,907,784,232,501,249 // Results: // Using Divide method: 0 // Using Division operator: 0 // Using DivRem method: 0, remainder 19,807,040,619,342,712,359,383,728,129 // // Dividend: 85,070,591,730,234,615,847,396,907,784,232,501,250 // Divisor: 85,070,591,730,234,615,847,396,907,784,232,501,249 // Results: // Using Divide method: 1 // Using Division operator: 1 // Using DivRem method: 1, remainder 1 }