summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-11-28 09:32:20 +0100
committerEugen Wissner <belka@caraus.de>2017-11-28 09:32:20 +0100
commitc199cdd47c33bed20f0fdcc1bd8803df69b282b3 (patch)
treeba62317c1b36e653da560c4a5ba9861414aace76
parent3a24e9e462b7319419d06610a08e15db2e8c9b98 (diff)
downloadtanya-c199cdd47c33bed20f0fdcc1bd8803df69b282b3.tar.gz
Merge changes to reals formatting from master
-rw-r--r--source/tanya/format/package.d867
1 files changed, 413 insertions, 454 deletions
diff --git a/source/tanya/format/package.d b/source/tanya/format/package.d
index 44c079c..70b32c7 100644
--- a/source/tanya/format/package.d
+++ b/source/tanya/format/package.d
@@ -17,11 +17,138 @@ module tanya.format;
import tanya.container.string;
import tanya.encoding.ascii;
public import tanya.format.conv;
+import tanya.math;
import tanya.memory.op;
import tanya.meta.metafunction;
import tanya.meta.trait;
import tanya.range.array;
+// Integer and floating point to string conversion is based on stb_sprintf
+// written by Jeff Roberts.
+
+// Returns the last part of buffer with converted number.
+package(tanya) char[] integral2String(T)(T number, return ref char[21] buffer)
+if (isIntegral!T)
+{
+ // abs the integer.
+ ulong n64 = number < 0 ? -cast(long) number : number;
+
+ char* start = buffer[].ptr + buffer.sizeof - 1;
+
+ while (true)
+ {
+ // Do in 32-bit chunks (avoid lots of 64-bit divides even with constant
+ // denominators).
+ char* o = start - 8;
+ uint n;
+ if (n64 >= 100000000)
+ {
+ n = n64 % 100000000;
+ n64 /= 100000000;
+ }
+ else
+ {
+ n = cast(uint) n64;
+ n64 = 0;
+ }
+
+ while (n)
+ {
+ *--start = cast(char) (n % 10) + '0';
+ n /= 10;
+ }
+ // Ignore the leading zero if it was the last part of the integer.
+ if (n64 == 0)
+ {
+ if ((start[0] == '0')
+ && (start != (buffer[].ptr + buffer.sizeof -1)))
+ {
+ ++start;
+ }
+ break;
+ }
+ // Copy leading zeros if it wasn't the most significant part of the
+ // integer.
+ while (start != o)
+ {
+ *--start = '0';
+ }
+ }
+
+ // Get the length that we have copied.
+ uint l = cast(uint) ((buffer[].ptr + buffer.sizeof - 1) - start);
+ if (l == 0)
+ {
+ *--start = '0';
+ l = 1;
+ }
+ else if (number < 0) // Set the sign.
+ {
+ *--start = '-';
+ ++l;
+ }
+
+ return buffer[$ - l - 1 .. $ - 1];
+}
+
+// Converting an integer to string.
+@nogc nothrow pure @system unittest
+{
+ char[21] buf;
+
+ assert(integral2String(80, buf) == "80");
+ assert(integral2String(-80, buf) == "-80");
+ assert(integral2String(0, buf) == "0");
+ assert(integral2String(uint.max, buf) == "4294967295");
+ assert(integral2String(int.min, buf) == "-2147483648");
+}
+
+/*
+ * Double-double high-precision floating point number.
+ *
+ * The first element is a base value corresponding to the nearest approximation
+ * of the target $(D_PSYMBOL HP) value, and the second element is an offset
+ * value corresponding to the difference between the target value and the base.
+ * Thus, the $(D_PSYMBOL HP) value represented is the sum of the base and the
+ * offset.
+ */
+private struct HP
+{
+ private double base;
+ private double offset = 0.0;
+
+ private void normalize() @nogc nothrow pure @safe
+ {
+ const double target = this.base + this.offset;
+ this.offset -= target - this.base;
+ this.base = target;
+ }
+
+ private void multiply(ref const HP x, ref const HP y)
+ @nogc nothrow pure @safe
+ {
+ HP a, b;
+ long bt;
+
+ this.base = x.base * y.base;
+ copyFp(x.base, bt);
+ bt &= ulong.max << 27;
+ copyFp(bt, a.base);
+
+ a.offset = x.base - a.base;
+ copyFp(y.base, bt);
+ bt &= ulong.max << 27;
+ copyFp(bt, b.base);
+
+ b.offset = y.base - b.base;
+ this.offset = a.base * b.base - this.base
+ + a.base * b.offset
+ + a.offset * b.base
+ + a.offset * b.offset;
+ this.offset += x.base * y.offset + x.offset * y.base;
+ }
+}
+
private enum special = 0x7000;
private enum char period = '.';
@@ -48,145 +175,121 @@ private static const ulong[20] powersOf10 = [
10000000000000000000UL,
];
-private static const char[201] digitpair =
+private static const char[201] digitPairs =
"0001020304050607080910111213141516171819202122232425262728293031323334353"
~ "6373839404142434445464748495051525354555657585960616263646566676869707172"
~ "737475767778798081828384858687888990919293949596979899";
-private static const double[23] bottom = [
- 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008,
- 1e+009, 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017,
- 1e+018, 1e+019, 1e+020, 1e+021, 1e+022,
-];
-
-private static const double[22] negativeBottom = [
- 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009,
- 1e-010, 1e-011, 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018,
- 1e-019, 1e-020, 1e-021, 1e-022,
-];
-
-private static const double[13] top = [
- 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207,
- 1e+230, 1e+253, 1e+276, 1e+299,
-];
-
-private static const double[13] negativeTop = [
- 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207,
- 1e-230, 1e-253, 1e-276, 1e-299,
+private static const HP[23] bottom = [
+ HP(1e+000), HP(1e+001), HP(1e+002), HP(1e+003), HP(1e+004), HP(1e+005),
+ HP(1e+006), HP(1e+007), HP(1e+008), HP(1e+009), HP(1e+010), HP(1e+011),
+ HP(1e+012), HP(1e+013), HP(1e+014), HP(1e+015), HP(1e+016), HP(1e+017),
+ HP(1e+018), HP(1e+019), HP(1e+020), HP(1e+021), HP(1e+022),
];
-private static const double[13] topError = [
- 8388608, 6.8601809640529717e+028, -7.253143638152921e+052,
- -4.3377296974619174e+075, -1.5559416129466825e+098,
- -3.2841562489204913e+121, -3.7745893248228135e+144,
- -1.7356668416969134e+167, -3.8893577551088374e+190,
- -9.9566444326005119e+213, 6.3641293062232429e+236,
- -5.2069140800249813e+259, -5.2504760255204387e+282,
+private static const HP[22] negativeBottom = [
+ HP(1e-001, -5.551115123125783e-018),
+ HP(1e-002, -2.0816681711721684e-019),
+ HP(1e-003, -2.0816681711721686e-020),
+ HP(1e-004, -4.7921736023859299e-021),
+ HP(1e-005, -8.1803053914031305e-022),
+ HP(1e-006, 4.5251888174113741e-023),
+ HP(1e-007, 4.5251888174113739e-024),
+ HP(1e-008, -2.0922560830128471e-025),
+ HP(1e-009, -6.2281591457779853e-026),
+ HP(1e-010, -3.6432197315497743e-027),
+ HP(1e-011, 6.0503030718060191e-028),
+ HP(1e-012, 2.0113352370744385e-029),
+ HP(1e-013, -3.0373745563400371e-030),
+ HP(1e-014, 1.1806906454401013e-032),
+ HP(1e-015, -7.7705399876661076e-032),
+ HP(1e-016, 2.0902213275965398e-033),
+ HP(1e-017, -7.1542424054621921e-034),
+ HP(1e-018, -7.1542424054621926e-035),
+ HP(1e-019, 2.4754073164739869e-036),
+ HP(1e-020, 5.4846728545790429e-037),
+ HP(1e-021, 9.2462547772103625e-038),
+ HP(1e-022, -4.8596774326570872e-039),
];
-private static const double[22] negativeBottomError = [
- -5.551115123125783e-018, -2.0816681711721684e-019,
- -2.0816681711721686e-020, -4.7921736023859299e-021,
- -8.1803053914031305e-022, 4.5251888174113741e-023,
- 4.5251888174113739e-024, -2.0922560830128471e-025,
- -6.2281591457779853e-026, -3.6432197315497743e-027,
- 6.0503030718060191e-028, 2.0113352370744385e-029, -3.0373745563400371e-030,
- 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033,
- -7.1542424054621921e-034, -7.1542424054621926e-035,
- 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038,
- -4.8596774326570872e-039,
+private static const HP[13] top = [
+ HP(1e+023, 8388608),
+ HP(1e+046, 6.8601809640529717e+028),
+ HP(1e+069, -7.253143638152921e+052),
+ HP(1e+092, -4.3377296974619174e+075),
+ HP(1e+115, -1.5559416129466825e+098),
+ HP(1e+138, -3.2841562489204913e+121),
+ HP(1e+161, -3.7745893248228135e+144),
+ HP(1e+184, -1.7356668416969134e+167),
+ HP(1e+207, -3.8893577551088374e+190),
+ HP(1e+230, -9.9566444326005119e+213),
+ HP(1e+253, 6.3641293062232429e+236),
+ HP(1e+276, -5.2069140800249813e+259),
+ HP(1e+299, -5.2504760255204387e+282),
];
-private static const double[13] negativeTopError = [
- 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086,
- 1.1875228833981544e-109, -5.0644902316928607e-132,
- -6.7156837247865426e-155, -2.812077463003139e-178,
- -5.7778912386589953e-201, 7.4997100559334532e-224,
- -4.6439668915134491e-247, -6.3691100762962136e-270,
- -9.436808465446358e-293, // 8.0970921678014997e-317,
+private static const HP[13] negativeTop = [
+ HP(1e-023, 3.9565301985100693e-040L),
+ HP(1e-046, -2.299904345391321e-063L),
+ HP(1e-069, 3.6506201437945798e-086L),
+ HP(1e-092, 1.1875228833981544e-109L),
+ HP(1e-115, -5.0644902316928607e-132L),
+ HP(1e-138, -6.7156837247865426e-155L),
+ HP(1e-161, -2.812077463003139e-178L),
+ HP(1e-184, -5.7778912386589953e-201L),
+ HP(1e-207, 7.4997100559334532e-224L),
+ HP(1e-230, -4.6439668915134491e-247L),
+ HP(1e-253, -6.3691100762962136e-270L),
+ HP(1e-276, -9.436808465446358e-293L),
+ HP(1e-299, 8.0970921678014997e-317L),
];
private enum ulong tenTo19th = 1000000000000000000UL;
-private void ddmultlo(A, B, C, D, E, F)(ref A oh,
- ref B ol,
- ref C xh,
- ref D xl,
- ref E yh,
- ref F yl)
-{
- ol = ol + (xh * yl + xl * yh);
-}
-
-private void ddmultlos(A, B, C, D)(ref A oh, ref B ol, ref C xh, ref D yl)
-{
- ol = ol + (xh * yl);
-}
-
-private void ddrenorm(T, U)(ref T oh, ref U ol)
-{
- double s;
- s = oh + ol;
- ol = ol - (s - oh);
- oh = s;
-}
-
// Power can be -323 to +350.
-private void raise2Power10(double* ohi,
- double* olo,
- double d,
- int power) @nogc nothrow pure
+private HP raise2Power10(const HP value, int power)
+@nogc nothrow pure @safe
{
- double ph, pl;
+ HP result;
if ((power >= 0) && (power <= 22))
{
- ddmulthi(ph, pl, d, bottom[power]);
+ result.multiply(value, bottom[power]);
}
else
{
- int e, et, eb;
- double p2h, p2l;
+ HP p2;
+ int e = power;
- e = power;
if (power < 0)
{
e = -e;
}
- et = (e * 0x2c9) >> 14; /* %23 */
+ int et = (e * 0x2c9) >> 14; // % 23
if (et > 13)
{
et = 13;
}
- eb = e - (et * 23);
+ int eb = e - (et * 23);
- ph = d;
- pl = 0.0;
+ result = value;
if (power < 0)
{
- if (eb)
+ if (eb != 0)
{
--eb;
- ddmulthi(ph, pl, d, negativeBottom[eb]);
- ddmultlos(ph, pl, d, negativeBottomError[eb]);
+ result.multiply(value, negativeBottom[eb]);
}
if (et)
{
- ddrenorm(ph, pl);
+ result.normalize();
--et;
- ddmulthi(p2h, p2l, ph, negativeTop[et]);
- ddmultlo(p2h,
- p2l,
- ph,
- pl,
- negativeTop[et],
- negativeTopError[et]);
- ph = p2h;
- pl = p2l;
+ p2.multiply(result, negativeTop[et]);
+ result = p2;
}
}
else
{
- if (eb)
+ if (eb != 0)
{
e = eb;
if (eb > 22)
@@ -194,168 +297,141 @@ private void raise2Power10(double* ohi,
eb = 22;
}
e -= eb;
- ddmulthi(ph, pl, d, bottom[eb]);
+ result.multiply(value, bottom[eb]);
if (e)
{
- ddrenorm(ph, pl);
- ddmulthi(p2h, p2l, ph, bottom[e]);
- ddmultlos(p2h, p2l, bottom[e], pl);
- ph = p2h;
- pl = p2l;
+ result.normalize();
+ p2.multiply(result, bottom[e]);
+ result = p2;
}
}
- if (et)
+ if (et != 0)
{
- ddrenorm(ph, pl);
+ result.normalize();
--et;
- ddmulthi(p2h, p2l, ph, top[et]);
- ddmultlo(p2h, p2l, ph, pl, top[et], topError[et]);
- ph = p2h;
- pl = p2l;
+ p2.multiply(result, top[et]);
+ result = p2;
}
}
}
- ddrenorm(ph, pl);
- *ohi = ph;
- *olo = pl;
+ result.normalize();
+
+ return result;
}
/*
* Given a float value, returns the significant bits in bits, and the position
- * of the decimal point in decimalPos. +/-Inf and NaN are specified by special
- * values returned in the decimalPos parameter.
- * fracDigits is absolute normally, but if you want from first significant
- * digits (got %g), or in 0x80000000
+ * of the decimal point in $(D_PARAM exponent). +/-Inf and NaN are specified
+ * by special values returned in the $(D_PARAM exponent). Sing bit is set in
+ * $(D_PARAM sign).
*/
-private int real2String(ref const(char)* start,
- ref uint len,
- char* out_,
- out int decimalPos,
- double value,
- uint fracDigits) @nogc nothrow pure
+private const(char)[] real2String(double value,
+ ref char[512] buffer,
+ out int exponent,
+ out bool sign) @nogc nothrow pure @trusted
{
- long bits = 0;
- int e, tens;
-
- double d = value;
- copyFp(bits, d);
- auto exponent = cast(int) ((bits >> 52) & 2047);
- auto ng = cast(int) (bits >> 63);
- if (ng)
+ long bits;
+ copyFp(value, bits);
+
+ exponent = (bits >> 52) & 0x7ff;
+ sign = signBit(value);
+ if (sign)
{
- d = -d;
+ value = -value;
}
- if (exponent == 2047) // Is NaN or inf?
+ if (exponent == 2047) // Is NaN or Inf?
{
- start = (bits & (((cast(ulong) 1) << 52) - 1)) ? "NaN" : "Inf";
- decimalPos = special;
- len = 3;
- return ng;
+ exponent = special;
+ return (bits & ((1UL << 52) - 1)) != 0 ? "NaN" : "Inf";
}
if (exponent == 0) // Is zero or denormal?
{
- if ((bits << 1) == 0) // Do zero.
+ if ((bits << 1) == 0) // Zero.
{
- decimalPos = 1;
- start = out_;
- out_[0] = '0';
- len = 1;
- return ng;
+ exponent = 1;
+ buffer[0] = '0';
+ return buffer[0 .. 1];
}
+
// Find the right exponent for denormals.
+ for (long cursor = 1UL << 51; (bits & cursor) == 0; cursor >>= 1)
{
- long v = (cast(ulong) 1) << 51;
- while ((bits & v) == 0)
- {
- --exponent;
- v >>= 1;
- }
+ --exponent;
}
}
- // Find the decimal exponent as well as the decimal bits of the value.
+ // "617 / 2048" and "1233 / 4096" are estimations for the common logarithm
+ // (log10) of 2. Multiplied by a binary number it tells how big the number
+ // is in decimals, so it translates the binary exponent into decimal
+ // format. The estimation is tweaked to hit or undershoot by no more than
+ // 1 of log10 of all exponents 1..2046.
+ int tens = exponent - 1023; // Bias.
+ if (tens < 0)
{
- double ph, pl;
-
- // log10 estimate - very specifically tweaked to hit or undershoot by
- // no more than 1 of log10 of all exponents 1..2046.
- tens = exponent - 1023;
- if (tens < 0)
- {
- tens = (tens * 617) / 2048;
- }
- else
- {
- tens = ((tens * 1233) / 4096) + 1;
- }
+ tens = tens * 617 / 2048;
+ }
+ else
+ {
+ tens = tens * 1233 / 4096 + 1;
+ }
- // Move the significant bits into position and stick them into an int.
- raise2Power10(&ph, &pl, d, 18 - tens);
+ // Move the significant bits into position and stick them into an int.
+ HP p = raise2Power10(HP(value), 18 - tens);
- // Get full as much precision from double-double as possible.
- bits = cast(long) ph;
- double vh = cast(double) bits;
- double ahi = (ph - vh);
- double t = (ahi - ph);
- double alo = (ph - (ahi - t)) - (vh + t);
- bits += cast(long) (ahi + alo + pl);
+ // Get full as much precision from double-double as possible.
+ bits = cast(long) p.base;
+ double vh = cast(double) bits;
+ auto a = HP(p.base - vh);
+ double t = a.base - p.base;
+ a.offset = p.base - a.base + t - vh - t;
+ bits += cast(long) (a.base + a.offset + p.offset);
- // Check if we undershot.
- if ((cast(ulong) bits) >= tenTo19th)
- {
- ++tens;
- }
+ // Check if we undershot (bits >= 10 ^ 19).
+ if ((cast(ulong) bits) >= 1000000000000000000UL)
+ {
+ ++tens;
}
// Now do the rounding in integer land.
- if (fracDigits & 0x80000000)
- {
- fracDigits = (fracDigits & 0x7ffffff) + 1;
- }
- else
+ enum uint fracDigits = 6;
+
+ uint dg = 1;
+ if ((cast(ulong) bits) >= powersOf10[9])
{
- fracDigits = tens + fracDigits;
+ dg = 10;
}
- if ((fracDigits < 24))
+ uint length;
+ while ((cast(ulong) bits) >= powersOf10[dg])
{
- uint dg = 1;
- if (cast(ulong) bits >= powersOf10[9])
+ ++dg;
+ if (dg == 20)
{
- dg = 10;
+ goto NoRound;
}
- while (cast(ulong) bits >= powersOf10[dg])
+ }
+ if (fracDigits < dg)
+ {
+ // Add 0.5 at the right position and round.
+ length = dg - fracDigits;
+ if (length >= 24)
{
- ++dg;
- if (dg == 20)
- {
- goto noround;
- }
+ goto NoRound;
}
- if (fracDigits < dg)
+ ulong r = powersOf10[length];
+ bits = bits + (r / 2);
+ if ((cast(ulong) bits) >= powersOf10[dg])
{
- // Add 0.5 at the right position and round.
- e = dg - fracDigits;
- if (cast(uint) e >= 24)
- {
- goto noround;
- }
- ulong r = powersOf10[e];
- bits = bits + (r / 2);
- if (cast(ulong) bits >= powersOf10[dg])
- {
- ++tens;
- }
- bits /= r;
+ ++tens;
}
- noround:
+ bits /= r;
}
+NoRound:
// Kill long trailing runs of zeros.
if (bits)
{
- uint n;
for (;;)
{
if (bits <= 0xffffffff)
@@ -364,26 +440,26 @@ private int real2String(ref const(char)* start,
}
if (bits % 1000)
{
- goto donez;
+ goto Zeroed;
}
bits /= 1000;
}
- n = cast(uint) bits;
+ auto n = cast(uint) bits;
while ((n % 1000) == 0)
{
n /= 1000;
}
bits = n;
- donez:
}
+Zeroed:
// Convert to string.
- out_ += 64;
- e = 0;
- for (;;)
+ auto result = buffer.ptr + 64;
+ length = 0;
+ while (true)
{
uint n;
- char *o = out_ - 8;
+ char* o = result - 8;
// Do the conversion in chunks of U32s (avoid most 64-bit divides,
// worth it, constant denomiators be damned).
if (bits >= 100000000)
@@ -398,35 +474,31 @@ private int real2String(ref const(char)* start,
}
while (n)
{
- out_ -= 2;
- *cast(ushort*) out_ = *cast(ushort*) &digitpair[(n % 100) * 2];
+ result -= 2;
+ *cast(ushort*) result = *cast(ushort*) &digitPairs[(n % 100) * 2];
n /= 100;
- e += 2;
+ length += 2;
}
if (bits == 0)
{
- if ((e) && (out_[0] == '0'))
+ if ((length != 0) && (result[0] == '0'))
{
- ++out_;
- --e;
+ ++result;
+ --length;
}
break;
}
- while (out_ != o)
+ for (; result !is o; ++length, --result)
{
- *--out_ = '0';
- ++e;
+ *result = '0';
}
}
-
- decimalPos = tens;
- start = out_;
- len = e;
- return ng;
+ exponent = tens;
+ return result[0 .. length];
}
private void leadSign(bool negative, ref char[8] sign)
-@nogc nothrow pure
+@nogc nothrow pure @safe
{
sign[0] = 0;
if (negative)
@@ -436,13 +508,13 @@ private void leadSign(bool negative, ref char[8] sign)
}
}
-// Copies d to bits w/ strict aliasing (this compiles to nothing on /Ox).
-private void copyFp(T, U)(ref T dest, ref U src)
+/*
+ * Copies double into long and back bitwise.
+ */
+private void copyFp(T, U)(ref const U src, ref T dest) @trusted
+if (T.sizeof == U.sizeof)
{
- for (int count = 0; count < 8; ++count)
- {
- (cast(char*) &dest)[count] = (cast(char*) &src)[count];
- }
+ copy((&src)[0 .. 1], (&dest)[0 .. 1]);
}
private void ddmulthi(ref double oh,
@@ -453,13 +525,13 @@ private void ddmulthi(ref double oh,
double ahi, bhi;
long bt;
oh = xh * yh;
- copyFp(bt, xh);
+ copyFp(xh, bt);
bt &= ((~cast(ulong) 0) << 27);
- copyFp(ahi, bt);
+ copyFp(bt, ahi);
double alo = xh - ahi;
- copyFp(bt, yh);
+ copyFp(yh, bt);
bt &= ((~cast(ulong) 0) << 27);
- copyFp(bhi, bt);
+ copyFp(bt, bhi);
double blo = yh - bhi;
ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo;
}
@@ -467,25 +539,6 @@ private void ddmulthi(ref double oh,
package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
{
String result;
- char* bf = buf.ptr;
-
- // Ok, we have a percent, read the modifiers first.
- int precision = -1;
- int tz = 0;
- bool negative;
-
- // Handle each replacement.
- char[512] num; // Big enough for e308 (with commas) or e-307.
- char[8] lead;
- char[8] tail;
- char *s;
- uint l, n;
- ulong n64;
-
- double fv;
-
- int decimalPos;
- const(char)* sn;
static if (isSomeString!(Args[0])) // String
{
@@ -504,28 +557,23 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
}
else static if (isFloatingPoint!(Args[0])) // Float
{
- fv = args[0];
- if (precision == -1)
- {
- precision = 6;
- }
- else if (precision == 0)
- {
- precision = 1; // Default is 6.
- }
+ char[512] num; // Big enough for e308 (with commas) or e-307.
+ char[8] lead;
+ char[8] tail = 0;
+ char *s;
+ int precision = 6;
+ int tz;
+ bool negative;
+ char* bf = buf.ptr;
+ int decimalPos;
+
// Read the double into a string.
- if (real2String(sn,
- l,
- num.ptr,
- decimalPos,
- fv,
- (precision - 1) | 0x80000000))
- {
- negative = true;
- }
+ auto fv = real2String(args[0], num, decimalPos, negative);
+ const(char)* sn = fv.ptr;
+ auto l = cast(uint) fv.length;
// Clamp the precision and delete extra zeros after clamp.
- n = precision;
+ uint n = precision;
if (l > cast(uint) precision)
{
l = precision;
@@ -570,7 +618,6 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
goto dofloatfromg;
doexpfromg:
- tail[0] = 0;
leadSign(negative, lead);
if (decimalPos == special)
{
@@ -628,7 +675,6 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
goto flt_lead;
dofloatfromg:
- tail[0] = 0;
leadSign(negative, lead);
if (decimalPos == special)
{
@@ -765,140 +811,67 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
// Get the length that we copied.
l = cast(uint) (s - (num.ptr + 64));
s = num.ptr + 64;
- }
- else static if (isPointer!(Args[0])) // Pointer
- {
- // Get the number.
- n64 = cast(size_t) args[0];
- size_t position = num.length;
- do // Write at least "0" if the pointer is null.
+ scopy:
+ // Get fw=leading/trailing space, precision=leading zeros.
+ if (precision < cast(int) l)
{
- num[--position] = lowerHexDigits[cast(size_t) (n64 & 15)];
- n64 >>= 4;
+ precision = l;
}
- while (n64 != 0);
+ n = precision + lead[0] + tail[0] + tz;
+ precision -= l;
- result.insertBack("0x");
- result.insertBack(num[position .. $]);
- }
- else static if (isIntegral!(Args[0])) // Integer
- {
- // Get the integer and abs it.
- static if (Args[0].sizeof == 8)
+ // Copy the spaces and/or zeros.
+ if (precision)
{
- long k64 = args[0];
- n64 = cast(ulong) k64;
- static if (isSigned!(Args[0]))
+ int i;
+
+ // copy leader
+ sn = lead.ptr + 1;
+ while (lead[0])
{
- if (k64 < 0)
+ i = lead[0];
+ lead[0] -= cast(char) i;
+ while (i)
{
- n64 = cast(ulong) -k64;
- negative = true;
+ *bf++ = *sn++;
+ --i;
}
}
- }
- else
- {
- int k = args[0];
- n64 = cast(uint) k;
- static if (isSigned!(Args[0]))
+
+ // Copy leading zeros.
+ while (precision > 0)
{
- if (k < 0)
+ i = precision;
+ precision -= i;
+ while (i)
{
- n64 = cast(uint) -k;
- negative = true;
+ if (((cast(size_t) bf) & 3) == 0)
+ {
+ break;
+ }
+ *bf++ = '0';
+ --i;
}
- }
- }
-
- // Convert to string.
- s = num.ptr + num.length;
- l = 0;
-
- for (;;)
- {
- // Do in 32-bit chunks (avoid lots of 64-bit divides even
- // with constant denominators).
- char *o = s - 8;
- if (n64 >= 100000000)
- {
- n = cast(uint) (n64 % 100000000);
- n64 /= 100000000;
- }
- else
- {
- n = cast(uint) n64;
- n64 = 0;
- }
- while (n)
- {
- s -= 2;
- *cast(ushort*) s = *cast(ushort*) &digitpair[(n % 100) * 2];
- n /= 100;
- }
- while (n)
- {
- *--s = cast(char) (n % 10) + '0';
- n /= 10;
- }
- if (n64 == 0)
- {
- if ((s[0] == '0') && (s != (num.ptr + num.length)))
+ while (i >= 4)
{
- ++s;
+ *cast(uint*) bf = 0x30303030;
+ bf += 4;
+ i -= 4;
+ }
+ while (i)
+ {
+ *bf++ = '0';
+ --i;
}
- break;
- }
- while (s != o)
- {
- *--s = '0';
}
}
- tail[0] = 0;
- leadSign(negative, lead);
-
- // Get the length that we copied.
- l = cast(uint) ((num.ptr + num.length) - s);
- if (l == 0)
- {
- *--s = '0';
- l = 1;
- }
- if (precision < 0)
- {
- precision = 0;
- }
- }
- else
- {
- static assert(false);
- }
-
- if (result.length > 0)
- {
- return result;
- }
-scopy:
- // Get fw=leading/trailing space, precision=leading zeros.
- if (precision < cast(int) l)
- {
- precision = l;
- }
- n = precision + lead[0] + tail[0] + tz;
- precision -= l;
-
- // Copy the spaces and/or zeros.
- if (precision)
- {
- int i;
-
- // copy leader
+ // copy leader if there is still one
sn = lead.ptr + 1;
while (lead[0])
{
- i = lead[0];
+ int i = lead[0];
lead[0] -= cast(char) i;
while (i)
{
@@ -907,11 +880,25 @@ scopy:
}
}
- // Copy leading zeros.
- while (precision > 0)
+ // Copy the string.
+ n = l;
+ while (n)
{
- i = precision;
- precision -= i;
+ int i = n;
+ n -= i;
+
+ while (i)
+ {
+ *bf++ = *s++;
+ --i;
+ }
+ }
+
+ // Copy trailing zeros.
+ while (tz)
+ {
+ int i = tz;
+ tz -= i;
while (i)
{
if (((cast(size_t) bf) & 3) == 0)
@@ -933,77 +920,49 @@ scopy:
--i;
}
}
- }
- // copy leader if there is still one
- sn = lead.ptr + 1;
- while (lead[0])
- {
- int i = lead[0];
- lead[0] -= cast(char) i;
- while (i)
+ // copy tail if there is one
+ sn = tail.ptr + 1;
+ while (tail[0])
{
- *bf++ = *sn++;
- --i;
+ int i = tail[0];
+ tail[0] -= cast(char) i;
+ while (i)
+ {
+ *bf++ = *sn++;
+ --i;
+ }
}
- }
- // Copy the string.
- n = l;
- while (n)
+ *bf = 0;
+ result = String(buf[0 .. cast(int) (bf - buf.ptr)]);
+ }
+ else static if (isPointer!(Args[0])) // Pointer
{
- int i = n;
- n -= i;
+ char[size_t.sizeof * 2] buffer;
+ size_t position = buffer.length;
+ auto address = cast(size_t) args[0];
- while (i)
+ do // Write at least "0" if the pointer is null.
{
- *bf++ = *s++;
- --i;
+ buffer[--position] = lowerHexDigits[cast(size_t) (address & 15)];
+ address >>= 4;
}
- }
+ while (address != 0);
- // Copy trailing zeros.
- while (tz)
+ result.insertBack("0x");
+ result.insertBack(buffer[position .. $]);
+ }
+ else static if (isIntegral!(Args[0])) // Integer
{
- int i = tz;
- tz -= i;
- while (i)
- {
- if (((cast(size_t) bf) & 3) == 0)
- {
- break;
- }
- *bf++ = '0';
- --i;
- }
- while (i >= 4)
- {
- *cast(uint*) bf = 0x30303030;
- bf += 4;
- i -= 4;
- }
- while (i)
- {
- *bf++ = '0';
- --i;
- }
+ char[21] buffer;
+ result.insertBack(integral2String(args[0], buffer));
}
-
- // copy tail if there is one
- sn = tail.ptr + 1;
- while (tail[0])
+ else
{
- int i = tail[0];
- tail[0] -= cast(char) i;
- while (i)
- {
- *bf++ = *sn++;
- --i;
- }
+ static assert(false);
}
- *bf = 0;
- result = String(buf[0 .. cast(int) (bf - buf.ptr)]);
return result;
}