static class · System
NumberFormat
public static class NumberFormat
Numbers formatted as text (what the primitives' ToString(format) call).
- Tipo
- static class
- Espacio de nombres
- System
- Ensamblado
- System.Core
- Acceso
- public, static, abstract
- Archivo fuente
Format.ant
Herencia
- Clases base
-
AnyNumberFormat
Métodos
An integer (its bits, width of them, and whether its type is signed) by format.
A finite f64 as print writes it: the shortest digits that read back as the same number, in exponent
form (1e+20, 1.5e-07) when the exponent is below -4 or at least 15.
An f64 by format (G or R: the shortest text that reads back as the same number; nan, inf, -inf).
An f32 by format (no format, G or R: the shortest text that reads back as the same f32).
An f16 by format (no format, G or R: the shortest text that reads back as the same f16).
An f128 or f256 (its IEEE bits; width 128 or 256) by format: no format, G or R give the shortest text
that reads back as the same number; the fixed formats show up to 33 (f128) or 71 (f256) digits.
Miembros privados e internos (25)
ExactDigits(f64 x) : DecimalDigits
#
The exact digits of a finite f64 (every f64 is a finite decimal).
ExactOf(u64 mantissa, i32 e2, bool negative) : DecimalDigits
#
The exact digits of mantissa × 2^e2.
limbs = value (base 10^9); the count.
The decimal digits of a base-10^9 integer, over 10^shift: the first limit of them, then (when the rest is not
all zeros) a 1 standing for the rest, which keeps comparisons and rounding to fewer digits exact.
ExactWide(u256 mantissa, i32 e2, bool negative) : DecimalDigits
#
The exact digits of a wide mantissa × 2^e2 (an f128 or f256).
limbs = value (base 10^9); the count.
a × factor (a wide integer: up to nine limbs), base 10^9, into result; the count.
The shortest digits that read back as the same wide float (see ShortestOf).
a × factor (factor < 10^18: two limbs), base 10^9, into result; the count.
a + b or a - b (a ≥ b), base 10^9, into result; the count.
limbs × factor (factor < 2^34), in place; the new count.
IntegerDigits(u64 magnitude, bool negative) : DecimalDigits
#
The digits of an integer's magnitude.
A format's letter (0 for none: general) and precision (-1 for none).
Fixed(NumberText text, DecimalDigits d, i32 decimals, bool groups)
#
Fixed point: the integer digits (grouped by three with commas when groups), then decimals decimals.
Scientific(NumberText text, DecimalDigits d, i32 decimals, u8 letter, i32 exponentDigits)
#
Exponent form: one digit, decimals more after the point, then E (or e), the sign and exponentDigits or more.
General(NumberText text, DecimalDigits d, i32 precision, i32 scientificFrom, u8 letter)
#
General: precision significant digits (all of them when 0 or less), in exponent form when the exponent is
below -4 or at least scientificFrom; trailing zeros dropped.
Digits(NumberText text, DecimalDigits d, u8 letter, i32 precision, i32 generalPrecision, i32 scientificFrom) : bool
#
The digits by a format letter (not D, X, B: those are integers' own).
Shortest(f64 value) : DecimalDigits
#
The shortest digits that read back as the same f64 (the nearest of that length): those strictly between the midpoints to its neighbours (or on them, when its mantissa is even and reading rounds to it).
ShortestSingle(f32 value) : DecimalDigits
#
RoundInto(DecimalDigits d, i32 keep, DecimalDigits target)
#
d rounded to keep digits, into target (its array has room): only the digits that decide it are copied
(what follows the next one, never all zeros, stands as a 1).
Compare(DecimalDigits a, DecimalDigits b) : i32
#
Which of two positive numbers is larger (-1, 0, 1).
Miembros heredados (5)
GetTypemétodo de AnyUndescribedmétodo de AnyToStringmétodo de AnyHashmétodo de Anydestroymétodo de Any
Código fuente
NumberFormat en Antril, descompilado a partir de su Larva HIR.
// System.NumberFormat — System.Core (decompiled from Larva HIR)
into namespace System
{
/// Numbers formatted as text (what the primitives' `ToString(format)` call).
public static class NumberFormat
{
/// The exact digits of a finite f64 (every f64 is a finite decimal).
ExactDigits(f64 x) : DecimalDigits
{
i64 bits = Float64.Bits(x);
bool negative = bits < 0;
i32 biased = (i32)(bits >> 52 & 2047);
u64 mantissa = (u64)bits & 4503599627370495;
i32 e2 = -1074;
if (biased != 0)
{
mantissa |= 4503599627370496;
e2 = biased - 1075;
}
return ExactOf(mantissa, e2, negative);
}
/// The exact digits of mantissa × 2^e2.
ExactOf(u64 mantissa, i32 e2, bool negative) : DecimalDigits
{
if (mantissa == 0)
return new DecimalDigits(new u8[1], 0, 0, negative);
loop ((mantissa & 1) == 0)
{
mantissa = mantissa >> 1;
e2++;
}
i32 k = e2 < 0 ? -e2 : 0;
u32[] limbs = new u32[4 + (e2 >= 0 ? e2 / 29 : k * 7 / 29)];
i32 used = Set(limbs, mantissa);
used = e2 > 0 ? TimesPowerOfTwo(limbs, used, e2) : TimesPowerOfFive(limbs, used, k);
return DigitsOf(limbs, used, k, negative, 2147483646);
}
/// limbs = value (base 10^9); the count.
Set(u32[] limbs, u64 value) : i32
{
i32 used = 0;
loop (value > 0)
{
limbs[used] = (u32)(value % 1000000000);
value = value / 1000000000;
used++;
}
return used;
}
TimesPowerOfTwo(u32[] limbs, i32 used, i32 power) : i32
{
loop (power > 0)
{
i32 step = power < 29 ? power : 29;
used = Multiply(limbs, used, 1 << (u64)step);
power -= step;
}
return used;
}
TimesPowerOfFive(u32[] limbs, i32 used, i32 power) : i32
{
loop (power > 0)
{
i32 step = power < 13 ? power : 13;
u64 factor = 1;
loop (i32 s = 0..step)
factor *= 5;
used = Multiply(limbs, used, factor);
power -= step;
}
return used;
}
/// The decimal digits of a base-10^9 integer, over 10^shift: the first `limit` of them, then (when the rest is not
/// all zeros) a 1 standing for the rest, which keeps comparisons and rounding to fewer digits exact.
DigitsOf(u32[] limbs, i32 used, i32 shift, bool negative, i32 limit) : DecimalDigits
{
if (used == 0)
return new DecimalDigits(new u8[1], 0, 0, negative);
u32 top = limbs[used - 1];
i32 topDigits = 1;
loop (u32 t = top; t >= 10; t = t / 10)
topDigits++;
i32 total = topDigits + (used - 1) * 9;
i32 keep = total < limit ? total : limit;
u8[] digits = new u8[keep + 1];
bool rest = false;
i32 end = topDigits;
loop (i32 l = used - 1; l >= 0; l--)
{
u32 limb = limbs[l];
i32 width = l == used - 1 ? topDigits : 9;
i32 start = end - width;
if (start >= keep)
{
if (limb != 0)
rest = true;
if (rest)
break;
}
else
{
loop (i32 at = end - 1; at >= start; at--)
{
u32 digit = limb % 10;
limb = limb / 10;
if (at < keep)
digits[at] = (u8)digit;
else if (digit != 0)
rest = true;
}
}
end += 9;
}
i32 count = keep;
if (rest)
{
digits[count] = 1;
count++;
}
DecimalDigits result = new DecimalDigits(digits, count, total - shift, negative);
result.Trim();
return result;
}
/// The exact digits of a wide mantissa × 2^e2 (an f128 or f256).
ExactWide(u256 mantissa, i32 e2, bool negative) : DecimalDigits
{
if (mantissa == 0)
return new DecimalDigits(new u8[1], 0, 0, negative);
loop ((mantissa & 1) == 0)
{
mantissa = mantissa >> 1;
e2++;
}
i32 k = e2 < 0 ? -e2 : 0;
u32[] limbs = new u32[13 + (e2 >= 0 ? e2 / 29 : k * 7 / 29)];
i32 used = SetWide(limbs, mantissa);
used = e2 > 0 ? TimesPowerOfTwo(limbs, used, e2) : TimesPowerOfFive(limbs, used, k);
return DigitsOf(limbs, used, k, negative, 2147483646);
}
/// limbs = value (base 10^9); the count.
SetWide(u32[] limbs, u256 value) : i32
{
i32 used = 0;
loop (value > 0)
{
limbs[used] = (u32)(value % 1000000000);
value = value / 1000000000;
used++;
}
return used;
}
/// a × factor (a wide integer: up to nine limbs), base 10^9, into `result`; the count.
TimesWide(u32[] a, i32 used, u256 factor, u32[] result) : i32
{
u32[] f = new u32[9];
i32 count = SetWide(f, factor);
i32 end = used + count + 1;
loop (i32 i = 0..end)
result[i] = 0;
loop (i32 i = 0..used)
{
u64 carry = 0;
loop (i32 j = 0..count)
{
u64 product = (u64)a[i] * (u64)f[j] + (u64)result[i + j] + carry;
result[i + j] = (u32)(product % 1000000000);
carry = product / 1000000000;
}
i32 at = i + count;
loop (carry > 0)
{
u64 sum = (u64)result[at] + carry;
result[at] = (u32)(sum % 1000000000);
carry = sum / 1000000000;
at++;
}
}
loop (end > 0 && result[end - 1] == 0)
end--;
return end;
}
/// The shortest digits that read back as the same wide float (see ShortestOf).
ShortestWide(u256 mantissa, i32 e2, bool boundary, i32 most) : DecimalDigits
{
if (mantissa == 0)
return new DecimalDigits(new u8[1], 0, 0, false);
i32 scale = boundary ? 2 : 1;
i32 unitExponent = e2 - scale;
i32 k = unitExponent < 0 ? -unitExponent : 0;
i32 room = 16 + (unitExponent >= 0 ? unitExponent / 29 : k * 7 / 29);
u32[] unit = new u32[room];
i32 unitUsed = Set(unit, 1);
unitUsed = unitExponent > 0 ? TimesPowerOfTwo(unit, unitUsed, unitExponent) : TimesPowerOfFive(unit, unitUsed, k);
u32[] center = new u32[room];
i32 centerUsed = TimesWide(unit, unitUsed, mantissa << (u256)scale, center);
u32[] step = new u32[room];
loop (i32 i = 0..unitUsed)
step[i] = unit[i];
i32 stepUsed = boundary ? Multiply(step, unitUsed, 2) : unitUsed;
u32[] side = new u32[room];
i32 sideUsed = AddOrSubtract(center, centerUsed, step, stepUsed, true, side);
DecimalDigits exact = DigitsOf(center, centerUsed, k, false, most + 2);
DecimalDigits high = DigitsOf(side, sideUsed, k, false, most + 2);
sideUsed = AddOrSubtract(center, centerUsed, unit, unitUsed, false, side);
DecimalDigits low = DigitsOf(side, sideUsed, k, false, most + 2);
bool even = (mantissa & 1) == 0;
DecimalDigits scratch = new DecimalDigits(new u8[most + 2], 0, 0, false);
i32 shared = 0;
if (low.Point == high.Point)
{
loop (shared < most && low[shared] == high[shared])
shared++;
}
i32 lowest = shared > 1 ? shared : 1;
i32 last = most < exact.Count ? most : exact.Count;
loop (lowest < last)
{
RoundInto(exact, lowest, scratch);
i32 below = Compare(low, scratch);
i32 above = Compare(scratch, high);
if ((below < 0 || even && below == 0) && (above < 0 || even && above == 0))
break;
lowest++;
}
RoundInto(exact, lowest, scratch);
u8[] digits = new u8[scratch.Count > 0 ? scratch.Count : 1];
loop (i32 i = 0..scratch.Count)
digits[i] = scratch.Digits[i];
return new DecimalDigits(digits, scratch.Count, scratch.Point, false);
}
/// a × factor (factor < 10^18: two limbs), base 10^9, into `result`; the count.
TimesLarge(u32[] a, i32 used, u64 factor, u32[] result) : i32
{
u64 f0 = factor % 1000000000;
u64 f1 = factor / 1000000000;
loop (i32 i = 0..used + 3)
result[i] = 0;
u64 carry = 0;
loop (i32 i = 0..used)
{
u64 product = (u64)a[i] * f0 + (u64)result[i] + carry;
result[i] = (u32)(product % 1000000000);
carry = product / 1000000000;
}
i32 end = used;
loop (carry > 0)
{
result[end] = (u32)(carry % 1000000000);
carry = carry / 1000000000;
end++;
}
if (f1 > 0)
{
carry = 0;
loop (i32 i = 0..used)
{
u64 product = (u64)a[i] * f1 + (u64)result[i + 1] + carry;
result[i + 1] = (u32)(product % 1000000000);
carry = product / 1000000000;
}
i32 at = used + 1;
loop (carry > 0)
{
u64 sum = (u64)result[at] + carry;
result[at] = (u32)(sum % 1000000000);
carry = sum / 1000000000;
at++;
}
if (at > end)
end = at;
}
loop (end > 0 && result[end - 1] == 0)
end--;
return end;
}
/// a + b or a - b (a ≥ b), base 10^9, into `result`; the count.
AddOrSubtract(u32[] a, i32 aUsed, u32[] b, i32 bUsed, bool add, u32[] result) : i32
{
i64 carry = 0;
i32 used = aUsed > bUsed ? aUsed : bUsed;
loop (i32 i = 0..used)
{
i64 sum = (i < aUsed ? (i64)a[i] : 0) + carry + (add ? i < bUsed ? (i64)b[i] : 0 : -(i < bUsed ? (i64)b[i] : 0));
carry = 0;
if (sum >= 1000000000)
{
sum -= 1000000000;
carry = 1;
}
else if (sum < 0)
{
sum += 1000000000;
carry = -1;
}
result[i] = (u32)sum;
}
if (carry > 0)
{
result[used] = (u32)carry;
used++;
}
loop (used > 0 && result[used - 1] == 0)
used--;
return used;
}
/// limbs × factor (factor < 2^34), in place; the new count.
Multiply(u32[] limbs, i32 used, u64 factor) : i32
{
u64 carry = 0;
loop (i32 i = 0..used)
{
u64 product = (u64)limbs[i] * factor + carry;
limbs[i] = (u32)(product % 1000000000);
carry = product / 1000000000;
}
loop (carry > 0)
{
limbs[used] = (u32)(carry % 1000000000);
carry = carry / 1000000000;
used++;
}
return used;
}
/// The digits of an integer's magnitude.
IntegerDigits(u64 magnitude, bool negative) : DecimalDigits
{
u8[] digits = new u8[20];
i32 count = 0;
loop (u64 m = magnitude; m > 0; m = m / 10)
count++;
u64 rest = magnitude;
loop (i32 d = count - 1; d >= 0; d--)
{
digits[d] = (u8)(rest % 10);
rest = rest / 10;
}
DecimalDigits result = new DecimalDigits(digits, count, count, negative);
result.Trim();
return result;
}
/// A format's letter (0 for none: general) and precision (-1 for none).
Letter(str format) : u8
{
if (format.Length == 0)
return 71;
u8 letter = format.Units()[0];
return letter;
}
Precision(str format) : i32
{
u8[] bytes = format.Units();
if (bytes.Length <= 1)
return -1;
i32 value = 0;
loop (i32 i = 1..bytes.Length)
{
u8 c = bytes[i];
if (c < 48 || c > 57 || value > 99999)
throw new FormatError("bad number format: " + format);
value = value * 10 + ((i32)c - 48);
}
return value;
}
/// Fixed point: the integer digits (grouped by three with commas when `groups`), then `decimals` decimals.
Fixed(NumberText text, DecimalDigits d, i32 decimals, bool groups)
{
if (d.Point <= 0)
{
text.Add(48);
}
else
{
loop (i32 i = 0..d.Point)
{
if (groups && i > 0 && (d.Point - i) % 3 == 0)
text.Add(44);
text.Add(48 + d[i]);
}
}
if (decimals > 0)
{
text.Add(46);
loop (i32 i = d.Point..d.Point + decimals)
text.Add(48 + d[i]);
}
}
/// Exponent form: one digit, `decimals` more after the point, then E (or e), the sign and `exponentDigits` or more.
Scientific(NumberText text, DecimalDigits d, i32 decimals, u8 letter, i32 exponentDigits)
{
text.Add(48 + d[0]);
if (decimals > 0)
{
text.Add(46);
loop (i32 i = 1..decimals + 1)
text.Add(48 + d[i]);
}
i32 exponent = d.Count == 0 ? 0 : d.Point - 1;
text.Add(letter);
text.Add(exponent < 0 ? 45 : 43);
i32 magnitude = exponent < 0 ? -exponent : exponent;
i32 width = 1;
loop (i32 m = magnitude; m >= 10; m = m / 10)
width++;
loop (i32 pad = width..exponentDigits)
text.Add(48);
text.Number(magnitude);
}
/// General: `precision` significant digits (all of them when 0 or less), in exponent form when the exponent is
/// below -4 or at least `scientificFrom`; trailing zeros dropped.
General(NumberText text, DecimalDigits d, i32 precision, i32 scientificFrom, u8 letter)
{
if (precision > 0)
d.Round(precision);
d.Trim();
if (d.Count == 0)
{
text.Add(48);
return;
}
i32 exponent = d.Point - 1;
if (exponent < -4 || exponent >= scientificFrom)
{
Scientific(text, d, d.Count - 1, letter == 103 ? 101 : 69, 2);
return;
}
i32 decimals = d.Count - d.Point;
Fixed(text, d, decimals > 0 ? decimals : 0, false);
}
/// The digits by a format letter (not D, X, B: those are integers' own).
Digits(NumberText text, DecimalDigits d, u8 letter, i32 precision, i32 generalPrecision, i32 scientificFrom) : bool
{
switch (letter)
{
70 or 102 =>
{
i32 decimals = precision < 0 ? 2 : precision;
d.Round(d.Point + decimals);
Fixed(text, d, decimals, false);
}
78 or 110 =>
{
i32 decimals = precision < 0 ? 2 : precision;
d.Round(d.Point + decimals);
Fixed(text, d, decimals, true);
}
69 or 101 =>
{
i32 decimals = precision < 0 ? 6 : precision;
d.Round(decimals + 1);
Scientific(text, d, decimals, letter, 3);
}
80 or 112 =>
{
i32 decimals = precision < 0 ? 2 : precision;
d.Point += 2;
d.Round(d.Point + decimals);
Fixed(text, d, decimals, true);
text.Add(32);
text.Add(37);
}
71 or 103 =>
General(text, d, precision > 0 ? precision : generalPrecision, precision > 0 ? precision : scientificFrom, letter);
_ =>
return false;
}
return true;
}
/// The shortest digits that read back as the same f64 (the nearest of that length): those strictly between
/// the midpoints to its neighbours (or on them, when its mantissa is even and reading rounds to it).
Shortest(f64 value) : DecimalDigits
{
i64 bits = Float64.Bits(value) & 9223372036854775807;
i32 biased = (i32)(bits >> 52);
u64 mantissa = (u64)bits & 4503599627370495;
i32 e2 = -1074;
if (biased != 0)
{
mantissa |= 4503599627370496;
e2 = biased - 1075;
}
return ShortestOf(mantissa, e2, biased > 1 && mantissa == 4503599627370496, 17);
}
ShortestSingle(f32 value) : DecimalDigits
{
u32 bits = Float32.Bits(value) & 2147483647;
i32 biased = (i32)(bits >> 23);
u64 mantissa = (u64)bits & 8388607;
i32 e2 = -149;
if (biased != 0)
{
mantissa |= 8388608;
e2 = biased - 150;
}
return ShortestOf(mantissa, e2, biased > 1 && mantissa == 8388608, 9);
}
ShortestOf(u64 mantissa, i32 e2, bool boundary, i32 most) : DecimalDigits
{
if (mantissa == 0)
return new DecimalDigits(new u8[1], 0, 0, false);
i32 scale = boundary ? 2 : 1;
i32 unitExponent = e2 - scale;
i32 k = unitExponent < 0 ? -unitExponent : 0;
i32 room = 6 + (unitExponent >= 0 ? unitExponent / 29 : k * 7 / 29);
u32[] unit = new u32[room];
i32 unitUsed = Set(unit, 1);
unitUsed = unitExponent > 0 ? TimesPowerOfTwo(unit, unitUsed, unitExponent) : TimesPowerOfFive(unit, unitUsed, k);
u32[] center = new u32[room];
i32 centerUsed = TimesLarge(unit, unitUsed, mantissa << (u64)scale, center);
u32[] step = new u32[room];
loop (i32 i = 0..unitUsed)
step[i] = unit[i];
i32 stepUsed = boundary ? Multiply(step, unitUsed, 2) : unitUsed;
u32[] side = new u32[room];
i32 sideUsed = AddOrSubtract(center, centerUsed, step, stepUsed, true, side);
DecimalDigits exact = DigitsOf(center, centerUsed, k, false, most + 2);
DecimalDigits high = DigitsOf(side, sideUsed, k, false, most + 2);
sideUsed = AddOrSubtract(center, centerUsed, unit, unitUsed, false, side);
DecimalDigits low = DigitsOf(side, sideUsed, k, false, most + 2);
bool even = (mantissa & 1) == 0;
DecimalDigits scratch = new DecimalDigits(new u8[most + 2], 0, 0, false);
i32 shared = 0;
if (low.Point == high.Point)
{
loop (shared < most && low[shared] == high[shared])
shared++;
}
i32 lowest = shared > 1 ? shared : 1;
i32 last = most < exact.Count ? most : exact.Count;
loop (lowest < last)
{
RoundInto(exact, lowest, scratch);
i32 below = Compare(low, scratch);
i32 above = Compare(scratch, high);
if ((below < 0 || even && below == 0) && (above < 0 || even && above == 0))
break;
lowest++;
}
RoundInto(exact, lowest, scratch);
u8[] digits = new u8[scratch.Count > 0 ? scratch.Count : 1];
loop (i32 i = 0..scratch.Count)
digits[i] = scratch.Digits[i];
return new DecimalDigits(digits, scratch.Count, scratch.Point, false);
}
/// `d` rounded to `keep` digits, into `target` (its array has room): only the digits that decide it are copied
/// (what follows the next one, never all zeros, stands as a 1).
RoundInto(DecimalDigits d, i32 keep, DecimalDigits target)
{
bool more = d.Count > keep + 1;
i32 count = more ? keep + 2 : d.Count;
u8[] digits = target.Digits;
loop (i32 i = 0..count)
digits[i] = i == keep + 1 ? 1 : d.Digits[i];
target.Count = count;
target.Point = d.Point;
target.Round(keep);
}
/// Which of two positive numbers is larger (-1, 0, 1).
Compare(DecimalDigits a, DecimalDigits b) : i32
{
if (a.Point != b.Point)
return a.Point < b.Point ? -1 : 1;
i32 n = a.Count > b.Count ? a.Count : b.Count;
loop (i32 i = 0..n)
{
u8 x = a[i];
u8 y = b[i];
if (x != y)
return x < y ? -1 : 1;
}
return 0;
}
public:
/// An integer (its bits, `width` of them, and whether its type is signed) by `format`.
FormatInteger(u64 bits, i32 width, bool signed, str format) : str
{
u8 letter = Letter(format);
i32 precision = Precision(format);
bool negative = signed && width < 64 ? (bits >> (u64)(width - 1) & 1) == 1 : signed && (i64)bits < 0;
u64 masked = width < 64 ? bits & (1 << (u64)width) - 1 : bits;
u64 magnitude = negative ? 0 - masked & (width < 64 ? (1 << (u64)width) - 1 : 18446744073709551615) : masked;
if (letter == 68 || letter == 100)
{
i32 count = 1;
loop (u64 m = magnitude / 10; m > 0; m = m / 10)
count++;
i32 size = count > precision ? count : precision;
u8[] units = new u8[size + (negative ? 1 : 0)];
i32 at = units.Length;
u64 rest = magnitude;
loop (i32 i = 0..size)
{
at--;
units[at] = (u8)(48 + rest % 10);
rest = rest / 10;
}
if (negative)
units[0] = 45;
return new str(units);
}
if (letter == 88 || letter == 120 || letter == 66 || letter == 98)
{
i32 shift = letter == 66 || letter == 98 ? 1 : 4;
u64 digitMask = (1 << (u64)shift) - 1;
i32 count = 1;
loop (u64 m = masked >> (u64)shift; m > 0; m = m >> (u64)shift)
count++;
i32 size = count > precision ? count : precision;
u8[] units = new u8[size];
u8 letters = letter == 120 ? 87 : 55;
u64 rest = masked;
loop (i32 at = size - 1; at >= 0; at--)
{
u8 digit = (u8)(rest & digitMask);
units[at] = digit < 10 ? 48 + digit : letters + digit;
rest = rest >> (u64)shift;
}
return new str(units);
}
NumberText text = new NumberText();
switch (letter)
{
_ =>
{
DecimalDigits d = IntegerDigits(magnitude, negative);
if (negative)
text.Add(45);
if (!Digits(text, d, letter, precision, 0, 1000))
throw new FormatError("bad number format: " + format);
}
}
return text.Made();
}
FormatInteger(i64 value, str format) : str => FormatInteger((u64)value, 64, true, format);
/// A finite f64 as `print` writes it: the shortest digits that read back as the same number, in exponent
/// form (`1e+20`, `1.5e-07`) when the exponent is below -4 or at least 15.
ShortestDouble(f64 value) : str
{
NumberText text = new NumberText();
if (Float64.Bits(value) < 0)
text.Add(45);
General(text, Shortest(value), 0, 15, 103);
return text.Made();
}
/// An f64 by `format` (G or R: the shortest text that reads back as the same number; `nan`, `inf`, `-inf`).
FormatDouble(f64 value, str format) : str
{
if (value != value)
return "nan";
if (value - value != 0.0)
return value > 0.0 ? "inf" : "-inf";
u8 letter = Letter(format);
i32 precision = Precision(format);
NumberText text = new NumberText();
if (Float64.Bits(value) < 0)
text.Add(45);
if ((letter == 71 || letter == 103) && precision <= 0 || letter == 82 || letter == 114)
{
General(text, Shortest(value), 0, 17, letter == 103 ? 103 : 71);
return text.Made();
}
if (!Digits(text, ExactDigits(value), letter, precision, 15, 15))
throw new FormatError("bad number format: " + format);
return text.Made();
}
/// An f32 by `format` (no format, G or R: the shortest text that reads back as the same f32).
FormatSingle(f32 value, str format) : str
{
if (value != value)
return "nan";
if (value - value != 0.0)
return value > 0.0 ? "inf" : "-inf";
u8 letter = Letter(format);
i32 precision = Precision(format);
NumberText text = new NumberText();
if (Float32.Bits(value) >= 2147483648)
text.Add(45);
if ((letter == 71 || letter == 103) && precision <= 0 || letter == 82 || letter == 114)
{
General(text, ShortestSingle(value), 0, 9, letter == 103 ? 103 : 71);
return text.Made();
}
if (!Digits(text, ExactDigits(value), letter, precision, 7, 7))
throw new FormatError("bad number format: " + format);
return text.Made();
}
/// An f16 by `format` (no format, G or R: the shortest text that reads back as the same f16).
FormatHalf(f16 value, str format) : str
{
u16 bits = Float16.Bits(value);
bool negative = bits >= 32768;
i32 biased = (i32)(bits >> 10) & 31;
u64 mantissa = (u64)bits & 1023;
if (biased == 31)
return mantissa != 0 ? "nan" : negative ? "-inf" : "inf";
i32 e2 = -24;
if (biased != 0)
{
mantissa |= 1024;
e2 = biased - 25;
}
u8 letter = Letter(format);
i32 precision = Precision(format);
NumberText text = new NumberText();
if (negative)
text.Add(45);
if ((letter == 71 || letter == 103) && precision <= 0 || letter == 82 || letter == 114)
{
General(text, ShortestOf(mantissa, e2, biased > 1 && mantissa == 1024, 5), 0, 5, letter == 103 ? 103 : 71);
return text.Made();
}
if (!Digits(text, ExactOf(mantissa, e2, negative), letter, precision, 3, 3))
throw new FormatError("bad number format: " + format);
return text.Made();
}
/// An f128 or f256 (its IEEE bits; `width` 128 or 256) by `format`: no format, G or R give the shortest text
/// that reads back as the same number; the fixed formats show up to 33 (f128) or 71 (f256) digits.
FormatWide(u256 bits, i32 width, str format) : str
{
i32 exponentBits = width == 128 ? 15 : 19;
i32 fractionBits = width - 1 - exponentBits;
i32 bias = (1 << exponentBits - 1) - 1;
i32 exponentMask = (1 << exponentBits) - 1;
bool negative = bits >> (u256)(width - 1) != 0;
i32 biased = (i32)(bits >> (u256)fractionBits & (u256)exponentMask);
u256 hidden = 1 << (u256)fractionBits;
u256 mantissa = bits & hidden - 1;
if (biased == exponentMask)
return mantissa != 0 ? "nan" : negative ? "-inf" : "inf";
i32 e2 = 1 - bias - fractionBits;
if (biased != 0)
{
mantissa |= hidden;
e2 = biased - bias - fractionBits;
}
u8 letter = Letter(format);
i32 precision = Precision(format);
i32 most = width == 128 ? 36 : 72;
i32 exact = width == 128 ? 33 : 71;
NumberText text = new NumberText();
if (negative)
text.Add(45);
if ((letter == 71 || letter == 103) && precision <= 0 || letter == 82 || letter == 114)
{
General(text, ShortestWide(mantissa, e2, biased > 1 && mantissa == hidden, most), 0, most, letter == 103 ? 103 : 71);
return text.Made();
}
if (!Digits(text, ExactWide(mantissa, e2, negative), letter, precision, exact, exact))
throw new FormatError("bad number format: " + format);
return text.Made();
}
}
}