(float) fix some rounding errors when showing as str
This seems to fix issue #1876, and some of the superficial parts of issue #1375. The #fmt macro and the to_str functions will round, rather than truncate, floats as strings. Other issues remain, and I wrote more code here than intended, but the following should pass now. ``` fn x() { assert "3.1416" == #fmt["%.4f", 3.14159]; assert "3" == #fmt["%.0f", 3.14159]; assert "99" == #fmt["%.0f", 98.5]; assert "7.0000" == #fmt["%.4f", 6.999999999]; assert "3.141590000" == #fmt["%.9f", 3.14159]; } ```
This commit is contained in:
parent
7d0755529e
commit
a7359f5b3b
@ -44,24 +44,77 @@ fn to_str_common(num: float, digits: uint, exact: bool) -> str {
|
||||
if is_NaN(num) { ret "NaN"; }
|
||||
if num == infinity { ret "inf"; }
|
||||
if num == neg_infinity { ret "-inf"; }
|
||||
let mut (num, accum) = if num < 0.0 { (-num, "-") } else { (num, "") };
|
||||
let trunc = num as uint;
|
||||
let mut frac = num - (trunc as float);
|
||||
accum += uint::str(trunc);
|
||||
if (frac < epsilon && !exact) || digits == 0u { ret accum; }
|
||||
accum += ".";
|
||||
let mut i = digits;
|
||||
let mut epsilon_prime = 1. / pow_with_uint(10u, i);
|
||||
while i > 0u && (frac >= epsilon_prime || exact) {
|
||||
frac *= 10.0;
|
||||
epsilon_prime *= 10.0;
|
||||
let digit = frac as uint;
|
||||
accum += uint::str(digit);
|
||||
frac -= digit as float;
|
||||
i -= 1u;
|
||||
}
|
||||
ret accum;
|
||||
|
||||
let mut (num, sign) = if num < 0.0 { (-num, "-") } else { (num, "") };
|
||||
|
||||
// truncated integer
|
||||
let trunc = num as uint;
|
||||
|
||||
// decimal remainder
|
||||
let mut frac = num - (trunc as float);
|
||||
|
||||
// stack of digits
|
||||
let mut fractionalParts = [];
|
||||
|
||||
// FIXME:
|
||||
// This used to return right away without rounding, as "[-]num",
|
||||
// but given epsilon like in f64.rs, I don't see how the comparison
|
||||
// to epsilon did much when only used there.
|
||||
// if (frac < epsilon && !exact) || digits == 0u { ret accum; }
|
||||
//
|
||||
// With something better, possibly weird results like this can be avoided:
|
||||
// assert "3.14158999999999988262" == my_to_str_exact(3.14159, 20u);
|
||||
|
||||
let mut ii = digits;
|
||||
let mut epsilon_prime = 1.0 / pow_with_uint(10u, ii);
|
||||
|
||||
// while we still need digits
|
||||
// build stack of digits
|
||||
while ii > 0u && (frac >= epsilon_prime || exact) {
|
||||
// store the next digit
|
||||
frac *= 10.0;
|
||||
let digit = frac as uint;
|
||||
vec::push(fractionalParts, digit);
|
||||
|
||||
// calculate the next frac
|
||||
frac -= digit as float;
|
||||
epsilon_prime *= 10.0;
|
||||
ii -= 1u;
|
||||
}
|
||||
|
||||
let mut acc;
|
||||
let mut racc = "";
|
||||
let mut carry = if frac * 10.0 as uint >= 5u { 1u } else { 0u };
|
||||
|
||||
// turn digits into string
|
||||
// using stack of digits
|
||||
while vec::len(fractionalParts) > 0u {
|
||||
let mut adjusted_digit = carry + vec::pop(fractionalParts);
|
||||
|
||||
if adjusted_digit == 10u {
|
||||
carry = 1u;
|
||||
adjusted_digit %= 10u
|
||||
} else {
|
||||
carry = 0u
|
||||
};
|
||||
|
||||
racc = uint::str(adjusted_digit) + racc;
|
||||
}
|
||||
|
||||
// pad decimals with trailing zeroes
|
||||
while str::len(racc) < digits && exact {
|
||||
racc += "0"
|
||||
}
|
||||
|
||||
// combine ints and decimals
|
||||
let mut ones = uint::str(trunc + carry);
|
||||
if racc == "" {
|
||||
acc = sign + ones;
|
||||
} else {
|
||||
acc = sign + ones + "." + racc;
|
||||
}
|
||||
|
||||
ret acc;
|
||||
}
|
||||
|
||||
#[doc = "
|
||||
|
@ -94,7 +94,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["%.f", 5.82], "6");
|
||||
test(#fmt["%.0d", 0], "");
|
||||
test(#fmt["%.0u", 0u], "");
|
||||
test(#fmt["%.0x", 0u], "");
|
||||
@ -107,7 +107,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["%.0f", 5.892], "6");
|
||||
test(#fmt["%.1d", 0], "0");
|
||||
test(#fmt["%.1u", 0u], "0");
|
||||
test(#fmt["%.1x", 0u], "0");
|
||||
|
Loading…
Reference in New Issue
Block a user