1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![allow(missing_doc)]
14 use collections::Collection;
16 use iter::{Iterator, range, DoubleEndedIterator};
17 use num::{Float, FPNaN, FPInfinite, ToPrimitive, Primitive};
18 use num::{Zero, One, cast};
19 use option::{None, Some};
21 use slice::{ImmutableVector, MutableVector};
25 /// A flag that specifies whether to use exponential (scientific) notation.
26 pub enum ExponentFormat {
27 /// Do not use exponential notation.
29 /// Use exponential notation with the exponent having a base of 10 and the
30 /// exponent sign being `e` or `E`. For example, 1000 would be printed
33 /// Use exponential notation with the exponent having a base of 2 and the
34 /// exponent sign being `p` or `P`. For example, 8 would be printed 1p3.
38 /// The number of digits used for emitting the fractional part of a number, if
40 pub enum SignificantDigits {
41 /// All calculable digits will be printed.
43 /// Note that bignums or fractions may cause a surprisingly large number
44 /// of digits to be printed.
47 /// At most the given number of digits will be printed, truncating any
51 /// Precisely the given number of digits will be printed.
55 /// How to emit the sign of a number.
57 /// No sign will be printed. The exponent sign will also be emitted.
59 /// `-` will be printed for negative values, but no sign will be emitted
60 /// for positive numbers.
62 /// `+` will be printed for positive values, and `-` will be printed for
67 static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
68 static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
71 * Converts a number to its string representation as a byte vector.
72 * This is meant to be a common base implementation for all numeric string
73 * conversion functions like `to_string()` or `to_str_radix()`.
76 * - `num` - The number to convert. Accepts any number that
77 * implements the numeric traits.
78 * - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation
79 * is used, then this base is only used for the significand. The exponent
80 * itself always printed using a base of 10.
81 * - `negative_zero` - Whether to treat the special value `-0` as
83 * - `sign` - How to emit the sign. See `SignFormat`.
84 * - `digits` - The amount of digits to use for emitting the fractional
85 * part, if any. See `SignificantDigits`.
86 * - `exp_format` - Whether or not to use the exponential (scientific) notation.
87 * See `ExponentFormat`.
88 * - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if
89 * exponential notation is desired.
90 * - `f` - A closure to invoke with the bytes representing the
94 * - Fails if `radix` < 2 or `radix` > 36.
95 * - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
96 * between digit and exponent sign `'e'`.
97 * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
98 * between digit and exponent sign `'p'`.
100 pub fn float_to_str_bytes_common<T: Primitive + Float, U>(
105 digits: SignificantDigits,
106 exp_format: ExponentFormat,
110 assert!(2 <= radix && radix <= 36);
112 ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
113 => fail!("float_to_str_bytes_common: radix {} incompatible with \
114 use of 'e' as decimal exponent", radix),
115 ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
116 => fail!("float_to_str_bytes_common: radix {} incompatible with \
117 use of 'p' as binary exponent", radix),
121 let _0: T = Zero::zero();
122 let _1: T = One::one();
124 match num.classify() {
125 FPNaN => return f("NaN".as_bytes()),
126 FPInfinite if num > _0 => {
128 SignAll => return f("+inf".as_bytes()),
129 _ => return f("inf".as_bytes()),
132 FPInfinite if num < _0 => {
134 SignNone => return f("inf".as_bytes()),
135 _ => return f("-inf".as_bytes()),
141 let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
142 // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so
143 // we may have up to that many digits. Give ourselves some extra wiggle room
144 // otherwise as well.
145 let mut buf = [0u8, ..1536];
147 let radix_gen: T = cast(radix as int).unwrap();
149 let (num, exp) = match exp_format {
150 ExpNone => (num, 0i32),
151 ExpDec | ExpBin if num == _0 => (num, 0i32),
153 let (exp, exp_base) = match exp_format {
154 ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
155 ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
156 ExpNone => fail!("unreachable"),
159 (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
163 // First emit the non-fractional part, looping at least once to make
164 // sure at least a `0` gets emitted.
165 let mut deccum = num.trunc();
167 // Calculate the absolute value of each digit instead of only
168 // doing it once for the whole number because a
169 // representable negative number doesn't necessary have an
170 // representable additive inverse of the same type
171 // (See twos complement). But we assume that for the
172 // numbers [-35 .. 0] we always have [0 .. 35].
173 let current_digit = (deccum % radix_gen).abs();
175 // Decrease the deccumulator one digit at a time
176 deccum = deccum / radix_gen;
177 deccum = deccum.trunc();
179 let c = char::from_digit(current_digit.to_int().unwrap() as uint, radix);
180 buf[end] = c.unwrap() as u8;
183 // No more digits to calculate for the non-fractional part -> break
184 if deccum == _0 { break; }
187 // If limited digits, calculate one digit more for rounding.
188 let (limit_digits, digit_count, exact) = match digits {
189 DigAll => (false, 0u, false),
190 DigMax(count) => (true, count+1, false),
191 DigExact(count) => (true, count+1, true)
194 // Decide what sign to put in front
196 SignNeg | SignAll if neg => {
197 buf[end] = '-' as u8;
201 buf[end] = '+' as u8;
207 buf.mut_slice_to(end).reverse();
209 // Remember start of the fractional digits.
210 // Points one beyond end of buf if none get generated,
211 // or at the '.' otherwise.
212 let start_fractional_digits = end;
214 // Now emit the fractional part, if any
215 deccum = num.fract();
216 if deccum != _0 || (limit_digits && exact && digit_count > 0) {
217 buf[end] = '.' as u8;
221 // calculate new digits while
222 // - there is no limit and there are digits left
223 // - or there is a limit, it's not reached yet and
225 // - or it's a maximum, and there are still digits left
226 while (!limit_digits && deccum != _0)
227 || (limit_digits && dig < digit_count && (
229 || (!exact && deccum != _0)
232 // Shift first fractional digit into the integer part
233 deccum = deccum * radix_gen;
235 // Calculate the absolute value of each digit.
236 // See note in first loop.
237 let current_digit = deccum.trunc().abs();
239 let c = char::from_digit(current_digit.to_int().unwrap() as uint,
241 buf[end] = c.unwrap() as u8;
244 // Decrease the deccumulator one fractional digit at a time
245 deccum = deccum.fract();
249 // If digits are limited, and that limit has been reached,
250 // cut off the one extra digit, and depending on its value
251 // round the remaining ones.
252 if limit_digits && dig == digit_count {
253 let ascii2value = |chr: u8| {
254 char::to_digit(chr as char, radix).unwrap()
256 let value2ascii = |val: uint| {
257 char::from_digit(val, radix).unwrap() as u8
260 let extra_digit = ascii2value(buf[end - 1]);
262 if extra_digit >= radix / 2 { // -> need to round
263 let mut i: int = end as int - 1;
265 // If reached left end of number, have to
266 // insert additional digit:
268 || buf[i as uint] == '-' as u8
269 || buf[i as uint] == '+' as u8 {
270 for j in range(i as uint + 1, end).rev() {
273 buf[(i + 1) as uint] = value2ascii(1);
279 if buf[i as uint] == '.' as u8 { i -= 1; continue; }
281 // Either increment the digit,
282 // or set to 0 if max and carry the 1.
283 let current_digit = ascii2value(buf[i as uint]);
284 if current_digit < (radix - 1) {
285 buf[i as uint] = value2ascii(current_digit+1);
288 buf[i as uint] = value2ascii(0);
296 // if number of digits is not exact, remove all trailing '0's up to
297 // and including the '.'
299 let buf_max_i = end - 1;
301 // index to truncate from
302 let mut i = buf_max_i;
304 // discover trailing zeros of fractional part
305 while i > start_fractional_digits && buf[i] == '0' as u8 {
309 // Only attempt to truncate digits if buf has fractional digits
310 if i >= start_fractional_digits {
311 // If buf ends with '.', cut that too.
312 if buf[i] == '.' as u8 { i -= 1 }
314 // only resize buf if we actually remove digits
319 } // If exact and trailing '.', just cut that
322 if buf[max_i] == '.' as u8 {
330 buf[end] = match exp_format {
331 ExpDec if exp_upper => 'E',
332 ExpDec if !exp_upper => 'e',
333 ExpBin if exp_upper => 'P',
334 ExpBin if !exp_upper => 'p',
335 _ => fail!("unreachable"),
344 impl<'a> fmt::FormatWriter for Filler<'a> {
345 fn write(&mut self, bytes: &[u8]) -> fmt::Result {
346 slice::bytes::copy_memory(self.buf.mut_slice_from(*self.end),
348 *self.end += bytes.len();
353 let mut filler = Filler { buf: buf, end: &mut end };
356 let _ = format_args!(|args| {
357 fmt::write(&mut filler, args)
360 SignNone | SignAll => {
361 let _ = format_args!(|args| {
362 fmt::write(&mut filler, args)