/// <summary> /// Constructs a BigInt from a string, using the specified precision and base /// </summary> /// <param name="init"></param> /// <param name="precision"></param> /// <param name="numberBase"></param> public BigInt(string init, PrecisionSpec precision, int numberBase) { InitFromString(init, precision, numberBase); }
private void Init(PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; mantissa = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); }
/// <summary> /// Get e to the indicated precision /// </summary> /// <param name="precision">The preicision to perform the calculation to</param> /// <returns>e (the number for which the d/dx(e^x) = e^x)</returns> public static BigFloat GetE(PrecisionSpec precision) { if (eCache == null || eCache.mantissa.Precision.NumBits < precision.NumBits) { CalculateEOnly(precision.NumBits); //CalculateFactorials(precision.NumBits); } BigFloat ret = new BigFloat(precision); ret.Assign(eCache); return ret; }
/// <summary> /// Constructs a BigFloat from a BigInt, using the specified precision /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(BigInt value, PrecisionSpec mantissaPrec) { if (value.IsZero()) { Init(mantissaPrec); SetZero(); return; } mantissa = new BigInt(value, mantissaPrec); exponent = BigInt.GetMSB(value); mantissa.Normalise(); }
/// <summary> /// Copy Constructor - constructs a new BigFloat with the specified precision, copying the old one. /// /// The value is rounded towards zero in the case where precision is decreased. The Round() function /// should be used beforehand if a correctly rounded result is required. /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(BigFloat value, PrecisionSpec mantissaPrec) { Init(mantissaPrec); exponent = value.exponent; if (mantissa.AssignHigh(value.mantissa)) exponent++; }
/// <summary> /// Uses the Gauss-Legendre formula for pi /// Taken from http://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm /// </summary> /// <param name="numBits"></param> private static void CalculatePi(int numBits) { int bits = numBits + 32; //Precision extend taken out. PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN); if (scratch.Precision.NumBits != bits) { scratch = new BigInt(extendedPres); } //a0 = 1 BigFloat an = new BigFloat(1, extendedPres); //b0 = 1/sqrt(2) BigFloat bn = new BigFloat(2, extendedPres); bn.Sqrt(); bn.exponent--; //to = 1/4 BigFloat tn = new BigFloat(1, extendedPres); tn.exponent -= 2; int pn = 0; BigFloat anTemp = new BigFloat(extendedPres); int iteration = 0; int cutoffBits = numBits >> 5; for (iteration = 0; ; iteration++) { //Save a(n) anTemp.Assign(an); //Calculate new an an.Add(bn); an.exponent--; //Calculate new bn bn.Mul(anTemp); bn.Sqrt(); //Calculate new tn anTemp.Sub(an); anTemp.mantissa.SquareHiFast(scratch); anTemp.exponent += anTemp.exponent + pn + 1 - anTemp.mantissa.Normalise(); tn.Sub(anTemp); anTemp.Assign(an); anTemp.Sub(bn); if (anTemp.exponent < -(bits - cutoffBits)) break; //New pn pn++; } an.Add(bn); an.mantissa.SquareHiFast(scratch); an.exponent += an.exponent + 1 - an.mantissa.Normalise(); tn.exponent += 2; an.Div(tn); pi = new BigFloat(an, normalPres); piBy2 = new BigFloat(pi); piBy2.exponent--; twoPi = new BigFloat(pi, normalPres); twoPi.exponent++; piRecip = new BigFloat(an.Reciprocal(), normalPres); twoPiRecip = new BigFloat(piRecip); twoPiRecip.exponent--; //1/3 is going to be useful for sin. threeRecip = new BigFloat((new BigFloat(3, extendedPres)).Reciprocal(), normalPres); }
/// <summary> /// Constructs a BigFloat from a 64-bit integer /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(Int64 value, PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; UInt64 uValue; if (value < 0) { if (value == Int64.MinValue) { uValue = 0x80000000; } else { uValue = (UInt64)(-value); } } else { uValue = (UInt64)value; } mantissa = new BigInt(value, new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); int bit = BigInt.GetMSB(uValue); if (bit == -1) return; int shift = mantissa.Precision.NumBits - (bit + 1); if (shift > 0) { mantissa.LSH(shift); } else { mantissa.SetHighDigit((uint)(uValue >> (-shift))); } exponent = bit; }
//*************** Utility Functions ************** /// <summary> /// Casts a BigInt to the new precision provided. /// Note: This will return the input if the precision already matches. /// </summary> /// <param name="input"></param> /// <param name="precision"></param> /// <returns></returns> public static BigInt CastToPrecision(BigInt input, PrecisionSpec precision) { if (input.pres == precision) return input; return new BigInt(input, precision); }
/// <summary> /// GetSDTMultiplicityResult() calculates Singles, Doubles, and Triples rates plus related metadata. /// /// This utility method works for both Slow- and Fast-Background Multiplicity Analyzers. /// /// Note that the input parameter "accidentalsHistogram" need not be normalized, /// and that a normalized-accidentals distribution will be included in output and will be valid /// for both slow and fast accidentals. /// /// </summary> /// <param name="realsPlusAccidentalsHistogram"> The histogram of gate populations. </param> /// <param name="accidentalsHistogram"> The histogram of gate populations - NOT NORMALIZED. </param> /// <param name="wasFastAccidentals"> true or false. Affects how PTsingles are calculated, etc. </param> /// <param name="multiplicityGateWidth"> as a UInt64, in 100-nanosecond tics. </param> /// <param name="multiplicityDeadDelay"> as a UInt64, in 100-nanosecond tics. </param> /// <param name="accidentalsDelay"> as a UInt64, in 100-nanosecond tics. </param> /// <param name="deadTimeCoeffTinNanoSecs"> as a double, in nanoseconds. </param> /// <param name="deadTimeCoeffAinMicroSecs"> as a double, in microseconds. </param> /// <param name="deadTimeCoeffBinPicoSecs"> as a double, in picoseconds. </param> /// <param name="deadTimeCoeffCinNanoSecs"> as a double, in nanoseconds. </param> /// <param name="totalMeasurementTime"> as a double, in seconds. </param> /// <param name="normedAccidentalsHistogram"> UInt64[]. </param> /// <returns></returns> public MultiplicityResult GetSDTMultiplicityResult(UInt64[] realsPlusAccidentalsHistogram, UInt64[] accidentalsHistogram, Boolean wasFastAccidentals, UInt64 multiplicityGateWidth, UInt64 multiplicityDeadDelay, UInt64 accidentalsDelay, double deadTimeCoeffTinNanoSecs, double deadTimeCoeffAinMicroSecs, double deadTimeCoeffBinPicoSecs, double deadTimeCoeffCinNanoSecs, double totalMeasurementTime, UInt64[] normedAccidentalsHistogram = null) { MultiplicityResult result; double phi; double gateInSeconds; UInt32 biggestKey, biggestAKey; int arrayLength; double[] alpha; double[] beta; BigFloat[] α = new BigFloat[0], β = new BigFloat[0]; result = new MultiplicityResult(); if (wasFastAccidentals == true) { result.isSlowBackground = false; } else { result.isSlowBackground = true; } //store parameters result.multiplicityGateWidth = multiplicityGateWidth; result.multiplicityDeadDelay = multiplicityDeadDelay; result.accidentalsDelay = accidentalsDelay; result.deadTimeCoefficientTinNanoSecs = deadTimeCoeffTinNanoSecs; result.deadTimeCoefficientAinMicroSecs = deadTimeCoeffAinMicroSecs; result.deadTimeCoefficientBinPicoSecs = deadTimeCoeffBinPicoSecs; result.deadTimeCoefficientCinNanoSecs = deadTimeCoeffCinNanoSecs; //copy the real-plus-accidental multiplicity histogram biggestKey = 0; arrayLength = realsPlusAccidentalsHistogram.Length; for (int i = 0; i < arrayLength; i++) { if (realsPlusAccidentalsHistogram[i] > 0) { result.realPlusAccidentalDistribution.Add((UInt64)i, realsPlusAccidentalsHistogram[i]); biggestKey = (UInt32)i; } } result.maxRABin = biggestKey; //copy the accidental-only histogram biggestAKey = 0; arrayLength = accidentalsHistogram.Length; for (int i = 0; i < arrayLength; i++) { if (accidentalsHistogram[i] > 0) { result.accidentalDistribution.Add((UInt32)i, accidentalsHistogram[i]); biggestAKey = (UInt32)i; } } result.maxABin = biggestAKey; //************************************************************ //Normalize the AccidentalDistribution, //scaling the FastBackgroundAnalysis result in proportion //to the number of Real+Accidental gate UInt64 numAccidentalGates = 0; UInt64 numRealPlusAccidentalGates = 0; foreach (KeyValuePair<UInt64, UInt64> pair in result.realPlusAccidentalDistribution) { numRealPlusAccidentalGates += pair.Value; } // compute the normalization param and recompute the unnormalizaed array from this one (code does not seem to work JFL) if (normedAccidentalsHistogram != null) { for (int i = 0; i < normedAccidentalsHistogram.Length; i++) { if (normedAccidentalsHistogram[i] > 0) { result.normalizedAccidentalDistribution.Add((UInt32)i, normedAccidentalsHistogram[i]); } } UInt64 numNAccidentalGates = 0; foreach (ulong no in normedAccidentalsHistogram) { numNAccidentalGates += no; } double denormalizingRatio; UInt64 denormalizedRate; denormalizingRatio = ((double)numNAccidentalGates) / ((double)numRealPlusAccidentalGates); result.accidentalDistribution.Clear(); foreach (KeyValuePair<UInt64, UInt64> pair in result.normalizedAccidentalDistribution) { denormalizedRate = (UInt64)(pair.Value * denormalizingRatio); result.accidentalDistribution.Add(pair.Key, denormalizedRate); biggestAKey = (UInt32)pair.Key; } result.maxABin = biggestAKey; foreach (KeyValuePair<UInt64, UInt64> pair in result.accidentalDistribution) { numAccidentalGates += pair.Value; } } else { foreach (KeyValuePair<UInt64, UInt64> pair in result.accidentalDistribution) { numAccidentalGates += pair.Value; } double normalizingRatio; UInt64 normalizedRate; normalizingRatio = ((double)numRealPlusAccidentalGates) / ((double)numAccidentalGates); result.normalizedAccidentalDistribution.Clear(); foreach (KeyValuePair<UInt64, UInt64> pair in result.accidentalDistribution) { normalizedRate = (UInt64)(pair.Value * normalizingRatio); result.normalizedAccidentalDistribution.Add(pair.Key, normalizedRate); } } //*** END Normalizing the AccidentalDistribution ************* //store the bigger key... if (biggestAKey > biggestKey) { biggestKey = biggestAKey; } if (biggestKey < 2) { biggestKey = 2; //...minimum size for data-output arrays... } alpha = new double[biggestKey + 1]; beta = new double[biggestKey + 1]; gateInSeconds = ((double)multiplicityGateWidth) * this.ticSizeInSeconds; phi = (deadTimeCoeffTinNanoSecs / 1E9) / gateInSeconds; bool standard = true; // dev note: this toggle signals use of BigNum when FP overflow is detected int axover = 0, bxover = 0; //calculate the alphas alpha[0] = 0.0; alpha[1] = 1.0; for (int n = 2; n <= biggestKey; n++) { if (phi > 1e-20) { alpha[n] = 1.0; if (standard) { for (int k = 0; k <= (n - 2); k++) { double alphaCoeff; alphaCoeff = this.binomialCoefficient((n - 1), (k + 1)) * Math.Pow((double)(k + 1), (double)k) * Math.Pow(phi, (double)k) / (Math.Pow((1.0 - ((k + 1) * phi)), (double)(k + 2))); alpha[n] += alphaCoeff; if (Double.IsInfinity(alpha[n]) || Double.IsNaN(alpha[n])) { result.warnings.Add("Overflow alpha at n = " + n + ", k = " + k); alpha[n] = 0; axover = n; standard = false; k = n; n = n - 1; // redo the loop α = new BigFloat[biggestKey + 1]; } } } else { // INCCCycleConditioning.calc_alpha_beta PrecisionSpec ps128 = new PrecisionSpec(128, PrecisionSpec.BaseType.BIN); BigFloat one = new BigFloat(1, ps128); BigFloat combination; BigFloat sum; double raise1, power1, power2; double log1, log2, log3; BigFloat exp1, exp2, exp3; /* calculate alpha array */ sum = new BigFloat(0, ps128); for (int k = 0; k <= (n - 2); k++) { combination = new BigFloat(binomialCoefficient((n - 1), (k + 1)), ps128); raise1 = (double)(k + 1); power1 = (double)k; power2 = (double)(k + 2); log1 = Math.Log(raise1); log2 = Math.Log(phi); log3 = Math.Log(1.0 - raise1 * phi); exp1 = BigFloat.Exp(new BigFloat(log1 * power1, ps128)); exp2 = BigFloat.Exp(new BigFloat(log2 * power1, ps128)); exp3 = BigFloat.Exp(new BigFloat(log3 * power2, ps128)); sum += combination * exp1 * exp2 / exp3; } α[n] = new BigFloat(one + sum, ps128); } } else { alpha[n] = 1.0; } } //calculate the betas standard = true; beta[0] = 0.0; beta[1] = 0.0; beta[2] = alpha[2] - 1.0; for (int n = 3; n <= biggestKey; n++) { if (phi > 1e-20) { beta[n] = alpha[n] - 1.0; if (standard) { for (int k = 0; k <= (n - 3); k++) { double betaCoeff; betaCoeff = this.binomialCoefficient((n - 1), (k + 2)) * (k + 1) * Math.Pow((double)(k + 2), (double)k) * Math.Pow(phi, (double)k) / (Math.Pow((1.0 - ((k + 2) * phi)), (double)(k + 3))); beta[n] += betaCoeff; if (Double.IsInfinity(beta[n]) || Double.IsNaN(beta[n])) { result.warnings.Add("Overflow beta at n = " + n + ", k = " + k); beta[n] = 0; bxover = n; standard = false; k = n; n = n - 1; // redo the loop β = new BigFloat[biggestKey + 1]; } } } else { PrecisionSpec ps128 = new PrecisionSpec(128, PrecisionSpec.BaseType.BIN); BigFloat one = new BigFloat(1, ps128); BigFloat combination; BigFloat sum; double raise1, power1, power2; double log1, log2, log3; BigFloat exp1, exp2, exp3; sum = new BigFloat(0, ps128); for (int k = 0; k <= n - 3; k++) { combination = new BigFloat(binomialCoefficient((n - 1), (k + 2)), ps128); raise1 = (double)(k + 2); power1 = (double)k; power2 = (double)(k + 3); log1 = Math.Log(raise1); log2 = Math.Log(phi); log3 = Math.Log(1.0 - raise1 * phi); exp1 = BigFloat.Exp(new BigFloat(log1 * power1, ps128)); exp2 = BigFloat.Exp(new BigFloat(log2 * power1, ps128)); exp3 = BigFloat.Exp(new BigFloat(log3 * power2, ps128)); sum += combination * (new BigFloat(k + 1, ps128)) * exp1 * exp2 / exp3; } β[n] = α[n] - one + sum; } } else { beta[n] = 0.0; } } //store the alpha and beta coefficients result.alpha = new double[biggestKey + 1]; result.beta = new double[biggestKey + 1]; for (int i = 0; i <= biggestKey; i++) { result.alpha[i] = alpha[i]; result.beta[i] = beta[i]; } double lastGoodD = 0; for (int i = axover; axover > 0 && i <= biggestKey; i++) { double d; bool good = Double.TryParse(α[i].ToString(), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out d); // what to do when it is really larger than a double? if (!good) { result.alpha[i] = lastGoodD; result.warnings.Add(String.Format("α[{0}] conversion failed on {1}", i, α[i].ToString())); } else { lastGoodD = d; result.alpha[i] = d; } } for (int i = bxover; bxover > 0 && i <= biggestKey; i++) { double d; bool good = Double.TryParse(β[i].ToString(), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out d); if (!good) { result.beta[i] = lastGoodD; result.warnings.Add(String.Format("β[{0}] conversion failed on {1}", i, β[i].ToString())); // URGENT: alpha/beta arrays are to be transformed from doubles to BigFloat types when this conversion happens to overflow } else { lastGoodD = d; result.beta[i] = d; } } //NOTE: in the following calculations, //variables named RAxxx refer to "Reals Plus Accidentals" phenomena, and //variables named Axxx refer to "Accidentals" phenomena (such as, fast-background counting) //calculate the factorial moments double RAfactorialMoment0, RAfactorialMoment1, RAfactorialMoment2, RAfactorialMoment3; double AfactorialMoment0, AfactorialMoment1, AfactorialMoment2, AfactorialMoment3; double RAfactorialMomentAlpha1, AfactorialMomentAlpha1; double RAfactorialMomentBeta2, AfactorialMomentBeta2; RAfactorialMoment0 = 0.0; RAfactorialMoment1 = 0.0; RAfactorialMoment2 = 0.0; RAfactorialMoment3 = 0.0; AfactorialMoment0 = 0.0; AfactorialMoment1 = 0.0; AfactorialMoment2 = 0.0; AfactorialMoment3 = 0.0; RAfactorialMomentAlpha1 = 0.0; AfactorialMomentAlpha1 = 0.0; RAfactorialMomentBeta2 = 0.0; AfactorialMomentBeta2 = 0.0; for (int i = 0; i <= biggestKey; i++) { UInt64 gateCount; int j = i + 1; int k = i + 2; int L = i + 3; if (result.realPlusAccidentalDistribution.TryGetValue((UInt64)i, out gateCount)) { RAfactorialMoment0 += (double)gateCount; } if (result.accidentalDistribution.TryGetValue((UInt64)i, out gateCount)) { AfactorialMoment0 += gateCount; } if (j <= biggestKey) { if (result.realPlusAccidentalDistribution.TryGetValue((UInt64)j, out gateCount)) { RAfactorialMoment1 += (double)(((UInt64)j) * gateCount); RAfactorialMomentAlpha1 += alpha[j] * ((double)gateCount); } if (result.accidentalDistribution.TryGetValue((UInt64)j, out gateCount)) { AfactorialMoment1 += (double)(((UInt64)j) * gateCount); AfactorialMomentAlpha1 += alpha[j] * ((double)gateCount); } } if (k <= biggestKey) { if (result.realPlusAccidentalDistribution.TryGetValue((UInt32)k, out gateCount)) { RAfactorialMoment2 += (double)(((UInt64)(k * (k - 1) / 2)) * gateCount); RAfactorialMomentBeta2 += beta[k] * ((double)gateCount); } if (result.accidentalDistribution.TryGetValue((UInt32)k, out gateCount)) { AfactorialMoment2 += (double)(((UInt64)(k * (k - 1) / 2)) * gateCount); AfactorialMomentBeta2 += beta[k] * ((double)gateCount); } } if (L <= biggestKey) { if (result.realPlusAccidentalDistribution.TryGetValue((UInt32)L, out gateCount)) { RAfactorialMoment3 += ((double)(((UInt64)(L * (L - 1) * (L - 2))) * gateCount)) / 6.0; } if (result.accidentalDistribution.TryGetValue((UInt32)L, out gateCount)) { AfactorialMoment3 += ((double)(((UInt64)(L * (L - 1) * (L - 2))) * gateCount)) / 6.0; } } } //store the factorial moments result.RAfactorialMoment0 = RAfactorialMoment0; result.RAfactorialMoment1 = RAfactorialMoment1; result.RAfactorialMoment2 = RAfactorialMoment2; result.RAfactorialMoment3 = RAfactorialMoment3; result.AfactorialMoment0 = AfactorialMoment0; result.AfactorialMoment1 = AfactorialMoment1; result.AfactorialMoment2 = AfactorialMoment2; result.AfactorialMoment3 = AfactorialMoment3; //NOTE: in the following calculations, //variables named PTxxx refer to "Pulse Triggered" phenomena, and //variables named RTxxx refer to "Regularly Triggered" phenomena (such as, fast-background counting) //penultimately, use all this to calculate the SDT rates double PTsingles, RTsingles, normRAfactorialMoment1, normRAfactorialMoment2; double normRAfactorialMomentAlpha1, normRAfactorialMomentBeta2; double normAfactorialMoment0, normAfactorialMoment1, normAfactorialMoment2, normAfactorialMoment3; double normAfactorialMomentAlpha1, normAfactorialMomentBeta2; if (wasFastAccidentals) { PTsingles = RAfactorialMoment0; double gateFactor = numAccidentalGates / Math.Floor(totalMeasurementTime / (multiplicityGateWidth * this.ticSizeInSeconds)); RTsingles = AfactorialMoment1 / gateFactor; normRAfactorialMoment1 = RAfactorialMoment1 / PTsingles; normRAfactorialMoment2 = RAfactorialMoment2 / PTsingles; //NOT USED: double normRAfactorialMoment3 = RAfactorialMoment3 / PTsingles; normRAfactorialMomentAlpha1 = RAfactorialMomentAlpha1 / PTsingles; normRAfactorialMomentBeta2 = RAfactorialMomentBeta2 / PTsingles; normAfactorialMoment0 = AfactorialMoment0 / numAccidentalGates; normAfactorialMoment1 = AfactorialMoment1 / numAccidentalGates; normAfactorialMoment2 = AfactorialMoment2 / numAccidentalGates; normAfactorialMoment3 = AfactorialMoment3 / numAccidentalGates; normAfactorialMomentAlpha1 = AfactorialMomentAlpha1 / numAccidentalGates; normAfactorialMomentBeta2 = AfactorialMomentBeta2 / numAccidentalGates; } else { PTsingles = AfactorialMoment0; //XXX SHOULDN'T THIS BE RAfactorialMoment0 not AfactorialMoment0???, answer, no, the two values should be the same, RA and A of 0 are identical for "slow" RTsingles = AfactorialMoment0; normRAfactorialMoment1 = RAfactorialMoment1 / PTsingles; normRAfactorialMoment2 = RAfactorialMoment2 / PTsingles; //NOT USED: double normRAfactorialMoment3 = RAfactorialMoment3 / PTsingles; normRAfactorialMomentAlpha1 = RAfactorialMomentAlpha1 / PTsingles; normRAfactorialMomentBeta2 = RAfactorialMomentBeta2 / PTsingles; normAfactorialMoment0 = AfactorialMoment0 / RTsingles; normAfactorialMoment1 = AfactorialMoment1 / RTsingles; normAfactorialMoment2 = AfactorialMoment2 / RTsingles; normAfactorialMoment3 = AfactorialMoment3 / RTsingles; normAfactorialMomentAlpha1 = AfactorialMomentAlpha1 / RTsingles; normAfactorialMomentBeta2 = AfactorialMomentBeta2 / RTsingles; } double RTdoubles = (0.5 / (multiplicityGateWidth * this.ticSizeInSeconds)) * ((2.0 * normAfactorialMoment2) - Math.Pow(normAfactorialMoment1, 2.0)); double RTtriples = (0.16667 / (multiplicityGateWidth * this.ticSizeInSeconds)) * ((6.0 * normAfactorialMoment3) - (6.0 * normAfactorialMoment1 * normAfactorialMoment2) + (2.0 * Math.Pow(normAfactorialMoment1, 3))); double PTdoubles = PTsingles * (normRAfactorialMoment1 - normAfactorialMoment1); double PTtriples; double PTtriplesDTcoef; if (AfactorialMoment0 != 0.0) { PTtriples = PTsingles * ((normRAfactorialMoment2 - normAfactorialMoment2) - ((normAfactorialMoment1 / normAfactorialMoment0) * (normRAfactorialMoment1 - normAfactorialMoment1))); PTtriplesDTcoef = PTsingles * ((normRAfactorialMomentBeta2 - normAfactorialMomentBeta2) - ((normAfactorialMomentAlpha1 / normAfactorialMoment0) * (normRAfactorialMomentAlpha1 - normAfactorialMomentAlpha1))); } else { PTtriples = 0.0; PTtriplesDTcoef = 0.0; } if (totalMeasurementTime > 1E-12) { PTsingles /= totalMeasurementTime; PTdoubles /= totalMeasurementTime; PTtriples /= totalMeasurementTime; PTtriplesDTcoef /= totalMeasurementTime; } else { PTsingles = 0.0; PTdoubles = 0.0; PTtriples = 0.0; PTtriplesDTcoef = 0.0; } //store the SDT rates result.singlesRatePerSecond = PTsingles; result.doublesRatePerSecond = PTdoubles; result.triplesRatePerSecond = PTtriples; //now that rates are calculated, calculate the dead-time corrections // dead time correction coefficients for RT rates (INCC as well as H&C) // determined experimentally using D/T ratio - see analysisComparison/triplesDeadTime.xls // the best fit (poly3) used to reproduce the trend // note: valid only for sources in the range of ~100n/s - ~500,000 n/s /** NOT USED *** double DTcoeffT0_RT = 3.42854465; double DTcoeffT1_RT = 3.35351651E-6; double DTcoeffT2_RT = -5.83706327E-12; double DTcoeffT3_RT = 2.03604973E-17; ***************/ // dead time correction coefficients for PT rates with background calculated using H&C consecutive gates // determined experimentally using D/T ratio - see analysisComparison/triplesDeadTime.xls // the best fit (poly3) used to reproduce the trend // note: valid only for sources in the range of ~100n/s - ~500,000 n/s /** NOT USED *** double DTcoeffT0_PT = 2.78760077; double DTcoeffT1_PT = 2.86078894E-6; double DTcoeffT2_PT = -8.21994836E-12; double DTcoeffT3_PT = 9.45195862E-17; ***************/ /** NOT USED *** double DTcoeffA_RT = 0.2063; // these values were determined using two source method double DTcoeffB_RT = 0.04256; ***************/ double DTcoeffA = deadTimeCoeffAinMicroSecs; double DTcoeffB = deadTimeCoeffBinPicoSecs; double DTcoeffC = deadTimeCoeffCinNanoSecs; double DTcoeffT = deadTimeCoeffTinNanoSecs; double exponent = ((DTcoeffA / 1E6) + ((DTcoeffB / 1E12) * PTsingles)) * PTsingles; double PTsinglesDTcorr = PTsingles * Math.Exp(exponent / 4.0); double PTdoublesDTcorr = PTdoubles * Math.Exp(exponent); double PTtriplesDTcorr = PTtriplesDTcoef * Math.Exp((DTcoeffT / 1E9) * PTsingles); /** NOT USED *** double RTsinglesDTcorr = RTsingles * Math.Exp(( ((DTcoeffA/1E6) + ((DTcoeffB/1E12)*RTsingles)) *RTsingles)/4.0); double RTdoublesDTcorr = RTdoubles * Math.Exp( ((DTcoeffA_RT/1E6) + ((DTcoeffB_RT/1E12)*RTsingles)) *RTsingles); double RTtriplesDTcorr = RTtriples* (( (DTcoeffT3_RT*Math.Pow(RTsingles,3)) + (DTcoeffT2_RT*Math.Pow(RTsingles,2)) + (DTcoeffT1_RT*RTsingles) + DTcoeffT0_RT) /DTcoeffT0_RT); ***************/ //store the dead-time corrected values result.deadTimeCorrectedSinglesRate = PTsinglesDTcorr; result.deadTimeCorrectedDoublesRate = PTdoublesDTcorr; result.deadTimeCorrectedTriplesRate = PTtriplesDTcorr; //Calculate the Dytlewski Dead-Time-Corrected Rates, based upon //N. Dytlewski, Dead-time corrections for multiplicity counters, //Nuclear Instruments and Methods in Physics Research A305(1991)492-494 double P03, P02, P13, P12, P23; P03 = Math.Pow((1.0 - (2.0 * phi)), 3.0); P02 = Math.Pow((1.0 - phi), 2.0); P13 = (2.0 * Math.Pow((1.0 - phi), 3.0)) - (2.0 * P03); P12 = 1.0 - P02; P23 = 1.0 + P03 - (2.0 * Math.Pow((1.0 - phi), 3.0)); result.dytlewskiDeadTimeCorrectedTriplesRate = PTtriples / P03; //Martyn made me do it. hn 2.6.2015 result.deadTimeCorrectedTriplesRate = result.dytlewskiDeadTimeCorrectedTriplesRate; result.dytlewskiDeadTimeCorrectedDoublesRate = (PTdoubles / P02) + ((PTtriples * P13) / (P02 * P03)); result.dytlewskiDeadTimeCorrectedSinglesRate = PTsingles + ((P12 * PTdoubles) / P02) + (PTtriples * (((P12 * P13) / (P02 * P03)) - (P23 / P03))); return (result); }
/// <summary> /// Constructs a BigInt from an Int32 /// </summary> /// <param name="input"></param> /// <param name="precision"></param> public BigInt(Int32 input, PrecisionSpec precision) { Init(precision); if (input < 0) { sign = true; if (input == Int32.MinValue) { digitArray[0] = 0x80000000; } else { digitArray[0] = (UInt32)(-input); } } else { digitArray[0] = ((UInt32)input); } }
/// <summary> /// Constructs a BigInt from a UInt32 /// </summary> /// <param name="input"></param> /// <param name="precision"></param> public BigInt(Int64 input, PrecisionSpec precision) { Init(precision); if (input < 0) sign = true; digitArray[0] = (UInt32)(input & 0xffffffff); if (digitArray.Length >= 2) { if (input == Int64.MinValue) { digitArray[1] = 0x80000000; } else { digitArray[1] = (UInt32)((input >> 32) & 0x7fffffff); } } }
/// <summary> /// Constructs a BigInt from a UInt64 /// </summary> /// <param name="input"></param> /// <param name="precision"></param> public BigInt(UInt64 input, PrecisionSpec precision) { Init(precision); digitArray[0] = (UInt32)(input & 0xffffffff); if (digitArray.Length > 1) digitArray[1] = (UInt32)(input >> 32); }
/// <summary> /// Constructs a BigInt from a UInt32 /// </summary> /// <param name="input"></param> /// <param name="precision"></param> public BigInt(UInt32 input, PrecisionSpec precision) { Init(precision); digitArray[0] = input; }
/// <summary> /// Constructs a bigint from the input, matching the new precision provided /// </summary> public BigInt(BigInt input, PrecisionSpec precision) { //Casts the input to the new precision. Init(precision); int Min = (input.digitArray.Length < digitArray.Length) ? input.digitArray.Length : digitArray.Length; for (int i = 0; i < Min; i++) { digitArray[i] = input.digitArray[i]; } sign = input.sign; }
private static void CalculateFactorials(int numBits) { System.Collections.Generic.List<BigFloat> list = new System.Collections.Generic.List<BigFloat>(64); System.Collections.Generic.List<BigFloat> list2 = new System.Collections.Generic.List<BigFloat>(64); PrecisionSpec extendedPrecision = new PrecisionSpec(numBits + 1, PrecisionSpec.BaseType.BIN); PrecisionSpec normalPrecision = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); BigFloat factorial = new BigFloat(1, extendedPrecision); BigFloat reciprocal; //Calculate e while we're at it BigFloat e = new BigFloat(1, extendedPrecision); list.Add(new BigFloat(factorial, normalPrecision)); for (int i = 1; i < Int32.MaxValue; i++) { BigFloat number = new BigFloat(i, extendedPrecision); factorial.Mul(number); if (factorial.exponent > numBits) break; list2.Add(new BigFloat(factorial, normalPrecision)); reciprocal = factorial.Reciprocal(); e.Add(reciprocal); list.Add(new BigFloat(reciprocal, normalPrecision)); } //Set the cached static values. inverseFactorialCache = list.ToArray(); factorialCache = list2.ToArray(); invFactorialCutoff = numBits; eCache = new BigFloat(e, normalPrecision); eRCPCache = new BigFloat(e.Reciprocal(), normalPrecision); }
//************************** Conversions ************************* /// <summary> /// Converts a BigFloat to an BigInt with the specified precision /// </summary> /// <param name="n1">The number to convert</param> /// <param name="precision">The precision to convert it with</param> /// <param name="round">Do we round the number if we are truncating the mantissa?</param> /// <returns></returns> public static BigInt ConvertToInt(BigFloat n1, PrecisionSpec precision, bool round) { BigInt ret = new BigInt(precision); int numBits = n1.mantissa.Precision.NumBits; int shift = numBits - (n1.exponent + 1); BigFloat copy = new BigFloat(n1); bool inc = false; //Rounding if (copy.mantissa.Precision.NumBits > ret.Precision.NumBits) { inc = true; for (int i = copy.exponent + 1; i <= ret.Precision.NumBits; i++) { if (copy.mantissa.GetBitFromTop(i) == 0) { inc = false; break; } } } if (shift > 0) { copy.mantissa.RSH(shift); } else if (shift < 0) { copy.mantissa.LSH(-shift); } ret.Assign(copy.mantissa); if (inc) ret.Increment(); return ret; }
private static void CalculateEOnly(int numBits) { PrecisionSpec extendedPrecision = new PrecisionSpec(numBits + 1, PrecisionSpec.BaseType.BIN); PrecisionSpec normalPrecision = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); int iExponent = (int)(Math.Sqrt(numBits)); BigFloat factorial = new BigFloat(1, extendedPrecision); BigFloat constant = new BigFloat(1, extendedPrecision); constant.exponent -= iExponent; BigFloat numerator = new BigFloat(constant); BigFloat reciprocal; //Calculate the 2^iExponent th root of e BigFloat e = new BigFloat(1, extendedPrecision); int i; for (i = 1; i < Int32.MaxValue; i++) { BigFloat number = new BigFloat(i, extendedPrecision); factorial.Mul(number); reciprocal = factorial.Reciprocal(); reciprocal.Mul(numerator); if (-reciprocal.exponent > numBits) break; e.Add(reciprocal); numerator.Mul(constant); System.GC.Collect(); } for (i = 0; i < iExponent; i++) { numerator.Assign(e); e.Mul(numerator); } //Set the cached static values. eCache = new BigFloat(e, normalPrecision); eRCPCache = new BigFloat(e.Reciprocal(), normalPrecision); }
/// <summary> /// Constructs a BigFloat of the required precision /// /// Sets the value to zero /// </summary> /// <param name="mantissaPrec"></param> public BigFloat(PrecisionSpec mantissaPrec) { Init(mantissaPrec); }
/// <summary> /// Calculates the odd reciprocals of the natural numbers (for atan series) /// </summary> /// <param name="numBits"></param> /// <param name="terms"></param> private static void CalculateReciprocals(int numBits, int terms) { int bits = numBits + 32; PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN); PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); System.Collections.Generic.List<BigFloat> list = new System.Collections.Generic.List<BigFloat>(terms); for (int i = 0; i < terms; i++) { BigFloat term = new BigFloat(i*2 + 1, extendedPres); list.Add(new BigFloat(term.Reciprocal(), normalPres)); } reciprocals = list.ToArray(); }
/// <summary> /// Constructs a big float from a UInt32 to the required precision /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(UInt32 value, PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; mantissa = new BigInt(value, new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(mantissa.Precision); int bit = BigInt.GetMSB(value); if (bit == -1) return; int shift = mantissa.Precision.NumBits - (bit + 1); mantissa.LSH(shift); exponent = bit; }
/// <summary> /// Constructs a BigFloat from a 64-bit unsigned integer /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(UInt64 value, PrecisionSpec mantissaPrec) { int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; //For efficiency, we just use a 32-bit exponent exponent = 0; int bit = BigInt.GetMSB(value); mantissa = new BigInt(value, new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(mantissa.Precision); int shift = mantissa.Precision.NumBits - (bit + 1); if (shift > 0) { mantissa.LSH(shift); } else { mantissa.SetHighDigit((uint)(value >> (-shift))); } exponent = bit; }
private void Exp(int numBits) { if (IsSpecialValue) { if (SpecialValue == SpecialValueType.ZERO) { //e^0 = 1 exponent = 0; mantissa.SetHighDigit(0x80000000); } else if (SpecialValue == SpecialValueType.INF_MINUS) { //e^-inf = 0 SetZero(); } return; } PrecisionSpec prec = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); numBits = prec.NumBits; if (scratch.Precision.NumBits != prec.NumBits) { scratch = new BigInt(prec); } if (inverseFactorialCache == null || invFactorialCutoff < numBits) { CalculateFactorials(numBits); } //let x = 1 * 'this'.mantissa (i.e. 1 <= x < 2) //exp(2^n * x) = e^(2^n * x) = (e^x)^2n = exp(x)^2n int oldExponent = 0; if (exponent > -4) { oldExponent = exponent + 4; exponent = -4; } BigFloat thisSave = new BigFloat(this, prec); BigFloat temp = new BigFloat(1, prec); BigFloat temp2 = new BigFloat(this, prec); BigFloat res = new BigFloat(1, prec); int length = inverseFactorialCache.Length; int iterations; for (int i = 1; i < length; i++) { //temp = x^i temp.Mul(thisSave); temp2.Assign(inverseFactorialCache[i]); temp2.Mul(temp); if (temp2.exponent < -(numBits + 4)) { iterations = i; break; } res.Add(temp2); } //res = exp(x) //Now... x^(2^n) = (x^2)^(2^(n - 1)) for (int i = 0; i < oldExponent; i++) { res.mantissa.SquareHiFast(scratch); int shift = res.mantissa.Normalise(); res.exponent = res.exponent << 1; res.exponent += 1 - shift; } //Deal with +/- inf if (res.exponent == Int32.MaxValue) { res.mantissa.Zero(); } Assign(res); }
/// <summary> /// Construct a BigFloat from a double-precision floating point number /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(double value, PrecisionSpec mantissaPrec) { if (value == 0.0) { Init(mantissaPrec); return; } bool sign = (value < 0) ? true : false; long bits = BitConverter.DoubleToInt64Bits(value); // Note that the shift is sign-extended, hence the test against -1 not 1 int valueExponent = (int)((bits >> 52) & 0x7ffL); long valueMantissa = bits & 0xfffffffffffffL; //The mantissa is stored with the top bit implied. valueMantissa = valueMantissa | 0x10000000000000L; //The exponent is biased by 1023. exponent = valueExponent - 1023; //Round the number of bits to the nearest word. int mbWords = ((mantissaPrec.NumBits) >> 5); if ((mantissaPrec.NumBits & 31) != 0) mbWords++; int newManBits = mbWords << 5; mantissa = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); //scratch = new BigInt(new PrecisionSpec(newManBits, PrecisionSpec.BaseType.BIN)); if (newManBits >= 64) { //The mantissa is 53 bits now, so add 11 to put it in the right place. mantissa.SetHighDigits(valueMantissa << 11); } else { //To get the top word of the mantissa, shift up by 11 and down by 32 = down by 21 mantissa.SetHighDigit((uint)(valueMantissa >> 21)); } mantissa.Sign = sign; }
/// <summary> /// Calculates ln(2) and returns -10^(n/2 + a bit) for reuse, using the AGM method as described in /// http://lacim.uqam.ca/~plouffe/articles/log2.pdf /// </summary> /// <param name="numBits"></param> /// <returns></returns> private static void CalculateLog2(int numBits) { //Use the AGM method formula to get log2 to N digits. //R(a0, b0) = 1 / (1 - Sum(2^-n*(an^2 - bn^2))) //log(1/2) = R(1, 10^-n) - R(1, 10^-n/2) PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN); PrecisionSpec extendedPres = new PrecisionSpec(numBits + 1, PrecisionSpec.BaseType.BIN); BigFloat a0 = new BigFloat(1, extendedPres); BigFloat b0 = TenPow(-(int)((double)((numBits >> 1) + 2) * 0.302), extendedPres); BigFloat pow10saved = new BigFloat(b0); BigFloat firstAGMcacheSaved = new BigFloat(extendedPres); //save power of 10 (in normal precision) pow10cache = new BigFloat(b0, normalPres); ln2cache = R(a0, b0); //save the first half of the log calculation firstAGMcache = new BigFloat(ln2cache, normalPres); firstAGMcacheSaved.Assign(ln2cache); b0.MulPow2(-1); ln2cache.Sub(R(a0, b0)); //Convert to log(2) ln2cache.mantissa.Sign = false; //Save magic constant for newton log //First guess in range 1 <= x < 2 is x0 = ln2 * (x - 1) + C logNewtonConstant = new BigFloat(ln2cache); logNewtonConstant.Mul(new BigFloat(3, extendedPres)); logNewtonConstant.exponent--; logNewtonConstant.Sub(new BigFloat(1, extendedPres)); logNewtonConstant = new BigFloat(logNewtonConstant, normalPres); //Save the inverse. log2ecache = new BigFloat(ln2cache); log2ecache = new BigFloat(log2ecache.Reciprocal(), normalPres); //Now cache log10 //Because the log functions call this function to the precision to which they //are called, we cannot call them without causing an infinite loop, so we need //to inline the code. log10recip = new BigFloat(10, extendedPres); { int power2 = log10recip.exponent + 1; log10recip.exponent = -1; //BigFloat res = new BigFloat(firstAGMcache); BigFloat ax = new BigFloat(1, extendedPres); BigFloat bx = new BigFloat(pow10saved); bx.Mul(log10recip); BigFloat r = R(ax, bx); log10recip.Assign(firstAGMcacheSaved); log10recip.Sub(r); ax.Assign(ln2cache); ax.Mul(new BigFloat(power2, log10recip.mantissa.Precision)); log10recip.Add(ax); } log10recip = log10recip.Reciprocal(); log10recip = new BigFloat(log10recip, normalPres); //Trim to n bits ln2cache = new BigFloat(ln2cache, normalPres); }
/// <summary> /// Constructs a BigFloat from a string /// </summary> /// <param name="value"></param> /// <param name="mantissaPrec"></param> public BigFloat(string value, PrecisionSpec mantissaPrec) { Init(mantissaPrec); PrecisionSpec extendedPres = new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN); BigFloat ten = new BigFloat(10, extendedPres); BigFloat iPart = new BigFloat(extendedPres); BigFloat fPart = new BigFloat(extendedPres); BigFloat tenRCP = ten.Reciprocal(); if (value.Contains(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NaNSymbol)) { SetNaN(); return; } else if (value.Contains(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PositiveInfinitySymbol)) { SetInfPlus(); return; } else if (value.Contains(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeInfinitySymbol)) { SetInfMinus(); return; } string decimalpoint = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; char[] digitChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '.' }; //Read in the integer part up the the decimal point. bool sign = false; value = value.Trim(); int i = 0; if (value.Length > i && value[i] == '-') { sign = true; i++; } if (value.Length > i && value[i] == '+') { i++; } for ( ; i < value.Length; i++) { //break on decimal point if (value[i] == decimalpoint[0]) break; int digit = Array.IndexOf(digitChars, value[i]); if (digit < 0) break; //Ignore place separators (assumed either , or .) if (digit > 9) continue; if (i > 0) iPart.Mul(ten); iPart.Add(new BigFloat(digit, extendedPres)); } //If we've run out of characters, assign everything and return if (i == value.Length) { iPart.mantissa.Sign = sign; exponent = iPart.exponent; if (mantissa.AssignHigh(iPart.mantissa)) exponent++; return; } //Assign the characters after the decimal point to fPart if (value[i] == '.' && i < value.Length - 1) { BigFloat RecipToUse = new BigFloat(tenRCP); for (i++; i < value.Length; i++) { int digit = Array.IndexOf(digitChars, value[i]); if (digit < 0) break; BigFloat temp = new BigFloat(digit, extendedPres); temp.Mul(RecipToUse); RecipToUse.Mul(tenRCP); fPart.Add(temp); } } //If we're run out of characters, add fPart and iPart and return if (i == value.Length) { iPart.Add(fPart); iPart.mantissa.Sign = sign; exponent = iPart.exponent; if (mantissa.AssignHigh(iPart.mantissa)) exponent++; return; } if (value[i] == '+' || value[i] == '-') i++; if (i == value.Length) { iPart.Add(fPart); iPart.mantissa.Sign = sign; exponent = iPart.exponent; if (mantissa.AssignHigh(iPart.mantissa)) exponent++; return; } //Look for exponential notation. if ((value[i] == 'e' || value[i] == 'E') && i < value.Length - 1) { //Convert the exponent to an int. int exp; try { exp = System.Convert.ToInt32(new string(value.ToCharArray(i + 1, value.Length - (i + 1)))); } catch (Exception) { iPart.Add(fPart); iPart.mantissa.Sign = sign; exponent = iPart.exponent; if (mantissa.AssignHigh(iPart.mantissa)) exponent++; return; } //Raise or lower 10 to the power of the exponent BigFloat acc = new BigFloat(1, extendedPres); BigFloat temp = new BigFloat(1, extendedPres); int powerTemp = exp; BigFloat multiplierToUse; if (exp < 0) { multiplierToUse = new BigFloat(tenRCP); powerTemp = -exp; } else { multiplierToUse = new BigFloat(ten); } //Fast power function while (powerTemp != 0) { temp.Mul(multiplierToUse); multiplierToUse.Assign(temp); if ((powerTemp & 1) != 0) { acc.Mul(temp); } powerTemp >>= 1; } iPart.Add(fPart); iPart.Mul(acc); iPart.mantissa.Sign = sign; exponent = iPart.exponent; if (mantissa.AssignHigh(iPart.mantissa)) exponent++; return; } iPart.Add(fPart); iPart.mantissa.Sign = sign; exponent = iPart.exponent; if (mantissa.AssignHigh(iPart.mantissa)) exponent++; }
private static BigFloat TenPow(int power, PrecisionSpec precision) { BigFloat acc = new BigFloat(1, precision); BigFloat temp = new BigFloat(1, precision); int powerTemp = power; BigFloat multiplierToUse = new BigFloat(10, precision); if (power < 0) { multiplierToUse = multiplierToUse.Reciprocal(); powerTemp = -power; } //Fast power function while (powerTemp != 0) { temp.Mul(multiplierToUse); multiplierToUse.Assign(temp); if ((powerTemp & 1) != 0) { acc.Mul(temp); } powerTemp >>= 1; } return acc; }
//******************** Mathematical Constants ******************* /// <summary> /// Gets pi to the indicated precision /// </summary> /// <param name="precision">The precision to perform the calculation to</param> /// <returns>pi (the ratio of the area of a circle to its diameter)</returns> public static BigFloat GetPi(PrecisionSpec precision) { if (pi == null || precision.NumBits <= pi.mantissa.Precision.NumBits) { CalculatePi(precision.NumBits); } BigFloat ret = new BigFloat (precision); ret.Assign(pi); return ret; }
private static BigFloat R(BigFloat a0, BigFloat b0) { //Precision extend taken out. int bits = a0.mantissa.Precision.NumBits; PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN); BigFloat an = new BigFloat(a0, extendedPres); BigFloat bn = new BigFloat(b0, extendedPres); BigFloat sum = new BigFloat(extendedPres); BigFloat term = new BigFloat(extendedPres); BigFloat temp1 = new BigFloat(extendedPres); BigFloat one = new BigFloat(1, extendedPres); int iteration = 0; for (iteration = 0; ; iteration++) { //Get the sum term for this iteration. term.Assign(an); term.Mul(an); temp1.Assign(bn); temp1.Mul(bn); //term = an^2 - bn^2 term.Sub(temp1); //term = 2^(n-1) * (an^2 - bn^2) term.exponent += iteration - 1; sum.Add(term); if (term.exponent < -(bits - 8)) break; //Calculate the new AGM estimates. temp1.Assign(an); an.Add(bn); //a(n+1) = (an + bn) / 2 an.MulPow2(-1); //b(n+1) = sqrt(an*bn) bn.Mul(temp1); bn.Sqrt(); } one.Sub(sum); one = one.Reciprocal(); return new BigFloat(one, a0.mantissa.Precision); }
/// <summary> /// Newton's method reciprocal, fastest for larger precisions over 15,000 bits. /// </summary> /// <returns>The reciprocal 1/this</returns> public BigFloat ReciprocalNewton() { if (mantissa.IsZero()) { exponent = Int32.MaxValue; return null; } bool oldSign = mantissa.Sign; int oldExponent = exponent; //Kill exponent for now (will re-institute later) exponent = 0; bool topBit = mantissa.IsTopBitOnlyBit(); PrecisionSpec curPrec = new PrecisionSpec(32, PrecisionSpec.BaseType.BIN); BigFloat reciprocal = new BigFloat(curPrec); BigFloat constant2 = new BigFloat(curPrec); BigFloat temp = new BigFloat(curPrec); BigFloat thisPrec = new BigFloat(this, curPrec); reciprocal.exponent = 1; reciprocal.mantissa.SetHighDigit(3129112985u); constant2.exponent = 1; constant2.mantissa.SetHighDigit(0x80000000u); //D is deliberately left negative for all the following operations. thisPrec.mantissa.Sign = true; //Initial estimate. reciprocal.Add(thisPrec); //mantissa.Sign = false; //Shift down into 0.5 < this < 1 range thisPrec.mantissa.RSH(1); //Iteration. int accuracyBits = 2; int mantissaBits = mantissa.Precision.NumBits; //Each iteration is a pass of newton's method for RCP. //The is a substantial optimisation to be done here... //You can double the number of bits for the calculations //at each iteration, meaning that the whole process only //takes some constant multiplier of the time for the //full-scale multiplication. while (accuracyBits < mantissaBits) { //Increase the precision as needed if (accuracyBits >= curPrec.NumBits / 2) { int newBits = curPrec.NumBits * 2; if (newBits > mantissaBits) newBits = mantissaBits; curPrec = new PrecisionSpec(newBits, PrecisionSpec.BaseType.BIN); reciprocal = new BigFloat(reciprocal, curPrec); constant2 = new BigFloat(curPrec); constant2.exponent = 1; constant2.mantissa.SetHighDigit(0x80000000u); temp = new BigFloat(temp, curPrec); thisPrec = new BigFloat(this, curPrec); thisPrec.mantissa.Sign = true; thisPrec.mantissa.RSH(1); } //temp = Xn temp.exponent = reciprocal.exponent; temp.mantissa.Assign(reciprocal.mantissa); //temp = -Xn * D temp.Mul(thisPrec); //temp = -Xn * D + 2 (= 2 - Xn * D) temp.Add(constant2); //reciprocal = X(n+1) = Xn * (2 - Xn * D) reciprocal.Mul(temp); accuracyBits *= 2; } //'reciprocal' is now the reciprocal of the shifted down, zero-exponent mantissa of 'this' //Restore the mantissa. //mantissa.LSH(1); exponent = oldExponent; //mantissa.Sign = oldSign; if (topBit) { reciprocal.exponent = -(oldExponent); } else { reciprocal.exponent = -(oldExponent + 1); } reciprocal.mantissa.Sign = oldSign; return reciprocal; }
/// <summary> /// Constructs a bigint from the string, with the desired precision, using base 10 /// </summary> /// <param name="init"></param> /// <param name="precision"></param> public BigInt(string init, PrecisionSpec precision) { InitFromString(init, precision, 10); }