/****************************************************************************/ /* * 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 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 int M_exp_compute_nn(ref int n, BigNumber b, BigNumber a) { BigNumber tmp0, tmp1; String cp = ""; int kk; n = 0; tmp0 = new BigNumber(); tmp1 = new BigNumber(); BigNumber.Mul(BN_exp_log2R, a, tmp1); if (tmp1.signum >= 0) { BigNumber.Add(tmp1, BigNumber.BN_OneHalf, tmp0); BigNumber.Floor(tmp1, tmp0); } else { BigNumber.Sub(tmp1, BigNumber.BN_OneHalf, tmp0); BigNumber.Ceil(tmp1, tmp0); } kk = tmp1.exponent; cp = BigNumber.ToIntString(tmp1); n = Convert.ToInt32(cp); BigNumber.SetFromLong(b, (long)(n)); kk = BigNumber.Compare(b, tmp1); return(kk); }
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 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); } }