authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-30 23:21:02-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2017-12-30 23:21:02-05:00
logaafb83228890c07eb3f0a203010d044aaceb8f85
tree6c447ee466d26efb5ea8b61b3dae7b014f9b3f10
parent4e3d7fc4bc06379c4ede2b687efa57666205bcb1
parentd15b02a6b603b0064dff781066f5089797f77b6f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #668 from sparrisable/master

Added format for floating point numbers. {.x} where x is the number of decimals.

1 files changed, 102 insertions(+), 0 deletions(-)

std/fmt/index.zig+102
......@@ -14,6 +14,8 @@ const State = enum { // TODO put inside format function and make sure the name a
1414 CloseBrace,
1515 Integer,
1616 IntegerWidth,
17 Float,
18 FloatWidth,
1719 Character,
1820 Buf,
1921 BufWidth,
......@@ -85,6 +87,8 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void,
8587 },
8688 's' => {
8789 state = State.Buf;
90 },'.' => {
91 state = State.Float;
8892 },
8993 else => @compileError("Unknown format character: " ++ []u8{c}),
9094 },
......@@ -129,6 +133,30 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void,
129133 '0' ... '9' => {},
130134 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
131135 },
136 State.Float => switch (c) {
137 '}' => {
138 %return formatFloatDecimal(args[next_arg], 0, context, output);
139 next_arg += 1;
140 state = State.Start;
141 start_index = i + 1;
142 },
143 '0' ... '9' => {
144 width_start = i;
145 state = State.FloatWidth;
146 },
147 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
148 },
149 State.FloatWidth => switch (c) {
150 '}' => {
151 width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10);
152 %return formatFloatDecimal(args[next_arg], width, context, output);
153 next_arg += 1;
154 state = State.Start;
155 start_index = i + 1;
156 },
157 '0' ... '9' => {},
158 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
159 },
132160 State.BufWidth => switch (c) {
133161 '}' => {
134162 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
267295 }
268296}
269297
298pub fn formatFloatDecimal(value: var, precision: usize, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void {
299 var x = f64(value);
300
301 // Errol doesn't handle these special cases.
302 if (math.isNan(x)) {
303 return output(context, "NaN");
304 }
305 if (math.signbit(x)) {
306 %return output(context, "-");
307 x = -x;
308 }
309 if (math.isPositiveInf(x)) {
310 return output(context, "Infinity");
311 }
312 if (x == 0.0) {
313 return output(context, "0.0");
314 }
315
316 var buffer: [32]u8 = undefined;
317 const float_decimal = errol3(x, buffer[0..]);
318
319 const num_left_digits = if (float_decimal.exp > 0) usize(float_decimal.exp) else 1;
320
321 %return output(context, float_decimal.digits[0 .. num_left_digits]);
322 %return output(context, ".");
323 if (float_decimal.digits.len > 1) {
324 const num_valid_digtis = if (@typeOf(value) == f32) math.min(usize(7), float_decimal.digits.len)
325 else
326 float_decimal.digits.len;
327
328 const num_right_digits = if (precision != 0)
329 math.min(precision, (num_valid_digtis-num_left_digits))
330 else
331 num_valid_digtis - num_left_digits;
332 %return output(context, float_decimal.digits[num_left_digits .. (num_left_digits + num_right_digits)]);
333 } else {
334 %return output(context, "0");
335 }
336}
337
338
270339pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
271340 context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void
272341{
......@@ -540,6 +609,39 @@ test "fmt.format" {
540609 const result = %%bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
541610 assert(mem.eql(u8, result, "f64: -Infinity\n"));
542611 }
612 {
613 var buf1: [32]u8 = undefined;
614 const value: f32 = 1.1234;
615 const result = %%bufPrint(buf1[0..], "f32: {.1}\n", value);
616 assert(mem.eql(u8, result, "f32: 1.1\n"));
617 }
618 {
619 var buf1: [32]u8 = undefined;
620 const value: f32 = 1234.567;
621 const result = %%bufPrint(buf1[0..], "f32: {.2}\n", value);
622 assert(mem.eql(u8, result, "f32: 1234.56\n"));
623 }
624 {
625 var buf1: [32]u8 = undefined;
626 const value: f32 = -11.1234;
627 const result = %%bufPrint(buf1[0..], "f32: {.4}\n", value);
628 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
629 // -11.12339... is truncated to -11.1233
630 assert(mem.eql(u8, result, "f32: -11.1233\n"));
631 }
632 {
633 var buf1: [32]u8 = undefined;
634 const value: f32 = 91.12345;
635 const result = %%bufPrint(buf1[0..], "f32: {.}\n", value);
636 assert(mem.eql(u8, result, "f32: 91.12345\n"));
637 }
638 {
639 var buf1: [32]u8 = undefined;
640 const value: f64 = 91.12345678901235;
641 const result = %%bufPrint(buf1[0..], "f64: {.10}\n", value);
642 assert(mem.eql(u8, result, "f64: 91.1234567890\n"));
643 }
644
543645 }
544646}
545647