Add float support to #fmt. Fix #1014.

This commit is contained in:
Josh Matthews 2011-11-10 06:31:42 -05:00 committed by Brian Anderson
parent 599baf9325
commit 43cb74b830
4 changed files with 72 additions and 4 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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)
}
/*

View File

@ -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");