/// <summary> /// Returns a base-10 string representing the number. /// /// Note: This is inefficient and possibly inaccurate. Please use with enough /// rounding digits (set using the RoundingDigits property) to ensure accuracy /// </summary> public override string ToString() { if (IsSpecialValue) { SpecialValueType s = SpecialValue; if (s == SpecialValueType.ZERO) { return String.Format("0{0}0", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); } else if (s == SpecialValueType.INF_PLUS) { return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PositiveInfinitySymbol; } else if (s == SpecialValueType.INF_MINUS) { return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeInfinitySymbol; } else if (s == SpecialValueType.NAN) { return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NaNSymbol; } else { return "Unrecognised special type"; } } if (scratch.Precision.NumBits != mantissa.Precision.NumBits) { scratch = new BigInt(mantissa.Precision); } //The mantissa expresses 1.xxxxxxxxxxx //The highest possible value for the mantissa without the implicit 1. is 0.9999999... scratch.Assign(mantissa); //scratch.Round(3); scratch.Sign = false; BigInt denom = new BigInt("0", mantissa.Precision); denom.SetBit(mantissa.Precision.NumBits - 1); bool useExponentialNotation = false; int halfBits = mantissa.Precision.NumBits / 2; if (halfBits > 60) halfBits = 60; int precDec = 10; if (exponent > 0) { if (exponent < halfBits) { denom.RSH(exponent); } else { useExponentialNotation = true; } } else if (exponent < 0) { int shift = -(exponent); if (shift < precDec) { scratch.RSH(shift); } else { useExponentialNotation = true; } } string output; if (useExponentialNotation) { int absExponent = exponent; if (absExponent < 0) absExponent = -absExponent; int powerOf10 = (int)((double)absExponent * Math.Log10(2.0)); //Use 1 extra digit of precision (this is actually 32 bits more, nb) BigFloat thisFloat = new BigFloat(this, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); thisFloat.mantissa.Sign = false; //Multiplicative correction factor to bring number into range. BigFloat one = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); BigFloat ten = new BigFloat(10, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); BigFloat tenRCP = ten.Reciprocal(); //Accumulator for the power of 10 calculation. BigFloat acc = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); BigFloat tenToUse; if (exponent > 0) { tenToUse = new BigFloat(tenRCP, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); } else { tenToUse = new BigFloat(ten, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); } BigFloat tenToPower = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN)); int powerTemp = powerOf10; //Fast power function while (powerTemp != 0) { tenToPower.Mul(tenToUse); tenToUse.Assign(tenToPower); if ((powerTemp & 1) != 0) { acc.Mul(tenToPower); } powerTemp >>= 1; } thisFloat.Mul(acc); //If we are out of range, correct. if (thisFloat.GreaterThan(ten)) { thisFloat.Mul(tenRCP); if (exponent > 0) { powerOf10++; } else { powerOf10--; } } else if (thisFloat.LessThan(one)) { thisFloat.Mul(ten); if (exponent > 0) { powerOf10--; } else { powerOf10++; } } //Restore the precision and the sign. BigFloat printable = new BigFloat(thisFloat, mantissa.Precision); printable.mantissa.Sign = mantissa.Sign; output = printable.ToString(); if (exponent < 0) powerOf10 = -powerOf10; output = String.Format("{0}E{1}", output, powerOf10); } else { BigInt bigDigit = BigInt.Div(scratch, denom); bigDigit.Sign = false; scratch.Sub(BigInt.Mul(denom, bigDigit)); if (mantissa.Sign) { output = String.Format("-{0}.", bigDigit); } else { output = String.Format("{0}.", bigDigit); } denom = BigInt.Div(denom, 10u); while (!denom.IsZero()) { uint digit = (uint)BigInt.Div(scratch, denom); if (digit == 10) digit--; scratch.Sub(BigInt.Mul(denom, digit)); output = String.Format("{0}{1}", output, digit); denom = BigInt.Div(denom, 10u); } output = RoundString(output, RoundingDigits); } return output; }