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 {...@@ -32,13 +32,13 @@ pub fn errol3(value: f64, buffer: []u8) -> FloatDecimal {
32fn errol3u(val: f64, buffer: []u8) -> FloatDecimal {32fn errol3u(val: f64, buffer: []u8) -> FloatDecimal {
33 // check if in integer or fixed range33 // 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) {
36 return errolInt(val, buffer);36 return errolInt(val, buffer);
37 } else if (val >= 16.0 and val < 9.007199254740992e15) {37 } else if (val >= 16.0 and val < 9.007199254740992e15) {
38 return errolFixed(val, buffer);38 return errolFixed(val, buffer);
39 }39 }
4040
41 41
42 // normalize the midpoint42 // normalize the midpoint
4343
44 const e = math.frexp(val).exponent;44 const e = math.frexp(val).exponent;
...@@ -138,7 +138,7 @@ fn tableLowerBound(k: u64) -> usize {...@@ -138,7 +138,7 @@ fn tableLowerBound(k: u64) -> usize {
138138
139 while (j < enum3.len) {139 while (j < enum3.len) {
140 if (enum3[j] < k) {140 if (enum3[j] < k) {
141 j = 2 * k + 2;141 j = 2 * j + 2;
142 } else {142 } else {
143 i = j;143 i = j;
144 j = 2 * j + 1;144 j = 2 * j + 1;
...@@ -217,7 +217,7 @@ fn hpMul10(hp: &HP) {...@@ -217,7 +217,7 @@ fn hpMul10(hp: &HP) {
217217
218 hp.val *= 10.0;218 hp.val *= 10.0;
219 hp.off *= 10.0;219 hp.off *= 10.0;
220 220
221 var off = hp.val;221 var off = hp.val;
222 off -= val * 8.0;222 off -= val * 8.0;
223 off -= val * 2.0;223 off -= val * 2.0;
...@@ -235,13 +235,13 @@ fn hpMul10(hp: &HP) {...@@ -235,13 +235,13 @@ fn hpMul10(hp: &HP) {
235fn errolInt(val: f64, buffer: []u8) -> FloatDecimal {235fn errolInt(val: f64, buffer: []u8) -> FloatDecimal {
236 const pow19 = u128(1e19);236 const pow19 = u128(1e19);
237237
238 assert((val >= 9.007199254740992e15) and val < (3.40282366920938e38));238 assert((val > 9.007199254740992e15) and val < (3.40282366920938e38));
239239
240 var mid = u128(val);240 var mid = u128(val);
241 var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);241 var low: u128 = mid - fpeint((fpnext(val) - val) / 2.0);
242 var high: u128 = mid + fpeint((val - fpprev(val)) / 2.0);242 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) {
245 high -= 1;245 high -= 1;
246 } else {246 } else {
247 low -= 1;247 low -= 1;
...@@ -347,11 +347,11 @@ fn errolFixed(val: f64, buffer: []u8) -> FloatDecimal {...@@ -347,11 +347,11 @@ fn errolFixed(val: f64, buffer: []u8) -> FloatDecimal {
347}347}
348348
349fn fpnext(val: f64) -> f64 {349fn fpnext(val: f64) -> f64 {
350 return @bitCast(f64, @bitCast(u64, val) + 1);350 return @bitCast(f64, @bitCast(u64, val) +% 1);
351}351}
352352
353fn fpprev(val: f64) -> f64 {353fn fpprev(val: f64) -> f64 {
354 return @bitCast(f64, @bitCast(u64, val) - 1);354 return @bitCast(f64, @bitCast(u64, val) -% 1);
355}355}
356356
357pub const c_digits_lut = []u8 {357pub const c_digits_lut = []u8 {
...@@ -510,10 +510,6 @@ fn u64toa(value_param: u64, buffer: []u8) -> usize {...@@ -510,10 +510,6 @@ fn u64toa(value_param: u64, buffer: []u8) -> usize {
510 buf_index += 1;510 buf_index += 1;
511 buffer[buf_index] = c_digits_lut[d8];511 buffer[buf_index] = c_digits_lut[d8];
512 buf_index += 1;512 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;
517 buffer[buf_index] = c_digits_lut[d8 + 1];513 buffer[buf_index] = c_digits_lut[d8 + 1];
518 buf_index += 1;514 buf_index += 1;
519 } else {515 } else {
...@@ -613,7 +609,7 @@ fn fpeint(from: f64) -> u128 {...@@ -613,7 +609,7 @@ fn fpeint(from: f64) -> u128 {
613 const bits = @bitCast(u64, from);609 const bits = @bitCast(u64, from);
614 assert((bits & ((1 << 52) - 1)) == 0);610 assert((bits & ((1 << 52) - 1)) == 0);
615611
616 return u64(1) << u6(((bits >> 52) - 1023));612 return u128(1) << @truncate(u7, (bits >> 52) -% 1023);
617}613}
618614
619615
std/fmt/index.zig+60-11
...@@ -244,30 +244,47 @@ pub fn formatBuf(buf: []const u8, width: usize,...@@ -244,30 +244,47 @@ pub fn formatBuf(buf: []const u8, width: usize,
244}244}
245245
246pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {246pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {
247 var buffer: [20]u8 = undefined;247 var x = f64(value);
248 const float_decimal = errol3(f64(value), buffer[0..]);248
249 if (float_decimal.exp != 0) {249 // Errol doesn't handle these special cases.
250 if (!output(context, float_decimal.digits[0..1]))250 if (math.isNan(x)) {
251 return false;251 return output(context, "NaN");
252 } else {252 }
253 if (!output(context, "0"))253 if (math.signbit(x)) {
254 if (!output(context, "-"))
254 return false;255 return false;
256 x = -x;
255 }257 }
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;
256 if (!output(context, "."))269 if (!output(context, "."))
257 return false;270 return false;
258 if (float_decimal.digits.len > 1) {271 if (float_decimal.digits.len > 1) {
259 const start = if (float_decimal.exp == 0) usize(0) else usize(1);272 const num_digits = if (@typeOf(value) == f32) {
260 if (!output(context, float_decimal.digits[start .. math.min(usize(7), float_decimal.digits.len)]))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]))
261 return false;278 return false;
262 } else {279 } else {
263 if (!output(context, "0"))280 if (!output(context, "0"))
264 return false;281 return false;
265 }282 }
266283
267 if (float_decimal.exp != 1 and float_decimal.exp != 0) {284 if (float_decimal.exp != 1) {
268 if (!output(context, "e"))285 if (!output(context, "e"))
269 return false;286 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))
271 return false;288 return false;
272 }289 }
273 return true;290 return true;
...@@ -514,6 +531,38 @@ test "fmt.format" {...@@ -514,6 +531,38 @@ test "fmt.format" {
514 const result = bufPrint(buf1[0..], "u3: {}\n", value);531 const result = bufPrint(buf1[0..], "u3: {}\n", value);
515 assert(mem.eql(u8, result, "u3: 5\n"));532 assert(mem.eql(u8, result, "u3: 5\n"));
516 }533 }
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 }
517}566}
518567
519pub fn trim(buf: []const u8) -> []const u8 {568pub fn trim(buf: []const u8) -> []const u8 {