diff --git a/src/comp/syntax/ext/fmt.rs b/src/comp/syntax/ext/fmt.rs index f3fb25acaf9..575d49e15a6 100644 --- a/src/comp/syntax/ext/fmt.rs +++ b/src/comp/syntax/ext/fmt.rs @@ -196,6 +196,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr]) ty_int(s) { alt s { signed. { ret true; } unsigned. { ret false; } } } + ty_float. { ret true; } _ { ret false; } } } @@ -250,6 +251,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr]) ty_hex(_) { ret make_conv_call(cx, arg.span, "uint", cnv, arg); } ty_bits. { ret make_conv_call(cx, arg.span, "uint", cnv, arg); } ty_octal. { ret make_conv_call(cx, arg.span, "uint", cnv, arg); } + ty_float. { ret make_conv_call(cx, arg.span, "float", cnv, arg); } _ { cx.span_unimpl(sp, unsupported); } } } @@ -301,6 +303,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr]) } } ty_octal. { log "type: octal"; } + ty_float. { log "type: float"; } } } let fmt_sp = args[0].span; diff --git a/src/lib/extfmt.rs b/src/lib/extfmt.rs index b6d04397711..460ceee5cff 100644 --- a/src/lib/extfmt.rs +++ b/src/lib/extfmt.rs @@ -49,6 +49,7 @@ mod ct { ty_bits; ty_hex(caseness); ty_octal; + ty_float; // FIXME: More types } tag flag { @@ -246,6 +247,8 @@ mod ct { ty_bits } else if str::eq(tstr, "o") { ty_octal + } else if str::eq(tstr, "f") { + ty_float } else { error("unknown type in conversion: " + tstr) }; ret {ty: t, next: i + 1u}; } @@ -328,6 +331,21 @@ mod rt { }; ret pad(cv, unpadded, pad_nozero); } + fn conv_float(cv: conv, f: float) -> str { + let (to_str, digits) = alt cv.precision { + count_is(c) { (float::to_str_exact, c as uint) } + count_implied. { (float::to_str, 6u) } + }; + let s = to_str(f, digits); + if 0.0 <= f { + if have_flag(cv.flags, flag_sign_always) { + s = "+" + s; + } else if have_flag(cv.flags, flag_space_for_sign) { + s = " " + s; + } + } + ret pad(cv, s, pad_signed); + } // Convert an int to string with minimum number of digits. If precision is // 0 and num is 0 then the result is the empty string. diff --git a/src/lib/float.rs b/src/lib/float.rs index 0b8a701e7aa..faa71b4ed56 100644 --- a/src/lib/float.rs +++ b/src/lib/float.rs @@ -7,16 +7,17 @@ Module: float */ /* -Function: to_str +Function: to_str_common Converts a float to a string Parameters: num - The float value -digits: The number of significant digits +digits - The number of significant digits +exact - Whether to enforce the exact number of significant digits */ -fn to_str(num: float, digits: uint) -> str { +fn to_str_common(num: float, digits: uint, exact: bool) -> str { let (num, accum) = num < 0.0 ? (-num, "-") : (num, ""); let trunc = num as uint; let frac = num - (trunc as float); @@ -24,14 +25,46 @@ fn to_str(num: float, digits: uint) -> str { if frac == 0.0 || digits == 0u { ret accum; } accum += "."; let i = digits; - while i > 0u && frac > 0.0 { + let epsilon = 1. / pow_uint_to_uint_as_float(10u, i); + while i > 0u && (frac >= epsilon || exact) { frac *= 10.0; + epsilon *= 10.0; let digit = frac as uint; accum += uint::str(digit); frac -= digit as float; i -= 1u; } ret accum; + +} + +/* +Function: to_str + +Converts a float to a string with exactly the number of provided significant +digits + +Parameters: + +num - The float value +digits - The number of significant digits +*/ +fn to_str_exact(num: float, digits: uint) -> str { + to_str_common(num, digits, true) +} + +/* +Function: to_str + +Converts a float to a string with a maximum number of significant digits + +Parameters: + +num - The float value +digits - The number of significant digits +*/ +fn to_str(num: float, digits: uint) -> str { + to_str_common(num, digits, false) } /* diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index c241a68e7f1..93e18580c64 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -38,6 +38,7 @@ fn part1() { test(#fmt["%X", 0x12ab_u], "12AB"); test(#fmt["%o", 10u], "12"); test(#fmt["%t", 0b11010101_u], "11010101"); + test(#fmt["%f", 5.82], "5.82"); // 32-bit limits test(#fmt["%i", -2147483648], "-2147483648"); @@ -61,6 +62,7 @@ fn part2() { test(#fmt["%10o", 10u], " 12"); test(#fmt["%10t", 0xff_u], " 11111111"); test(#fmt["%10c", 'A'], " A"); + test(#fmt["%10f", 5.82], " 5.82"); // Left justify test(#fmt["%-10d", 500], "500 "); @@ -73,6 +75,7 @@ fn part2() { test(#fmt["%-10o", 10u], "12 "); test(#fmt["%-10t", 0xff_u], "11111111 "); test(#fmt["%-10c", 'A'], "A "); + test(#fmt["%-10f", 5.82], "5.82 "); } fn part3() { @@ -90,6 +93,7 @@ fn part3() { test(#fmt["%.o", 10u], "12"); test(#fmt["%.t", 3u], "11"); test(#fmt["%.c", 'A'], "A"); + test(#fmt["%.f", 5.82], "5"); test(#fmt["%.0d", 0], ""); test(#fmt["%.0u", 0u], ""); test(#fmt["%.0x", 0u], ""); @@ -102,6 +106,7 @@ fn part3() { test(#fmt["%.0o", 10u], "12"); test(#fmt["%.0t", 3u], "11"); test(#fmt["%.0c", 'A'], "A"); + test(#fmt["%.0f", 5.892], "5"); test(#fmt["%.1d", 0], "0"); test(#fmt["%.1u", 0u], "0"); test(#fmt["%.1x", 0u], "0"); @@ -114,6 +119,7 @@ fn part3() { test(#fmt["%.1o", 10u], "12"); test(#fmt["%.1t", 3u], "11"); test(#fmt["%.1c", 'A'], "A"); + test(#fmt["%.1f", 5.82], "5.8"); } fn part4() { test(#fmt["%.5d", 0], "00000"); @@ -128,6 +134,7 @@ fn part4() { test(#fmt["%.5o", 10u], "00012"); test(#fmt["%.5t", 3u], "00011"); test(#fmt["%.5c", 'A'], "A"); + test(#fmt["%.5f", 5.82], "5.82000"); // Bool precision. I'm not sure if it's good or bad to have bool // conversions support precision - it's not standard printf so we // can do whatever. For now I'm making it behave the same as string @@ -144,15 +151,19 @@ fn part5() { test(#fmt["%+d", 0], "+0"); test(#fmt["%+d", 1], "+1"); test(#fmt["%+d", -1], "-1"); + test(#fmt["%+f", 0.0], "+0"); // Leave space for sign test(#fmt["% d", 0], " 0"); test(#fmt["% d", 1], " 1"); test(#fmt["% d", -1], "-1"); + test(#fmt["% f", 0.0], " 0"); // Plus overrides space test(#fmt["% +d", 0], "+0"); test(#fmt["%+ d", 0], "+0"); + test(#fmt["% +f", 0.0], "+0"); + test(#fmt["%+ f", 0.0], "+0"); // 0-padding test(#fmt["%05d", 0], "00000"); @@ -163,6 +174,7 @@ fn part5() { test(#fmt["%05X", 127u], "0007F"); test(#fmt["%05o", 10u], "00012"); test(#fmt["%05t", 3u], "00011"); + test(#fmt["%05f", 5.82], "05.82"); // 0-padding a string is undefined but glibc does this: test(#fmt["%05s", "test"], " test"); @@ -181,6 +193,7 @@ fn part5() { test(#fmt["%-05s", "test"], "test "); test(#fmt["%-05c", 'A'], "A "); test(#fmt["%-05b", true], "true "); + test(#fmt["%-05f", 5.82], "5.82 "); } fn part6() { // Precision overrides 0-padding @@ -196,6 +209,7 @@ fn part6() { test(#fmt["%06.5x", 127u], " 0007f"); test(#fmt["%06.5X", 127u], " 0007F"); test(#fmt["%06.5o", 10u], " 00012"); + test(#fmt["%08.5f", 5.82], " 5.82000"); // Signed combinations test(#fmt["% 5d", 1], " 1");