/// <summary> /// Returns the digits for the format spec, no sign is included. /// </summary> private static string DoubleToFormatString(CodeContext/*!*/ context, double self, StringFormatSpec/*!*/ spec) { self = Math.Abs(self); const int DefaultPrecision = 6; int precision = spec.Precision ?? DefaultPrecision; string digits; switch (spec.Type) { case '%': digits = self.ToString("0." + new string('0', precision) + "%", CultureInfo.InvariantCulture); break; case 'f': case 'F': digits = self.ToString("0." + new string('0', precision), CultureInfo.InvariantCulture); break; case 'e': digits = self.ToString("0." + new string('0', precision) + "e+00", CultureInfo.InvariantCulture); break; case 'E': digits = self.ToString("0." + new string('0', precision) + "E+00", CultureInfo.InvariantCulture); break; case '\0': case null: if (spec.Precision != null) { // precision applies to the combined digits before and after the decimal point // so we first need find out how many digits we have before... int digitCnt = 1; double cur = self; while (cur >= 10) { cur /= 10; digitCnt++; } // Use exponents if we don't have enough room for all the digits before. If we // only have as single digit avoid exponents. if (digitCnt > spec.Precision.Value && digitCnt != 1) { // first round off the decimal value self = MathUtils.RoundAwayFromZero(self, 0); // then remove any insignificant digits double pow = Math.Pow(10, digitCnt - Math.Max(spec.Precision.Value, 1)); self = self - (self % pow); // finally format w/ the requested precision string fmt = "0.0" + new string('#', spec.Precision.Value); digits = self.ToString(fmt + "e+00", CultureInfo.InvariantCulture); } else { // we're including all the numbers to the right of the decimal we can, we explicitly // round to match CPython's behavior int decimalPoints = Math.Max(spec.Precision.Value - digitCnt, 0); self = MathUtils.RoundAwayFromZero(self, decimalPoints); digits = self.ToString("0.0" + new string('#', decimalPoints)); } } else { // just the default formatting if (IncludeExponent(self)) { digits = self.ToString("0.#e+00", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.0###", CultureInfo.InvariantCulture); } } break; case 'n': case 'g': case 'G': { // precision applies to the combined digits before and after the decimal point // so we first need find out how many digits we have before... int digitCnt = 1; double cur = self; while (cur >= 10) { cur /= 10; digitCnt++; } // Use exponents if we don't have enough room for all the digits before. If we // only have as single digit avoid exponents. if (digitCnt > precision && digitCnt != 1) { // first round off the decimal value self = MathUtils.RoundAwayFromZero(self, 0); // then remove any insignificant digits double pow = Math.Pow(10, digitCnt - Math.Max(precision, 1)); double rest = self / pow; self = self - self % pow; if ((rest % 1) >= .5) { // round up self += pow; } string fmt; if (spec.Type == 'n' && PythonContext.GetContext(context).NumericCulture != PythonContext.CCulture) { // we've already figured out, we don't have any digits for decimal points, so just format as a number + exponent fmt = "0"; } else if (spec.Precision > 1 || digitCnt > 6) { // include the requested percision to the right of the decimal fmt = "0.#" + new string('#', precision); } else { // zero precision, no decimal fmt = "0"; } digits = self.ToString(fmt + (spec.Type == 'G' ? "E+00" : "e+00"), CultureInfo.InvariantCulture); } else { // we're including all the numbers to the right of the decimal we can, we explicitly // round to match CPython's behavior if (self < 1) { // no implicit 0 digitCnt--; } int decimalPoints = Math.Max(precision - digitCnt, 0); self = MathUtils.RoundAwayFromZero(self, decimalPoints); if (spec.Type == 'n' && PythonContext.GetContext(context).NumericCulture != PythonContext.CCulture) { if (digitCnt != precision && (self % 1) != 0) { digits = self.ToString("#,0.0" + new string('#', decimalPoints)); } else { // leave out the decimal if the precision == # of digits or we have a whole number digits = self.ToString("#,0"); } } else { if (digitCnt != precision && (self % 1) != 0) { digits = self.ToString("0.0" + new string('#', decimalPoints)); } else { // leave out the decimal if the precision == # of digits or we have a whole number digits = self.ToString("0"); } } } } break; default: throw PythonOps.ValueError("Unknown format code '{0}' for object of type 'float'", spec.Type.ToString()); } return digits; }
public static string /*!*/ __format__(CodeContext /*!*/ context, BigInteger /*!*/ self, [NotNull] string /*!*/ formatSpec) { StringFormatSpec spec = StringFormatSpec.FromString(formatSpec); if (spec.Precision != null) { throw PythonOps.ValueError("Precision not allowed in integer format specifier"); } BigInteger val = self; if (self < 0) { val = -self; } string digits; switch (spec.Type) { case 'n': CultureInfo culture = context.LanguageContext.NumericCulture; if (culture == CultureInfo.InvariantCulture) { // invariant culture maps to CPython's C culture, which doesn't // include any formatting info. goto case 'd'; } digits = FormattingHelper.ToCultureString(val, context.LanguageContext.NumericCulture.NumberFormat, spec); break; case null: case 'd': if (spec.ThousandsComma) { var width = spec.Width ?? 0; // If we're inserting commas, and we're padding with leading zeros. // AlignNumericText won't know where to place the commas, // so force .Net to help us out here. if (spec.Fill.HasValue && spec.Fill.Value == '0' && width > 1) { digits = val.ToString(FormattingHelper.ToCultureString(self, FormattingHelper.InvariantCommaNumberInfo, spec)); } else { digits = val.ToString("#,0", CultureInfo.InvariantCulture); } } else { digits = val.ToString("D", CultureInfo.InvariantCulture); } break; case '%': if (spec.ThousandsComma) { digits = val.ToString("#,0.000000%", CultureInfo.InvariantCulture); } else { digits = val.ToString("0.000000%", CultureInfo.InvariantCulture); } break; case 'e': if (spec.ThousandsComma) { digits = val.ToString("#,0.000000e+00", CultureInfo.InvariantCulture); } else { digits = val.ToString("0.000000e+00", CultureInfo.InvariantCulture); } break; case 'E': if (spec.ThousandsComma) { digits = val.ToString("#,0.000000E+00", CultureInfo.InvariantCulture); } else { digits = val.ToString("0.000000E+00", CultureInfo.InvariantCulture); } break; case 'f': case 'F': if (spec.ThousandsComma) { digits = val.ToString("#,########0.000000", CultureInfo.InvariantCulture); } else { digits = val.ToString("#########0.000000", CultureInfo.InvariantCulture); } break; case 'g': if (val >= 1000000) { digits = val.ToString("0.#####e+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { goto case 'd'; } else { digits = val.ToString(CultureInfo.InvariantCulture); } break; case 'G': if (val >= 1000000) { digits = val.ToString("0.#####E+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { goto case 'd'; } else { digits = val.ToString(CultureInfo.InvariantCulture); } break; case 'X': digits = AbsToHex(val, false); break; case 'x': digits = AbsToHex(val, true); break; case 'o': // octal digits = ToOctal(val, true); break; case 'b': // binary digits = ToBinary(val, false, true); break; case 'c': // single char int iVal; if (spec.Sign != null) { throw PythonOps.ValueError("Sign not allowed with integer format specifier 'c'"); } else if (!self.AsInt32(out iVal)) { throw PythonOps.OverflowError("long int too large to convert to int"); } else if (iVal < 0 || iVal > 0xFF) { throw PythonOps.OverflowError("%c arg not in range(0x10000)"); } digits = ScriptingRuntimeHelpers.CharToString((char)iVal); break; default: throw PythonOps.ValueError("Unknown format code '{0}'", spec.Type.ToString()); } Debug.Assert(digits[0] != '-'); return(spec.AlignNumericText(digits, self.IsZero(), self.IsPositive())); }
/// <summary> /// Returns the digits for the format spec, no sign is included. /// </summary> private static string DoubleToFormatString(CodeContext /*!*/ context, double self, StringFormatSpec /*!*/ spec) { self = Math.Abs(self); const int DefaultPrecision = 6; int precision = spec.Precision ?? DefaultPrecision; string digits; switch (spec.Type) { case '%': digits = self.ToString("0." + new string('0', precision) + "%", CultureInfo.InvariantCulture); break; case 'f': case 'F': digits = self.ToString("0." + new string('0', precision), CultureInfo.InvariantCulture); break; case 'e': digits = self.ToString("0." + new string('0', precision) + "e+00", CultureInfo.InvariantCulture); break; case 'E': digits = self.ToString("0." + new string('0', precision) + "E+00", CultureInfo.InvariantCulture); break; case '\0': case null: if (spec.Precision != null) { // precision applies to the combined digits before and after the decimal point // so we first need find out how many digits we have before... int digitCnt = 1; double cur = self; while (cur >= 10) { cur /= 10; digitCnt++; } // Use exponents if we don't have enough room for all the digits before. If we // only have as single digit avoid exponents. if (digitCnt > spec.Precision.Value && digitCnt != 1) { // first round off the decimal value self = MathUtils.RoundAwayFromZero(self, 0); // then remove any insignificant digits double pow = Math.Pow(10, digitCnt - Math.Max(spec.Precision.Value, 1)); self = self - (self % pow); // finally format w/ the requested precision string fmt = "0.0" + new string('#', spec.Precision.Value); digits = self.ToString(fmt + "e+00", CultureInfo.InvariantCulture); } else { // we're including all the numbers to the right of the decimal we can, we explicitly // round to match CPython's behavior int decimalPoints = Math.Max(spec.Precision.Value - digitCnt, 0); self = MathUtils.RoundAwayFromZero(self, decimalPoints); digits = self.ToString("0.0" + new string('#', decimalPoints)); } } else { // just the default formatting if (IncludeExponent(self)) { digits = self.ToString("0.#e+00", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.0###", CultureInfo.InvariantCulture); } } break; case 'n': case 'g': case 'G': { // precision applies to the combined digits before and after the decimal point // so we first need find out how many digits we have before... int digitCnt = 1; double cur = self; while (cur >= 10) { cur /= 10; digitCnt++; } // Use exponents if we don't have enough room for all the digits before. If we // only have as single digit avoid exponents. if (digitCnt > precision && digitCnt != 1) { // first round off the decimal value self = MathUtils.RoundAwayFromZero(self, 0); // then remove any insignificant digits double pow = Math.Pow(10, digitCnt - Math.Max(precision, 1)); double rest = self / pow; self = self - self % pow; if ((rest % 1) >= .5) { // round up self += pow; } string fmt; if (spec.Type == 'n' && PythonContext.GetContext(context).NumericCulture != PythonContext.CCulture) { // we've already figured out, we don't have any digits for decimal points, so just format as a number + exponent fmt = "0"; } else if (spec.Precision > 1 || digitCnt > 6) { // include the requested percision to the right of the decimal fmt = "0.#" + new string('#', precision); } else { // zero precision, no decimal fmt = "0"; } digits = self.ToString(fmt + (spec.Type == 'G' ? "E+00" : "e+00"), CultureInfo.InvariantCulture); } else { // we're including all the numbers to the right of the decimal we can, we explicitly // round to match CPython's behavior if (self < 1) { // no implicit 0 digitCnt--; } int decimalPoints = Math.Max(precision - digitCnt, 0); self = MathUtils.RoundAwayFromZero(self, decimalPoints); if (spec.Type == 'n' && PythonContext.GetContext(context).NumericCulture != PythonContext.CCulture) { if (digitCnt != precision && (self % 1) != 0) { digits = self.ToString("#,0.0" + new string('#', decimalPoints)); } else { // leave out the decimal if the precision == # of digits or we have a whole number digits = self.ToString("#,0"); } } else { if (digitCnt != precision && (self % 1) != 0) { digits = self.ToString("0.0" + new string('#', decimalPoints)); } else { // leave out the decimal if the precision == # of digits or we have a whole number digits = self.ToString("0"); } } } } break; default: throw PythonOps.ValueError("Unknown format code '{0}' for object of type 'float'", spec.Type.ToString()); } return(digits); }
public static string __format__(CodeContext /*!*/ context, int self, [NotNull] string /*!*/ formatSpec) { StringFormatSpec spec = StringFormatSpec.FromString(formatSpec); if (spec.Precision != null) { throw PythonOps.ValueError("Precision not allowed in integer format specifier"); } string digits; int width = 0; switch (spec.Type) { case 'n': CultureInfo culture = context.LanguageContext.NumericCulture; if (culture == CultureInfo.InvariantCulture) { // invariant culture maps to CPython's C culture, which doesn't // include any formatting info. goto case 'd'; } width = spec.Width ?? 0; // If we're padding with leading zeros and we might be inserting // culture sensitive number group separators. (i.e. commas) // So use FormattingHelper.ToCultureString for that support. if (spec.Fill.HasValue && spec.Fill.Value == '0' && width > 1) { digits = FormattingHelper.ToCultureString(self, culture.NumberFormat, spec); } else { digits = self.ToString("N0", culture); } break; case null: case 'd': if (spec.ThousandsComma) { width = spec.Width ?? 0; // If we're inserting commas, and we're padding with leading zeros. // AlignNumericText won't know where to place the commas, // so use FormattingHelper.ToCultureString for that support. if (spec.Fill.HasValue && spec.Fill.Value == '0' && width > 1) { digits = FormattingHelper.ToCultureString(self, FormattingHelper.InvariantCommaNumberInfo, spec); } else { digits = self.ToString("#,0", CultureInfo.InvariantCulture); } } else { digits = self.ToString("D", CultureInfo.InvariantCulture); } break; case '%': if (spec.ThousandsComma) { digits = self.ToString("#,0.000000%", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.000000%", CultureInfo.InvariantCulture); } break; case 'e': if (spec.ThousandsComma) { digits = self.ToString("#,0.000000e+00", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.000000e+00", CultureInfo.InvariantCulture); } break; case 'E': if (spec.ThousandsComma) { digits = self.ToString("#,0.000000E+00", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.000000E+00", CultureInfo.InvariantCulture); } break; case 'f': case 'F': if (spec.ThousandsComma) { digits = self.ToString("#,########0.000000", CultureInfo.InvariantCulture); } else { digits = self.ToString("#########0.000000", CultureInfo.InvariantCulture); } break; case 'g': if (self >= 1000000 || self <= -1000000) { digits = self.ToString("0.#####e+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { // Handle the common case in 'd'. goto case 'd'; } else { digits = self.ToString(CultureInfo.InvariantCulture); } break; case 'G': if (self >= 1000000 || self <= -1000000) { digits = self.ToString("0.#####E+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { // Handle the common case in 'd'. goto case 'd'; } else { digits = self.ToString(CultureInfo.InvariantCulture); } break; case 'X': digits = ToHex(self, false); break; case 'x': digits = ToHex(self, true); break; case 'o': // octal digits = ToOctal(self, true); break; case 'b': // binary digits = ToBinary(self, false); break; case 'c': // single char if (spec.Sign != null) { throw PythonOps.ValueError("Sign not allowed with integer format specifier 'c'"); } if (self < 0 || self > 0x10ffff) { throw PythonOps.OverflowError("%c arg not in range(0x110000)"); } digits = (self > char.MaxValue) ? char.ConvertFromUtf32(self) : ScriptingRuntimeHelpers.CharToString((char)self); break; default: throw PythonOps.ValueError("Unknown format code '{0}' for object of type 'int'", spec.TypeRepr); } if (self < 0 && digits[0] == '-') { digits = digits.Substring(1); } return(spec.AlignNumericText(digits, self == 0, self > 0)); }
public static string /*!*/ __format__(CodeContext /*!*/ context, BigInteger /*!*/ self, [NotNull] string /*!*/ formatSpec) { StringFormatSpec spec = StringFormatSpec.FromString(formatSpec); if (spec.Precision != null) { throw PythonOps.ValueError("Precision not allowed in integer format specifier"); } BigInteger val = self; if (self < 0) { val = -self; } string digits; switch (spec.Type) { case 'n': CultureInfo culture = PythonContext.GetContext(context).NumericCulture; if (culture == CultureInfo.InvariantCulture) { // invariant culture maps to CPython's C culture, which doesn't // include any formatting info. goto case 'd'; } digits = ToCultureString(val, PythonContext.GetContext(context).NumericCulture); break; #if CLR2 case null: case 'd': digits = val.ToString(); break; case '%': if (val == BigInteger.Zero) { digits = "0.000000%"; } else { digits = val.ToString() + "00.000000%"; } break; case 'e': digits = ToExponent(val, true, 6, 7); break; case 'E': digits = ToExponent(val, false, 6, 7); break; case 'f': if (val != BigInteger.Zero) { digits = val.ToString() + ".000000"; } else { digits = "0.000000"; } break; case 'F': if (val != BigInteger.Zero) { digits = val.ToString() + ".000000"; } else { digits = "0.000000"; } break; case 'g': if (val >= 1000000) { digits = ToExponent(val, true, 0, 6); } else { digits = val.ToString(); } break; case 'G': if (val >= 1000000) { digits = ToExponent(val, false, 0, 6); } else { digits = val.ToString(); } break; #else case null: case 'd': if (spec.ThousandsComma) { digits = val.ToString("#,0", CultureInfo.InvariantCulture); } else { digits = val.ToString("D", CultureInfo.InvariantCulture); } break; case '%': if (spec.ThousandsComma) { digits = val.ToString("#,0.000000%", CultureInfo.InvariantCulture); } else { digits = val.ToString("0.000000%", CultureInfo.InvariantCulture); } break; case 'e': if (spec.ThousandsComma) { digits = val.ToString("#,0.000000e+00", CultureInfo.InvariantCulture); } else { digits = val.ToString("0.000000e+00", CultureInfo.InvariantCulture); } break; case 'E': if (spec.ThousandsComma) { digits = val.ToString("#,0.000000E+00", CultureInfo.InvariantCulture); } else { digits = val.ToString("0.000000E+00", CultureInfo.InvariantCulture); } break; case 'f': case 'F': if (spec.ThousandsComma) { digits = val.ToString("#,########0.000000", CultureInfo.InvariantCulture); } else { digits = val.ToString("#########0.000000", CultureInfo.InvariantCulture); } break; case 'g': if (val >= 1000000) { digits = val.ToString("0.#####e+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { digits = val.ToString("#,0", CultureInfo.InvariantCulture); } else { digits = val.ToString(CultureInfo.InvariantCulture); } break; case 'G': if (val >= 1000000) { digits = val.ToString("0.#####E+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { digits = val.ToString("#,0", CultureInfo.InvariantCulture); } else { digits = val.ToString(CultureInfo.InvariantCulture); } break; #endif case 'X': digits = AbsToHex(val, false); break; case 'x': digits = AbsToHex(val, true); break; case 'o': // octal digits = ToOctal(val, true); break; case 'b': // binary digits = ToBinary(val, false, true); break; case 'c': // single char int iVal; if (spec.Sign != null) { throw PythonOps.ValueError("Sign not allowed with integer format specifier 'c'"); } else if (!self.AsInt32(out iVal)) { throw PythonOps.OverflowError("long int too large to convert to int"); } else if (iVal < 0 || iVal > 0xFF) { throw PythonOps.OverflowError("%c arg not in range(0x10000)"); } digits = digits = ScriptingRuntimeHelpers.CharToString((char)iVal); break; default: throw PythonOps.ValueError("Unknown format code '{0}'", spec.Type.ToString()); } Debug.Assert(digits[0] != '-'); return(spec.AlignNumericText(digits, self.IsZero(), self.IsPositive())); }
public static string __format__(CodeContext /*!*/ context, int self, [NotNull] string /*!*/ formatSpec) { StringFormatSpec spec = StringFormatSpec.FromString(formatSpec); if (spec.Precision != null) { throw PythonOps.ValueError("Precision not allowed in integer format specifier"); } string digits; switch (spec.Type) { case 'n': CultureInfo culture = PythonContext.GetContext(context).NumericCulture; if (culture == CultureInfo.InvariantCulture) { // invariant culture maps to CPython's C culture, which doesn't // include any formatting info. goto case 'd'; } digits = self.ToString("N0", PythonContext.GetContext(context).NumericCulture); break; case null: case 'd': if (spec.ThousandsComma) { digits = self.ToString("#,0", CultureInfo.InvariantCulture); } else { digits = self.ToString("D", CultureInfo.InvariantCulture); } break; case '%': if (spec.ThousandsComma) { digits = self.ToString("#,0.000000%", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.000000%", CultureInfo.InvariantCulture); } break; case 'e': if (spec.ThousandsComma) { digits = self.ToString("#,0.000000e+00", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.000000e+00", CultureInfo.InvariantCulture); } break; case 'E': if (spec.ThousandsComma) { digits = self.ToString("#,0.000000E+00", CultureInfo.InvariantCulture); } else { digits = self.ToString("0.000000E+00", CultureInfo.InvariantCulture); } break; case 'f': case 'F': if (spec.ThousandsComma) { digits = self.ToString("#,########0.000000", CultureInfo.InvariantCulture); } else { digits = self.ToString("#########0.000000", CultureInfo.InvariantCulture); } break; case 'g': if (self >= 1000000 || self <= -1000000) { digits = self.ToString("0.#####e+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { digits = self.ToString("#,0", CultureInfo.InvariantCulture); } else { digits = self.ToString(CultureInfo.InvariantCulture); } break; case 'G': if (self >= 1000000 || self <= -1000000) { digits = self.ToString("0.#####E+00", CultureInfo.InvariantCulture); } else if (spec.ThousandsComma) { digits = self.ToString("#,0", CultureInfo.InvariantCulture); } else { digits = self.ToString(CultureInfo.InvariantCulture); } break; case 'X': digits = ToHex(self, false); break; case 'x': digits = ToHex(self, true); break; case 'o': // octal digits = ToOctal(self, true); break; case 'b': // binary digits = ToBinary(self, false); break; case 'c': // single char if (spec.Sign != null) { throw PythonOps.ValueError("Sign not allowed with integer format specifier 'c'"); } if (self < 0 || self > 0xFF) { throw PythonOps.OverflowError("%c arg not in range(0x10000)"); } digits = ScriptingRuntimeHelpers.CharToString((char)self); break; default: throw PythonOps.ValueError("Unknown format code '{0}'", spec.Type.ToString()); } if (self < 0 && digits[0] == '-') { digits = digits.Substring(1); } return(spec.AlignNumericText(digits, self == 0, self > 0)); }