Skip to content

Commit 3c10706

Browse files
authored
Rollup merge of #41509 - froydnj:float-stack-reduction, r=nagisa
reduce stack requirements for floating-point formatting Doing this speeds up float formatting by ~10% or so, and also makes the formatting code more suitable for embedded environments where stack space is at a premium.
2 parents ab99c9b + b2c3102 commit 3c10706

File tree

2 files changed

+104
-18
lines changed

2 files changed

+104
-18
lines changed

src/libcore/benches/num/flt2dec/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ mod strategy {
1313
mod grisu;
1414
}
1515

16+
use std::f64;
17+
use std::io::Write;
18+
use std::vec::Vec;
19+
use test::Bencher;
1620
use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
1721
use core::num::flt2dec::MAX_SIG_DIGITS;
1822

@@ -22,3 +26,23 @@ pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
2226
full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
2327
}
2428
}
29+
30+
#[bench]
31+
fn bench_small_shortest(b: &mut Bencher) {
32+
let mut buf = Vec::with_capacity(20);
33+
34+
b.iter(|| {
35+
buf.clear();
36+
write!(&mut buf, "{}", 3.1415926f64).unwrap()
37+
});
38+
}
39+
40+
#[bench]
41+
fn bench_big_shortest(b: &mut Bencher) {
42+
let mut buf = Vec::with_capacity(300);
43+
44+
b.iter(|| {
45+
buf.clear();
46+
write!(&mut buf, "{}", f64::MAX).unwrap()
47+
});
48+
}

src/libcore/fmt/float.rs

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,43 @@
99
// except according to those terms.
1010

1111
use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
12+
use mem;
1213
use num::flt2dec;
1314

15+
// Don't inline this so callers don't use the stack space this function
16+
// requires unless they have to.
17+
#[inline(never)]
18+
fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T,
19+
sign: flt2dec::Sign, precision: usize) -> Result
20+
where T: flt2dec::DecodableFloat
21+
{
22+
unsafe {
23+
let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64
24+
let mut parts: [flt2dec::Part; 5] = mem::uninitialized();
25+
let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact,
26+
*num, sign, precision,
27+
false, &mut buf, &mut parts);
28+
fmt.pad_formatted_parts(&formatted)
29+
}
30+
}
31+
32+
// Don't inline this so callers that call both this and the above won't wind
33+
// up using the combined stack space of both functions in some cases.
34+
#[inline(never)]
35+
fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter,
36+
num: &T, sign: flt2dec::Sign) -> Result
37+
where T: flt2dec::DecodableFloat
38+
{
39+
unsafe {
40+
// enough for f32 and f64
41+
let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized();
42+
let mut parts: [flt2dec::Part; 5] = mem::uninitialized();
43+
let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest,
44+
*num, sign, 0, false, &mut buf, &mut parts);
45+
fmt.pad_formatted_parts(&formatted)
46+
}
47+
}
48+
1449
// Common code of floating point Debug and Display.
1550
fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
1651
where T: flt2dec::DecodableFloat
@@ -23,16 +58,48 @@ fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool)
2358
(true, true) => flt2dec::Sign::MinusPlusRaw,
2459
};
2560

26-
let mut buf = [0; 1024]; // enough for f32 and f64
27-
let mut parts = [flt2dec::Part::Zero(0); 16];
28-
let formatted = if let Some(precision) = fmt.precision {
29-
flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign,
30-
precision, false, &mut buf, &mut parts)
61+
if let Some(precision) = fmt.precision {
62+
float_to_decimal_common_exact(fmt, num, sign, precision)
3163
} else {
32-
flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
33-
0, false, &mut buf, &mut parts)
34-
};
35-
fmt.pad_formatted_parts(&formatted)
64+
float_to_decimal_common_shortest(fmt, num, sign)
65+
}
66+
}
67+
68+
// Don't inline this so callers don't use the stack space this function
69+
// requires unless they have to.
70+
#[inline(never)]
71+
fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T,
72+
sign: flt2dec::Sign, precision: usize,
73+
upper: bool) -> Result
74+
where T: flt2dec::DecodableFloat
75+
{
76+
unsafe {
77+
let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64
78+
let mut parts: [flt2dec::Part; 7] = mem::uninitialized();
79+
let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
80+
*num, sign, precision,
81+
upper, &mut buf, &mut parts);
82+
fmt.pad_formatted_parts(&formatted)
83+
}
84+
}
85+
86+
// Don't inline this so callers that call both this and the above won't wind
87+
// up using the combined stack space of both functions in some cases.
88+
#[inline(never)]
89+
fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter,
90+
num: &T, sign: flt2dec::Sign,
91+
upper: bool) -> Result
92+
where T: flt2dec::DecodableFloat
93+
{
94+
unsafe {
95+
// enough for f32 and f64
96+
let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized();
97+
let mut parts: [flt2dec::Part; 7] = mem::uninitialized();
98+
let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest,
99+
*num, sign, (0, 0), upper,
100+
&mut buf, &mut parts);
101+
fmt.pad_formatted_parts(&formatted)
102+
}
36103
}
37104

38105
// Common code of floating point LowerExp and UpperExp.
@@ -45,17 +112,12 @@ fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) ->
45112
true => flt2dec::Sign::MinusPlus,
46113
};
47114

48-
let mut buf = [0; 1024]; // enough for f32 and f64
49-
let mut parts = [flt2dec::Part::Zero(0); 16];
50-
let formatted = if let Some(precision) = fmt.precision {
115+
if let Some(precision) = fmt.precision {
51116
// 1 integral digit + `precision` fractional digits = `precision + 1` total digits
52-
flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign,
53-
precision + 1, upper, &mut buf, &mut parts)
117+
float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
54118
} else {
55-
flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign,
56-
(0, 0), upper, &mut buf, &mut parts)
57-
};
58-
fmt.pad_formatted_parts(&formatted)
119+
float_to_exponential_common_shortest(fmt, num, sign, upper)
120+
}
59121
}
60122

61123
macro_rules! floating {

0 commit comments

Comments
 (0)