authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-24 21:58:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-24 21:58:09-04:00
log6764a4522391d82c40fc54bae448b32366e3e6d8
treefcb9d80ac056a2e81efb6e31915ee94866dea1b1
parent1828f8eb8e1514578ed2da8d58536903f94b7ed0
parent73fe5f63c6acc1b2e6fec51da545178ffd12180e

Merge branch 'better-float-printing'


2 files changed, 69 insertions(+), 24 deletions(-)

std/fmt/errol/index.zig+9-13
......@@ -32,13 +32,13 @@ pub fn errol3(value: f64, buffer: []u8) -> FloatDecimal {
3232fn errol3u(val: f64, buffer: []u8) -> FloatDecimal {
3333 // check if in integer or fixed range
3434
35 if (val >= 9.007199254740992e15 and val < 3.40282366920938e+38) {
35 if (val > 9.007199254740992e15 and val < 3.40282366920938e+38) {
3636 return errolInt(val, buffer);
3737 } else if (val >= 16.0 and val < 9.007199254740992e15) {
3838 return errolFixed(val, buffer);
3939 }
4040
41
41
4242 // normalize the midpoint
4343
4444 const e = math.frexp(val).exponent;
......@@ -138,7 +138,7 @@ fn tableLowerBound(k: u64) -> usize {
138138
139139 while (j < enum3.len) {
140140 if (enum3[j] < k) {
141 j = 2 * k + 2;
141 j = 2 * j + 2;
142142 } else {
143143 i = j;
144144 j = 2 * j + 1;
......@@ -217,7 +217,7 @@ fn hpMul10(hp: &HP) {
217217
218218 hp.val *= 10.0;
219219 hp.off *= 10.0;
220
220
221221 var off = hp.val;
222222 off -= val * 8.0;
223223 off -= val * 2.0;
......@@ -235,13 +235,13 @@ fn hpMul10(hp: &HP) {
235235fn errolInt(val: f64, buffer: []u8) -> FloatDecimal {
236236 const pow19 = u128(1e19);
237237
238 assert((val >= 9.007199254740992e15) and val < (3.40282366920938e38));
238 assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
239239
240240 var mid = u128(val);
241241 var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
242242 var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);
243243
244 if (@bitCast(u64, val) & 0x1 != 0) {
244 if (@bitCast(u64, val) & 0x1 != 0) {
245245 high -= 1;
246246 } else {
247247 low -= 1;
......@@ -347,11 +347,11 @@ fn errolFixed(val: f64, buffer: []u8) -> FloatDecimal {
347347}
348348
349349fn fpnext(val: f64) -> f64 {
350 return @bitCast(f64, @bitCast(u64, val) + 1);
350 return @bitCast(f64, @bitCast(u64, val) +% 1);
351351}
352352
353353fn fpprev(val: f64) -> f64 {
354 return @bitCast(f64, @bitCast(u64, val) - 1);
354 return @bitCast(f64, @bitCast(u64, val) -% 1);
355355}
356356
357357pub const c_digits_lut = []u8 {
......@@ -510,10 +510,6 @@ fn u64toa(value_param: u64, buffer: []u8) -> usize {
510510 buf_index += 1;
511511 buffer[buf_index] = c_digits_lut[d8];
512512 buf_index += 1;
513 buffer[buf_index] = c_digits_lut[d8];
514 buf_index += 1;
515 buffer[buf_index] = c_digits_lut[d8];
516 buf_index += 1;
517513 buffer[buf_index] = c_digits_lut[d8 + 1];
518514 buf_index += 1;
519515 } else {
......@@ -613,7 +609,7 @@ fn fpeint(from: f64) -> u128 {
613609 const bits = @bitCast(u64, from);
614610 assert((bits & ((1 << 52) - 1)) == 0);
615611
616 return u64(1) << u6(((bits >> 52) - 1023));
612 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
617613}
618614
619615
std/fmt/index.zig+60-11
......@@ -244,30 +244,47 @@ pub fn formatBuf(buf: []const u8, width: usize,
244244}
245245
246246pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {
247 var buffer: [20]u8 = undefined;
248 const float_decimal = errol3(f64(value), buffer[0..]);
249 if (float_decimal.exp != 0) {
250 if (!output(context, float_decimal.digits[0..1]))
251 return false;
252 } else {
253 if (!output(context, "0"))
247 var x = f64(value);
248
249 // Errol doesn't handle these special cases.
250 if (math.isNan(x)) {
251 return output(context, "NaN");
252 }
253 if (math.signbit(x)) {
254 if (!output(context, "-"))
254255 return false;
256 x = -x;
255257 }
258 if (math.isPositiveInf(x)) {
259 return output(context, "Infinity");
260 }
261 if (x == 0.0) {
262 return output(context, "0.0");
263 }
264
265 var buffer: [32]u8 = undefined;
266 const float_decimal = errol3(x, buffer[0..]);
267 if (!output(context, float_decimal.digits[0..1]))
268 return false;
256269 if (!output(context, "."))
257270 return false;
258271 if (float_decimal.digits.len > 1) {
259 const start = if (float_decimal.exp == 0) usize(0) else usize(1);
260 if (!output(context, float_decimal.digits[start .. math.min(usize(7), float_decimal.digits.len)]))
272 const num_digits = if (@typeOf(value) == f32) {
273 math.min(usize(9), float_decimal.digits.len)
274 } else {
275 float_decimal.digits.len
276 };
277 if (!output(context, float_decimal.digits[1 .. num_digits]))
261278 return false;
262279 } else {
263280 if (!output(context, "0"))
264281 return false;
265282 }
266283
267 if (float_decimal.exp != 1 and float_decimal.exp != 0) {
284 if (float_decimal.exp != 1) {
268285 if (!output(context, "e"))
269286 return false;
270 if (!formatInt(float_decimal.exp, 10, false, 0, context, output))
287 if (!formatInt(float_decimal.exp - 1, 10, false, 0, context, output))
271288 return false;
272289 }
273290 return true;
......@@ -514,6 +531,38 @@ test "fmt.format" {
514531 const result = bufPrint(buf1[0..], "u3: {}\n", value);
515532 assert(mem.eql(u8, result, "u3: 5\n"));
516533 }
534
535 // TODO get these tests passing in release modes
536 // https://github.com/zig-lang/zig/issues/564
537 if (builtin.mode == builtin.Mode.Debug) {
538 {
539 var buf1: [32]u8 = undefined;
540 const value: f32 = 12.34;
541 const result = bufPrint(buf1[0..], "f32: {}\n", value);
542 assert(mem.eql(u8, result, "f32: 1.23400001e1\n"));
543 }
544 {
545 var buf1: [32]u8 = undefined;
546 const value: f64 = -12.34e10;
547 const result = bufPrint(buf1[0..], "f64: {}\n", value);
548 assert(mem.eql(u8, result, "f64: -1.234e11\n"));
549 }
550 {
551 var buf1: [32]u8 = undefined;
552 const result = bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
553 assert(mem.eql(u8, result, "f64: NaN\n"));
554 }
555 {
556 var buf1: [32]u8 = undefined;
557 const result = bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
558 assert(mem.eql(u8, result, "f64: Infinity\n"));
559 }
560 {
561 var buf1: [32]u8 = undefined;
562 const result = bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
563 assert(mem.eql(u8, result, "f64: -Infinity\n"));
564 }
565 }
517566}
518567
519568pub fn trim(buf: []const u8) -> []const u8 {