static private void SetFromHexString(BigNumber atm, String hexvalue) { int length = hexvalue.Length - 1; BigNumber CurValue = new BigNumber(); BigNumber.SetZero(CurValue); BigNumber CurDigitBaseValue = 1; InitializehexLookup(); try { while (length >= 0) { char digit = hexvalue[length]; int value = (int)hexLookup[digit]; CurValue += (CurDigitBaseValue * value); CurDigitBaseValue *= 16; length--; } BigNumber.Copy(CurValue, atm); } catch { // illegal input string throw new BigNumberException("illegal input string"); } }
static public void Round(BigNumber src, BigNumber dst, int places) { BigNumber t0_5 = new BigNumber(); BigNumber.Copy(Five, t0_5); int ii = places + 1; if (src.dataLength <= ii) { Copy(src, dst); return; } t0_5.exponent = src.exponent - ii; if (src.signum > 0) { BigNumber.Add(src, t0_5, dst); } else { BigNumber.Sub(src, t0_5, dst); } dst.dataLength = ii; BigNumber.Normalize(dst); }
/// <summary> /// get absolute value of number /// </summary> /// <param name="d"></param> /// <param name="s"></param> static void Abs(BigNumber d, BigNumber s) { BigNumber.Copy(s, d); if (d.signum != 0) { d.signum = 1; } }
static void Neg(BigNumber s, BigNumber d) { BigNumber.Copy(s, d); if (d.signum != 0) { d.signum = (sbyte)-(d.signum); } }
static public void Power(BigNumber xx, BigNumber yy, BigNumber rr, int places) { int iflag; BigNumber tmp8 = new BigNumber(); BigNumber tmp9 = new BigNumber(); int M_size_flag = BigNumber.GetSizeofInt(); if (yy.signum == 0) { BigNumber.Copy(BigNumber.One, rr); return; } if (xx.signum == 0) { BigNumber.SetZero(rr); return; } if (BigNumber.IsInteger(yy) > 0) { iflag = 0; if (M_size_flag == 2) /* 16 bit compilers */ { if (yy.exponent <= 4) { iflag = 1; } } else /* >= 32 bit compilers */ { if (yy.exponent <= 7) { iflag = 1; } } if (iflag > 0) { String sbuf = BigNumber.ToIntString(yy); int Exp = Convert.ToInt32(sbuf); BigNumber.IntPow(places, xx, Exp, rr); return; } } tmp8 = new BigNumber(); tmp9 = new BigNumber(); BigNumber.Log(xx, tmp9, (places + 8)); BigNumber.Mul(tmp9, yy, tmp8); BigNumber.Exp(tmp8, rr, places); }
/****************************************************************************/ /* * Calculate PI using the AGM (Arithmetic-Geometric Mean) * * Init : A0 = 1 * B0 = 1 / sqrt(2) * Sum = 1 * * Iterate: n = 1... * * * A = 0.5 * [ A + B ] * n n-1 n-1 * * * B = sqrt [ A * B ] * n n-1 n-1 * * * C = 0.5 * [ A - B ] * n n-1 n-1 * * * 2 n+1 * Sum = Sum - C * 2 * n * * * At the end when C is 'small enough' : * n * * 2 * PI = 4 * A / Sum * n+1 * * -OR- * * 2 * PI = ( A + B ) / Sum * n n * */ static private void CalculatePiAGM(BigNumber outv, int places) { int dplaces, nn; BigNumber tmp1 = new BigNumber(); BigNumber tmp2 = new BigNumber(); BigNumber a0 = new BigNumber(); BigNumber b0 = new BigNumber(); BigNumber c0 = new BigNumber(); BigNumber a1 = new BigNumber(); BigNumber b1 = new BigNumber(); BigNumber sum = new BigNumber(); BigNumber pow_2 = new BigNumber(); dplaces = places + 16; BigNumber.Copy(BigNumber.One, a0); BigNumber.Copy(BigNumber.One, sum); BigNumber.Copy(BigNumber.Four, pow_2); BigNumber.Sqrt(BigNumber.BN_OneHalf, b0, dplaces); while (true) { BigNumber.Add(a0, b0, tmp1); BigNumber.Mul(tmp1, BigNumber.BN_OneHalf, a1); BigNumber.Mul(a0, b0, tmp1); BigNumber.Sqrt(tmp1, b1, dplaces); BigNumber.Sub(a0, b0, tmp1); BigNumber.Mul(BigNumber.BN_OneHalf, tmp1, c0); BigNumber.Mul(c0, c0, tmp1); BigNumber.Mul(tmp1, pow_2, tmp2); BigNumber.Sub(sum, tmp2, tmp1); BigNumber.Round(tmp1, sum, dplaces); nn = -4 * c0.exponent; if (nn >= dplaces) { break; } BigNumber.Copy(a1, a0); BigNumber.Copy(b1, b0); BigNumber.Mul(pow_2, BigNumber.Two, tmp1); BigNumber.Copy(tmp1, pow_2); } BigNumber.Add(a1, b1, tmp1); BigNumber.Mul(tmp1, tmp1, tmp2); BigNumber.Div(tmp2, sum, tmp1, dplaces); BigNumber.Round(tmp1, outv, places); }
/****************************************************************************/ /* * calculate log (1 + x) with the following series: * * x * y = ----- ( |y| < 1 ) * x + 2 * * * [ 1 + y ] y^3 y^5 y^7 * log [-------] = 2 * [ y + --- + --- + --- ... ] * [ 1 - y ] 3 5 7 * */ static void M_log_near_1(BigNumber xx, BigNumber rr, int places) { BigNumber tmp0, tmp1, tmp2, tmpS, term; int tolerance, dplaces, local_precision; long m1; tmp0 = new BigNumber(); tmp1 = new BigNumber(); tmp2 = new BigNumber(); tmpS = new BigNumber(); term = new BigNumber(); tolerance = xx.exponent - (places + 6); dplaces = (places + 12) - xx.exponent; BigNumber.Add(xx, BigNumber.Two, tmp0); BigNumber.Div(xx, tmp0, tmpS, (dplaces + 6)); BigNumber.Copy(tmpS, term); BigNumber.Mul(tmpS, tmpS, tmp0); BigNumber.Round(tmp0, tmp2, (dplaces + 6)); m1 = 3L; while (true) { BigNumber.Mul(term, tmp2, tmp0); if ((tmp0.exponent < tolerance) || (tmp0.signum == 0)) { break; } local_precision = dplaces + tmp0.exponent; if (local_precision < 20) { local_precision = 20; } BigNumber.SetFromLong(tmp1, m1); BigNumber.Round(tmp0, term, local_precision); BigNumber.Div(term, tmp1, tmp0, local_precision); BigNumber.Add(tmpS, tmp0, tmp1); BigNumber.Copy(tmp1, tmpS); m1 += 2; } BigNumber.Mul(BigNumber.Two, tmpS, tmp0); BigNumber.Round(tmp0, rr, places); }
static private void FastMul(BigNumber aa, BigNumber bb, BigNumber rr) { int ii, k, nexp, sign; BigNumber M_ain = new BigNumber(); BigNumber M_bin = new BigNumber(); BigNumber.Copy(aa, M_ain); BigNumber.Copy(bb, M_bin); int size_flag = GetSizeofInt(); int bit_limit = 8 * size_flag + 1; sign = M_ain.signum * M_bin.signum; nexp = M_ain.exponent + M_bin.exponent; if (M_ain.dataLength >= M_bin.dataLength) { ii = M_ain.dataLength; } else { ii = M_bin.dataLength; } ii = (ii + 1) >> 1; ii = NextPowerOfTwo(ii); k = 2 * ii; /* required size of result, in bytes */ BigNumber.Pad(M_ain, k); /* fill out the data so the number of */ BigNumber.Pad(M_bin, k); /* bytes is an exact power of 2 */ if (k > rr.mantissa.Length) { BigNumber.Expand(rr, (k + 32)); } BigNumber.FastMulFFT(rr.mantissa, M_ain.mantissa, M_bin.mantissa, ii); rr.signum = (sbyte)sign; rr.exponent = nexp; rr.dataLength = 4 * ii; BigNumber.Normalize(rr); }
static private void M_raw_exp(BigNumber xx, BigNumber rr, int places) { BigNumber tmp0, digit, term; int tolerance, local_precision, prev_exp; long m1; tmp0 = new BigNumber(); term = new BigNumber(); digit = new BigNumber(); local_precision = places + 8; tolerance = -(places + 4); prev_exp = 0; BigNumber.Add(BigNumber.One, xx, rr); BigNumber.Copy(xx, term); m1 = 2L; while (true) { BigNumber.SetFromLong(digit, m1); BigNumber.Mul(term, xx, tmp0); BigNumber.Div(tmp0, digit, term, local_precision); BigNumber.Add(rr, term, tmp0); BigNumber.Copy(tmp0, rr); if ((term.exponent < tolerance) || (term.signum == 0)) { break; } if (m1 != 2L) { local_precision = local_precision + term.exponent - prev_exp; if (local_precision < 20) { local_precision = 20; } } prev_exp = term.exponent; m1++; } }
static void Floor(BigNumber dst, BigNumber src) { BigNumber.Copy(src, dst); if (BigNumber.IsInteger(dst) > 0) { return; } if (dst.exponent <= 0) /* if |bb| < 1, result is -1 or 0 */ { if (dst.signum < 0) { BigNumber.Neg(BigNumber.One, dst); } else { BigNumber.SetZero(dst); } return; } if (dst.signum < 0) { BigNumber mtmp = new BigNumber(); BigNumber.Neg(dst, mtmp); mtmp.dataLength = mtmp.exponent; BigNumber.Normalize(mtmp); BigNumber.Add(mtmp, BigNumber.One, dst); dst.signum = -1; } else { dst.dataLength = dst.exponent; BigNumber.Normalize(dst); } }
static void Ceil(BigNumber dst, BigNumber src) { BigNumber mtmp; BigNumber.Copy(src, dst); if (IsInteger(dst) > 0) /* if integer, we're done */ { return; } if (dst.exponent <= 0) /* if |bb| < 1, result is 0 or 1 */ { if (dst.signum < 0) { BigNumber.SetZero(dst); } else { BigNumber.Copy(BigNumber.One, dst); } return; } if (dst.signum < 0) { dst.dataLength = dst.exponent; BigNumber.Normalize(dst); } else { mtmp = new BigNumber(); BigNumber.Copy(dst, mtmp); mtmp.dataLength = mtmp.exponent; BigNumber.Normalize(mtmp); BigNumber.Add(mtmp, BigNumber.One, dst); } }
static void CheckLogPlaces(int places) { BigNumber tmp6, tmp7, tmp8, tmp9; int dplaces; dplaces = places + 4; if (dplaces > MM_lc_log_digits) { MM_lc_log_digits = dplaces + 4; tmp6 = new BigNumber(); tmp7 = new BigNumber(); tmp8 = new BigNumber(); tmp9 = new BigNumber(); dplaces += 6 + (int)Math.Log10((double)places); BigNumber.Copy(BigNumber.One, tmp7); tmp7.exponent = -places; BigNumber.LogAGMRFunc(BigNumber.One, tmp7, tmp8, dplaces); BigNumber.Mul(tmp7, BigNumber.BN_OneHalf, tmp6); BigNumber.LogAGMRFunc(BigNumber.One, tmp6, tmp9, dplaces); BigNumber.Sub(tmp9, tmp8, BN_lc_log2); tmp7.exponent -= 1; BigNumber.LogAGMRFunc(BigNumber.One, tmp7, tmp9, dplaces); BigNumber.Sub(tmp9, tmp8, BN_lc_log10); BigNumber.Reziprocal(BN_lc_log10R, BN_lc_log10, dplaces); } }
public BigNumber(BigNumber rh) { BigNumber.Copy(rh, this); }
/****************************************************************************/ /* * define a notation for a function 'R' : * * * * 1 * R (a0, b0) = ------------------------------ * * ---- * \ * \ n-1 2 2 * 1 - | 2 * (a - b ) * / n n * / * ---- * n >= 0 * * * where a, b are the classic AGM iteration : * * * a = 0.5 * (a + b ) * n+1 n n * * * b = sqrt(a * b ) * n+1 n n * * * * define a variable 'c' for more efficient computation : * * 2 2 2 * c = 0.5 * (a - b ) , c = a - b * n+1 n n n n n * */ /****************************************************************************/ static void LogAGMRFunc(BigNumber aa, BigNumber bb, BigNumber rr, int places) { BigNumber tmp1, tmp2, tmp3, tmp4, tmpC2, sum, pow_2, tmpA0, tmpB0; int tolerance, dplaces; tmpA0 = new BigNumber(); tmpB0 = new BigNumber(); tmpC2 = new BigNumber(); tmp1 = new BigNumber(); tmp2 = new BigNumber(); tmp3 = new BigNumber(); tmp4 = new BigNumber(); sum = new BigNumber(); pow_2 = new BigNumber(); tolerance = places + 8; dplaces = places + 16; BigNumber.Copy(aa, tmpA0); BigNumber.Copy(bb, tmpB0); BigNumber.Copy(BigNumber.BN_OneHalf, pow_2); BigNumber.Mul(aa, aa, tmp1); /* 0.5 * [ a ^ 2 - b ^ 2 ] */ BigNumber.Mul(bb, bb, tmp2); BigNumber.Sub(tmp1, tmp2, tmp3); BigNumber.Mul(BigNumber.BN_OneHalf, tmp3, sum); while (true) { BigNumber.Sub(tmpA0, tmpB0, tmp1); /* C n+1 = 0.5 * [ An - Bn ] */ BigNumber.Mul(BigNumber.BN_OneHalf, tmp1, tmp4); /* C n+1 */ BigNumber.Mul(tmp4, tmp4, tmpC2); /* C n+1 ^ 2 */ /* do the AGM */ BigNumber.Add(tmpA0, tmpB0, tmp1); BigNumber.Mul(BigNumber.BN_OneHalf, tmp1, tmp3); BigNumber.Mul(tmpA0, tmpB0, tmp2); BigNumber.Sqrt(tmp2, tmpB0, dplaces); BigNumber.Round(tmp3, tmpA0, dplaces); /* end AGM */ BigNumber.Mul(BigNumber.Two, pow_2, tmp2); BigNumber.Copy(tmp2, pow_2); BigNumber.Mul(tmpC2, pow_2, tmp1); BigNumber.Add(sum, tmp1, tmp3); if ((tmp1.signum == 0) || ((-2 * tmp1.exponent) > tolerance)) { break; } BigNumber.Round(tmp3, sum, dplaces); } BigNumber.Sub(BigNumber.One, tmp3, tmp4); BigNumber.Reziprocal(tmp4, rr, places); }
static void Log(BigNumber src, BigNumber dst, int places) { BigNumber tmp0, tmp1, tmp2; int mexp, dplaces; if (src.signum <= 0) { throw new BigNumberException(" 'Log', Negative argument"); } tmp0 = new BigNumber(); tmp1 = new BigNumber(); tmp2 = new BigNumber(); dplaces = places + 8; mexp = src.exponent; if (mexp == 0 || mexp == 1) { BigNumber.Sub(src, BigNumber.One, tmp0); if (tmp0.signum == 0) /* is input exactly 1 ?? */ { /* if so, result is 0 */ BigNumber.SetZero(dst); return; } if (tmp0.exponent <= -4) { M_log_near_1(tmp0, dst, places); return; } } /* make sure our log(10) is accurate enough for this calculation */ /* (and log(2) which is called from M_log_basic_iteration) */ BigNumber.CheckLogPlaces(dplaces + 25); if (Math.Abs(mexp) <= 3) { M_log_basic_iteration(src, dst, places); } else { /* * use log (x * y) = log(x) + log(y) * * here we use y = exponent of our base 10 number. * * let 'C' = log(10) = 2.3025850929940.... * * then log(x * y) = log(x) + ( C * base_10_exponent ) */ BigNumber.Copy(src, tmp2); mexp = tmp2.exponent - 2; tmp2.exponent = 2; M_log_basic_iteration(tmp2, tmp0, dplaces); BigNumber.SetFromLong(tmp1, (long)mexp); BigNumber.Mul(tmp1, BN_lc_log10, tmp2); BigNumber.Add(tmp2, tmp0, tmp1); BigNumber.Round(tmp1, dst, places); } }
static private void IntPow(int places, BigNumber src, int mexp, BigNumber dst) { BigNumber A, B, C; int nexp, ii, signflag, local_precision; if (mexp == 0) { BigNumber.Copy(BigNumber.One, dst); return; } else { if (mexp > 0) { signflag = 0; nexp = mexp; } else { signflag = 1; nexp = -mexp; } } if (src.signum == 0) { BigNumber.SetZero(dst); return; } A = new BigNumber(); B = new BigNumber(); C = new BigNumber(); local_precision = places + 8; BigNumber.Copy(BigNumber.One, B); BigNumber.Copy(src, C); while (true) { ii = nexp & 1; nexp = nexp >> 1; if (ii != 0) /* exponent -was- odd */ { BigNumber.Mul(B, C, A); BigNumber.Round(A, B, local_precision); if (nexp == 0) { break; } } BigNumber.Mul(C, C, A); BigNumber.Round(A, C, local_precision); } if (signflag > 0) { BigNumber.Reziprocal(B, dst, places); } else { BigNumber.Round(B, dst, places); } }
static public void Sub(BigNumber src, BigNumber dst, BigNumber result) { int itmp, j, ChangeOrderFlag, icompare, aexp, bexp, borrow, adigits, bdigits; sbyte sign; BigNumber A = 0, B = 0; if (dst.signum == 0) { BigNumber.Copy(src, result); return; } if (src.signum == 0) { BigNumber.Copy(dst.Neg(), result); return; } if (src.signum == 1 && dst.signum == -1) { dst.signum = 1; Add(src, dst, result); dst.signum = -1; return; } if (src.signum == -1 && dst.signum == 1) { dst.signum = -1; Add(src, dst, result); dst.signum = 1; return; } BigNumber.Abs(A, src); BigNumber.Abs(B, dst); if ((icompare = Compare(A, B)) == 0) { SetZero(result); return; } if (icompare == 1) /* |a| > |b| (do A-B) */ { ChangeOrderFlag = 1; sign = src.signum; } else /* |b| > |a| (do B-A) */ { ChangeOrderFlag = 0; sign = (sbyte)-(src.signum); } aexp = A.exponent; bexp = B.exponent; if (aexp > bexp) { Scale(B, (aexp - bexp)); } if (aexp < bexp) { Scale(A, (bexp - aexp)); } adigits = A.dataLength; bdigits = B.dataLength; if (adigits > bdigits) { Pad(B, adigits); } if (adigits < bdigits) { Pad(A, bdigits); } if (ChangeOrderFlag == 1) // |a| > |b| (do A-B) { Copy(A, result); j = (result.dataLength + 1) >> 1; borrow = 0; while (true) { j--; itmp = ((int)result.mantissa[j] - ((int)B.mantissa[j] + borrow)); if (itmp >= 0) { result.mantissa[j] = (byte)itmp; borrow = 0; } else { result.mantissa[j] = (byte)(100 + itmp); borrow = 1; } if (j == 0) { break; } } } else // |b| > |a| (do B-A) instead { Copy(B, result); j = (result.dataLength + 1) >> 1; borrow = 0; while (true) { j--; itmp = (int)result.mantissa[j] - ((int)A.mantissa[j] + borrow); if (itmp >= 0) { result.mantissa[j] = (byte)itmp; borrow = 0; } else { result.mantissa[j] = (byte)(100 + itmp); borrow = 1; } if (j == 0) { break; } } } result.signum = sign; BigNumber.Normalize(result); }
static void Sqrt(BigNumber src, BigNumber dst, int places) { int ii, nexp, tolerance, dplaces; bool bflag; if (src.signum <= 0) { if (src.signum == -1) { throw new BigNumberException("'Sqrt',Invalid Argument"); } } BigNumber last_x = new BigNumber(); BigNumber guess = new BigNumber(); BigNumber tmpN = new BigNumber(); BigNumber tmp7 = new BigNumber(); BigNumber tmp8 = new BigNumber(); BigNumber tmp9 = new BigNumber(); BigNumber.Copy(src, tmpN); nexp = src.exponent / 2; tmpN.exponent -= 2 * nexp; BigNumber.SQrtGuess(tmpN, guess); tolerance = places + 4; dplaces = places + 16; bflag = false; BigNumber.Neg(BigNumber.Ten, last_x); ii = 0; while (true) { BigNumber.Mul(tmpN, guess, tmp9); BigNumber.Mul(tmp9, guess, tmp8); BigNumber.Round(tmp8, tmp7, dplaces); BigNumber.Sub(BigNumber.Three, tmp7, tmp9); BigNumber.Mul(tmp9, guess, tmp8); BigNumber.Mul(tmp8, BigNumber.BN_OneHalf, tmp9); if (bflag) { break; } BigNumber.Round(tmp9, guess, dplaces); if (ii != 0) { BigNumber.Sub(guess, last_x, tmp7); if (tmp7.signum == 0) { break; } /* * if we are within a factor of 4 on the error term, * we will be accurate enough after the *next* iteration * is complete. (note that the sign of the exponent on * the error term will be a negative number). */ if ((-4 * tmp7.exponent) > tolerance) { bflag = true; } } BigNumber.Copy(guess, last_x); ii++; } BigNumber.Mul(tmp9, tmpN, tmp8); BigNumber.Round(tmp8, dst, places); dst.exponent += nexp; }
static private void Exp(BigNumber src, BigNumber dst, int places) { BigNumber A = 0, B = 0, C = 0; int dplaces, nn = 0, ii = 0; if (src.signum == 0) { BigNumber.Copy(BigNumber.One, dst); return; } if (src.exponent <= -3) { M_raw_exp(src, C, (places + 6)); BigNumber.Round(C, dst, places); return; } if (M_exp_compute_nn(ref nn, A, src) != 0) { throw new BigNumberException("'Exp', Input too large, Overflow"); } dplaces = places + 8; BigNumber.CheckLogPlaces(dplaces); BigNumber.Mul(A, BN_lc_log2, B); BigNumber.Sub(src, B, A); while (true) { if (A.signum != 0) { if (A.exponent == 0) { break; } } if (A.signum >= 0) { nn++; BigNumber.Sub(A, BN_lc_log2, B); BigNumber.Copy(B, A); } else { nn--; BigNumber.Add(A, BN_lc_log2, B); BigNumber.Copy(B, A); } } BigNumber.Mul(A, BN_exp_512R, C); M_raw_exp(C, B, dplaces); ii = 9; while (true) { BigNumber.Mul(B, B, C); BigNumber.Round(C, B, dplaces); if (--ii == 0) { break; } } BigNumber.IntPow(dplaces, BigNumber.Two, nn, A); BigNumber.Mul(A, B, C); BigNumber.Round(C, dst, places); }
static private void Div(BigNumber aa, BigNumber bb, BigNumber rr, int places) { int j, k, m, b0, nexp, indexr, icompare, iterations; sbyte sign; long trial_numer; BigNumber M_div_worka = new BigNumber(); BigNumber M_div_workb = new BigNumber(); BigNumber M_div_tmp7 = new BigNumber(); BigNumber M_div_tmp8 = new BigNumber(); BigNumber M_div_tmp9 = new BigNumber(); sign = (sbyte)(aa.signum * bb.signum); if (sign == 0) /* one number is zero, result is zero */ { if (bb.signum == 0) { throw new BigNumberException("Division by Zero"); } BigNumber.SetZero(rr); return; } if (bb.mantissa[0] >= 50) { BigNumber.Abs(M_div_worka, aa); BigNumber.Abs(M_div_workb, bb); } else /* 'normal' step D1 */ { k = 100 / (bb.mantissa[0] + 1); BigNumber.SetFromLong(M_div_tmp9, (long)k); BigNumber.Mul(M_div_tmp9, aa, M_div_worka); BigNumber.Mul(M_div_tmp9, bb, M_div_workb); M_div_worka.signum = 1; M_div_workb.signum = 1; } b0 = 100 * (int)M_div_workb.mantissa[0]; if (M_div_workb.dataLength >= 3) { b0 += M_div_workb.mantissa[1]; } nexp = M_div_worka.exponent - M_div_workb.exponent; if (nexp > 0) { iterations = nexp + places + 1; } else { iterations = places + 1; } k = (iterations + 1) >> 1; /* required size of result, in bytes */ if (k > rr.mantissa.Length) { BigNumber.Expand(rr, k + 32); } /* clear the exponent in the working copies */ M_div_worka.exponent = 0; M_div_workb.exponent = 0; /* if numbers are equal, ratio == 1.00000... */ if ((icompare = BigNumber.Compare(M_div_worka, M_div_workb)) == 0) { iterations = 1; rr.mantissa[0] = 10; nexp++; } else /* ratio not 1, do the real division */ { if (icompare == 1) /* numerator > denominator */ { nexp++; /* to adjust the final exponent */ M_div_worka.exponent += 1; /* multiply numerator by 10 */ } else /* numerator < denominator */ { M_div_worka.exponent += 2; /* multiply numerator by 100 */ } indexr = 0; m = 0; while (true) { /* * Knuth step D3. Only use the 3rd -> 6th digits if the number * actually has that many digits. */ trial_numer = 10000L * (long)M_div_worka.mantissa[0]; if (M_div_worka.dataLength >= 5) { trial_numer += 100 * M_div_worka.mantissa[1] + M_div_worka.mantissa[2]; } else { if (M_div_worka.dataLength >= 3) { trial_numer += 100 * M_div_worka.mantissa[1]; } } j = (int)(trial_numer / b0); /* * Since the library 'normalizes' all the results, we need * to look at the exponent of the number to decide if we * have a lead in 0n or 00. */ if ((k = 2 - M_div_worka.exponent) > 0) { while (true) { j /= 10; if (--k == 0) { break; } } } if (j == 100) /* qhat == base ?? */ { j = 99; /* if so, decrease by 1 */ } BigNumber.SetFromLong(M_div_tmp8, (long)j); BigNumber.Mul(M_div_tmp8, M_div_workb, M_div_tmp7); /* * Compare our q-hat (j) against the desired number. * j is either correct, 1 too large, or 2 too large * per Theorem B on pg 272 of Art of Compter Programming, * Volume 2, 3rd Edition. * * The above statement is only true if using the 2 leading * digits of the numerator and the leading digit of the * denominator. Since we are using the (3) leading digits * of the numerator and the (2) leading digits of the * denominator, we eliminate the case where our q-hat is * 2 too large, (and q-hat being 1 too large is quite remote). */ if (BigNumber.Compare(M_div_tmp7, M_div_worka) == 1) { j--; BigNumber.Sub(M_div_tmp7, M_div_workb, M_div_tmp8); BigNumber.Copy(M_div_tmp8, M_div_tmp7); } /* * Since we know q-hat is correct, step D6 is unnecessary. * * Store q-hat, step D5. Since D6 is unnecessary, we can * do D5 before D4 and decide if we are done. */ rr.mantissa[indexr++] = (byte)j; /* j == 'qhat' */ m += 2; if (m >= iterations) { break; } /* step D4 */ BigNumber.Sub(M_div_worka, M_div_tmp7, M_div_tmp9); /* * if the subtraction yields zero, the division is exact * and we are done early. */ if (M_div_tmp9.signum == 0) { iterations = m; break; } /* multiply by 100 and re-save */ M_div_tmp9.exponent += 2; BigNumber.Copy(M_div_tmp9, M_div_worka); } } rr.signum = sign; rr.exponent = nexp; rr.dataLength = iterations; BigNumber.Normalize(rr); }
static public void Add(BigNumber src, BigNumber dst, BigNumber result) { int j, carry, aexp, bexp, adigits, bdigits; sbyte sign; BigNumber A = 0, B = 0; if (src.signum == 0) { BigNumber.Copy(dst, result); return; } if (dst.signum == 0) { BigNumber.Copy(src, result); return; } if (src.signum == 1 && dst.signum == -1) { dst.signum = 1; Sub(src, dst, result); dst.signum = -1; return; } if (src.signum == -1 && dst.signum == 1) { src.signum = 1; Sub(dst, src, result); src.signum = -1; return; } sign = src.signum; aexp = src.exponent; bexp = dst.exponent; Copy(src, A); Copy(dst, B); if (aexp == bexp) { // scale (shift) 2 digits BigNumber.Scale(A, 2); BigNumber.Scale(B, 2); } else { // scale to larger exponent if (aexp > bexp) { BigNumber.Scale(A, 2); BigNumber.Scale(B, (aexp - bexp + 2)); } else { BigNumber.Scale(B, 2); BigNumber.Scale(A, (bexp - aexp + 2)); } } adigits = A.dataLength; bdigits = B.dataLength; if (adigits >= bdigits) { Copy(A, result); j = (bdigits + 1) >> 1; carry = 0; while (true) { j--; result.mantissa[j] += (byte)(carry + B.mantissa[j]); if (result.mantissa[j] >= 100) { result.mantissa[j] -= 100; carry = 1; } else { carry = 0; } if (j == 0) { break; } } } else { Copy(B, result); j = (adigits + 1) >> 1; carry = 0; while (true) { j--; result.mantissa[j] += (byte)(carry + A.mantissa[j]); if (result.mantissa[j] >= 100) { result.mantissa[j] -= 100; carry = 1; } else { carry = 0; } if (j == 0) { break; } } } result.signum = sign; Normalize(result); }
static private String ToExpString(BigNumber atm, int digits) { int i, index, first, max_i, num_digits, dec_places; byte numdiv = 0, numrem = 0; BigNumber ctmp = new BigNumber(); String res = ""; dec_places = digits; if (dec_places < 0) { BigNumber.Copy(atm, ctmp); } else { BigNumber.Round(atm, ctmp, dec_places); } if (ctmp.signum == 0) { if (dec_places < 0) { res = "0.0E+0"; } else { res = "0"; if (dec_places > 0) { res += "."; } for (i = 0; i < dec_places; i++) { res += "0"; } res += "E+0"; } return(res); } max_i = (ctmp.dataLength + 1) >> 1; if (dec_places < 0) { num_digits = ctmp.dataLength; } else { num_digits = dec_places + 1; } if (ctmp.signum == -1) { res += '-'; } first = 1; i = 0; index = 0; while (true) { if (index >= max_i) { numdiv = 0; numrem = 0; } else { Unpack(ctmp.mantissa[index], ref numdiv, ref numrem); } index++; res += (char)('0' + numdiv); if (++i == num_digits) { break; } if (first != 0) { first = 0; res += '.'; } res += (char)('0' + numrem); if (++i == num_digits) { break; } } i = ctmp.exponent - 1; if (i >= 0) { res += "E+" + i; } else if (i < 0) { res += "E" + i; } return(res); }