| ... | ... | @@ -244,30 +244,47 @@ pub fn formatBuf(buf: []const u8, width: usize, |
| 244 | 244 | } |
| 245 | 245 | |
| 246 | 246 | pub 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, "-")) |
| 254 | 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 | 269 | if (!output(context, ".")) |
| 257 | 270 | return false; |
| 258 | 271 | 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])) |
| 261 | 278 | return false; |
| 262 | 279 | } else { |
| 263 | 280 | if (!output(context, "0")) |
| 264 | 281 | return false; |
| 265 | 282 | } |
| 266 | 283 | |
| 267 | | if (float_decimal.exp != 1 and float_decimal.exp != 0) { |
| 284 | if (float_decimal.exp != 1) { |
| 268 | 285 | if (!output(context, "e")) |
| 269 | 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 | 288 | return false; |
| 272 | 289 | } |
| 273 | 290 | return true; |
| ... | ... | @@ -514,6 +531,38 @@ test "fmt.format" { |
| 514 | 531 | const result = bufPrint(buf1[0..], "u3: {}\n", value); |
| 515 | 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 | } |
| 518 | 567 | |
| 519 | 568 | pub fn trim(buf: []const u8) -> []const u8 { |