private string CreateExponentialRepresentation( DtoaBuilder buffer, int exponent, bool negative, int significantDigits) { bool negativeExponent = false; if (exponent < 0) { negativeExponent = true; exponent = -exponent; } using (var builder = StringBuilderPool.Rent()) { if (negative) { builder.Builder.Append('-'); } builder.Builder.Append(buffer._chars[0]); if (significantDigits != 1) { builder.Builder.Append('.'); builder.Builder.Append(buffer._chars, 1, buffer.Length - 1); int length = buffer.Length; builder.Builder.Append('0', significantDigits - length); } builder.Builder.Append('e'); builder.Builder.Append(negativeExponent ? '-' : '+'); builder.Builder.Append(exponent); return(builder.ToString()); } }
internal static string NumberToString( double m, DtoaBuilder builder, StringBuilder stringBuilder) { if (double.IsNaN(m)) { return("NaN"); } if (m == 0) { return("0"); } if (double.IsPositiveInfinity(m)) { return("Infinity"); } if (double.IsNegativeInfinity(m)) { return("-Infinity"); } DtoaNumberFormatter.DoubleToAscii( builder, m, DtoaMode.Shortest, 0, out var negative, out var decimal_point); if (negative) { stringBuilder.Append('-'); } if (builder.Length <= decimal_point && decimal_point <= 21) { // ECMA-262 section 9.8.1 step 6. stringBuilder.Append(builder._chars, 0, builder.Length); stringBuilder.Append('0', decimal_point - builder.Length); } else if (0 < decimal_point && decimal_point <= 21) { // ECMA-262 section 9.8.1 step 7. stringBuilder.Append(builder._chars, 0, decimal_point); stringBuilder.Append('.'); stringBuilder.Append(builder._chars, decimal_point, builder.Length - decimal_point); } else if (decimal_point <= 0 && decimal_point > -6) { // ECMA-262 section 9.8.1 step 8. stringBuilder.Append("0."); stringBuilder.Append('0', -decimal_point); stringBuilder.Append(builder._chars, 0, builder.Length); } else { // ECMA-262 section 9.8.1 step 9 and 10 combined. stringBuilder.Append(builder._chars[0]); if (builder.Length != 1) { stringBuilder.Append('.'); stringBuilder.Append(builder._chars, 1, builder.Length - 1); } stringBuilder.Append('e'); stringBuilder.Append((decimal_point >= 0) ? '+' : '-'); int exponent = decimal_point - 1; if (exponent < 0) { exponent = -exponent; } stringBuilder.Append(exponent); } return(stringBuilder.ToString()); }
private JsValue ToPrecision(JsValue thisObj, JsValue[] arguments) { if (!thisObj.IsNumber() && ReferenceEquals(thisObj.TryCast <NumberInstance>(), null)) { ExceptionHelper.ThrowTypeError(Engine); } var x = TypeConverter.ToNumber(thisObj); var precisionArgument = arguments.At(0); if (precisionArgument.IsUndefined()) { return(TypeConverter.ToString(x)); } var p = (int)TypeConverter.ToInteger(precisionArgument); if (double.IsNaN(x)) { return("NaN"); } if (double.IsInfinity(x)) { return(thisObj.ToString()); } if (p < 1 || p > 100) { ExceptionHelper.ThrowRangeError(_engine, "precision must be between 1 and 100"); } var dtoaBuilder = new DtoaBuilder(101); DtoaNumberFormatter.DoubleToAscii( dtoaBuilder, x, DtoaMode.Precision, p, out var negative, out var decimalPoint); int exponent = decimalPoint - 1; if (exponent < -6 || exponent >= p) { return(CreateExponentialRepresentation(dtoaBuilder, exponent, negative, p)); } using (var builder = StringBuilderPool.Rent()) { // Use fixed notation. if (negative) { builder.Builder.Append('-'); } if (decimalPoint <= 0) { builder.Builder.Append("0."); builder.Builder.Append('0', -decimalPoint); builder.Builder.Append(dtoaBuilder._chars, 0, dtoaBuilder.Length); builder.Builder.Append('0', p - dtoaBuilder.Length); } else { int m = System.Math.Min(dtoaBuilder.Length, decimalPoint); builder.Builder.Append(dtoaBuilder._chars, 0, m); builder.Builder.Append('0', System.Math.Max(0, decimalPoint - dtoaBuilder.Length)); if (decimalPoint < p) { builder.Builder.Append('.'); var extra = negative ? 2 : 1; if (dtoaBuilder.Length > decimalPoint) { int len = dtoaBuilder.Length - decimalPoint; int n = System.Math.Min(len, p - (builder.Builder.Length - extra)); builder.Builder.Append(dtoaBuilder._chars, decimalPoint, n); } builder.Builder.Append('0', System.Math.Max(0, extra + (p - builder.Builder.Length))); } } return(builder.ToString()); } }
/// <summary> /// https://www.ecma-international.org/ecma-262/6.0/#sec-number.prototype.toexponential /// </summary> private JsValue ToExponential(JsValue thisObj, JsValue[] arguments) { if (!thisObj.IsNumber() && ReferenceEquals(thisObj.TryCast <NumberInstance>(), null)) { ExceptionHelper.ThrowTypeError(Engine); } var x = TypeConverter.ToNumber(thisObj); var fractionDigits = arguments.At(0); if (fractionDigits.IsUndefined()) { fractionDigits = JsNumber.PositiveZero; } var f = (int)TypeConverter.ToInteger(fractionDigits); if (double.IsNaN(x)) { return("NaN"); } if (double.IsInfinity(x)) { return(thisObj.ToString()); } if (f < 0 || f > 100) { ExceptionHelper.ThrowRangeError(_engine, "fractionDigits argument must be between 0 and 100"); } if (arguments.At(0).IsUndefined()) { f = -1; } bool negative = false; if (x < 0) { x = -x; negative = true; } int decimalPoint; DtoaBuilder dtoaBuilder; if (f == -1) { dtoaBuilder = new DtoaBuilder(); DtoaNumberFormatter.DoubleToAscii( dtoaBuilder, x, DtoaMode.Shortest, requested_digits: 0, out _, out decimalPoint); f = dtoaBuilder.Length - 1; } else { dtoaBuilder = new DtoaBuilder(101); DtoaNumberFormatter.DoubleToAscii( dtoaBuilder, x, DtoaMode.Precision, requested_digits: f + 1, out _, out decimalPoint); } Debug.Assert(dtoaBuilder.Length > 0); Debug.Assert(dtoaBuilder.Length <= f + 1); int exponent = decimalPoint - 1; var result = CreateExponentialRepresentation(dtoaBuilder, exponent, negative, f + 1); return(result); }