diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-12-30 23:21:02 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-12-30 23:21:02 -0500 |
| commit | aafb83228890c07eb3f0a203010d044aaceb8f85 (patch) | |
| tree | 6c447ee466d26efb5ea8b61b3dae7b014f9b3f10 | |
| parent | 4e3d7fc4bc06379c4ede2b687efa57666205bcb1 (diff) | |
| parent | d15b02a6b603b0064dff781066f5089797f77b6f (diff) | |
| download | zig-aafb83228890c07eb3f0a203010d044aaceb8f85.tar.gz zig-aafb83228890c07eb3f0a203010d044aaceb8f85.zip | |
Merge pull request #668 from sparrisable/master
Added format for floating point numbers. {.x} where x is the number of decimals.
| -rw-r--r-- | std/fmt/index.zig | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 550fa1ce1f..7f3f4bf27a 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -14,6 +14,8 @@ const State = enum { // TODO put inside format function and make sure the name a CloseBrace, Integer, IntegerWidth, + Float, + FloatWidth, Character, Buf, BufWidth, @@ -85,6 +87,8 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void, }, 's' => { state = State.Buf; + },'.' => { + state = State.Float; }, else => @compileError("Unknown format character: " ++ []u8{c}), }, @@ -129,6 +133,30 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void, '0' ... '9' => {}, else => @compileError("Unexpected character in format string: " ++ []u8{c}), }, + State.Float => switch (c) { + '}' => { + %return formatFloatDecimal(args[next_arg], 0, context, output); + next_arg += 1; + state = State.Start; + start_index = i + 1; + }, + '0' ... '9' => { + width_start = i; + state = State.FloatWidth; + }, + else => @compileError("Unexpected character in format string: " ++ []u8{c}), + }, + State.FloatWidth => switch (c) { + '}' => { + width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10); + %return formatFloatDecimal(args[next_arg], width, context, output); + next_arg += 1; + state = State.Start; + start_index = i + 1; + }, + '0' ... '9' => {}, + else => @compileError("Unexpected character in format string: " ++ []u8{c}), + }, State.BufWidth => switch (c) { '}' => { width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10); @@ -267,6 +295,47 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons } } +pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void { + var x = f64(value); + + // Errol doesn't handle these special cases. + if (math.isNan(x)) { + return output(context, "NaN"); + } + if (math.signbit(x)) { + %return output(context, "-"); + x = -x; + } + if (math.isPositiveInf(x)) { + return output(context, "Infinity"); + } + if (x == 0.0) { + return output(context, "0.0"); + } + + var buffer: [32]u8 = undefined; + const float_decimal = errol3(x, buffer[0..]); + + const num_left_digits = if (float_decimal.exp > 0) usize(float_decimal.exp) else 1; + + %return output(context, float_decimal.digits[0 .. num_left_digits]); + %return output(context, "."); + if (float_decimal.digits.len > 1) { + const num_valid_digtis = if (@typeOf(value) == f32) math.min(usize(7), float_decimal.digits.len) + else + float_decimal.digits.len; + + const num_right_digits = if (precision != 0) + math.min(precision, (num_valid_digtis-num_left_digits)) + else + num_valid_digtis - num_left_digits; + %return output(context, float_decimal.digits[num_left_digits .. (num_left_digits + num_right_digits)]); + } else { + %return output(context, "0"); + } +} + + pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void { @@ -540,6 +609,39 @@ test "fmt.format" { const result = %%bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); assert(mem.eql(u8, result, "f64: -Infinity\n")); } + { + var buf1: [32]u8 = undefined; + const value: f32 = 1.1234; + const result = %%bufPrint(buf1[0..], "f32: {.1}\n", value); + assert(mem.eql(u8, result, "f32: 1.1\n")); + } + { + var buf1: [32]u8 = undefined; + const value: f32 = 1234.567; + const result = %%bufPrint(buf1[0..], "f32: {.2}\n", value); + assert(mem.eql(u8, result, "f32: 1234.56\n")); + } + { + var buf1: [32]u8 = undefined; + const value: f32 = -11.1234; + const result = %%bufPrint(buf1[0..], "f32: {.4}\n", value); + // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64). + // -11.12339... is truncated to -11.1233 + assert(mem.eql(u8, result, "f32: -11.1233\n")); + } + { + var buf1: [32]u8 = undefined; + const value: f32 = 91.12345; + const result = %%bufPrint(buf1[0..], "f32: {.}\n", value); + assert(mem.eql(u8, result, "f32: 91.12345\n")); + } + { + var buf1: [32]u8 = undefined; + const value: f64 = 91.12345678901235; + const result = %%bufPrint(buf1[0..], "f64: {.10}\n", value); + assert(mem.eql(u8, result, "f64: 91.1234567890\n")); + } + } } |
