ryu/pretty/
mod.rs

1mod exponent;
2mod mantissa;
3
4use core::{mem, ptr};
5
6use self::exponent::*;
7use self::mantissa::*;
8use common;
9use d2s;
10use d2s::*;
11use f2s::*;
12
13#[cfg(feature = "no-panic")]
14use no_panic::no_panic;
15
16/// Print f64 to the given buffer and return number of bytes written.
17///
18/// At most 24 bytes will be written.
19///
20/// ## Special cases
21///
22/// This function **does not** check for NaN or infinity. If the input
23/// number is not a finite float, the printed representation will be some
24/// correctly formatted but unspecified numerical value.
25///
26/// Please check [`is_finite`] yourself before calling this function, or
27/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
28///
29/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite
30/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan
31/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite
32///
33/// ## Safety
34///
35/// The `result` pointer argument must point to sufficiently many writable bytes
36/// to hold Ryū's representation of `f`.
37///
38/// ## Example
39///
40/// ```edition2018
41/// use std::{mem::MaybeUninit, slice, str};
42///
43/// let f = 1.234f64;
44///
45/// unsafe {
46///     let mut buffer = [MaybeUninit::<u8>::uninit(); 24];
47///     let len = ryu::raw::format64(f, buffer.as_mut_ptr() as *mut u8);
48///     let slice = slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
49///     let print = str::from_utf8_unchecked(slice);
50///     assert_eq!(print, "1.234");
51/// }
52/// ```
53#[cfg_attr(must_use_return, must_use)]
54#[cfg_attr(feature = "no-panic", no_panic)]
55pub unsafe fn format64(f: f64, result: *mut u8) -> usize {
56    let bits = mem::transmute::<f64, u64>(f);
57    let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
58    let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
59    let ieee_exponent =
60        (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);
61
62    let mut index = 0isize;
63    if sign {
64        *result = b'-';
65        index += 1;
66    }
67
68    if ieee_exponent == 0 && ieee_mantissa == 0 {
69        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
70        return sign as usize + 3;
71    }
72
73    let v = d2d(ieee_mantissa, ieee_exponent);
74
75    let length = d2s::decimal_length17(v.mantissa) as isize;
76    let k = v.exponent as isize;
77    let kk = length + k; // 10^(kk-1) <= v < 10^kk
78    debug_assert!(k >= -324);
79
80    if 0 <= k && kk <= 16 {
81        // 1234e7 -> 12340000000.0
82        write_mantissa_long(v.mantissa, result.offset(index + length));
83        for i in length..kk {
84            *result.offset(index + i) = b'0';
85        }
86        *result.offset(index + kk) = b'.';
87        *result.offset(index + kk + 1) = b'0';
88        index as usize + kk as usize + 2
89    } else if 0 < kk && kk <= 16 {
90        // 1234e-2 -> 12.34
91        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
92        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
93        *result.offset(index + kk) = b'.';
94        index as usize + length as usize + 1
95    } else if -5 < kk && kk <= 0 {
96        // 1234e-6 -> 0.001234
97        *result.offset(index) = b'0';
98        *result.offset(index + 1) = b'.';
99        let offset = 2 - kk;
100        for i in 2..offset {
101            *result.offset(index + i) = b'0';
102        }
103        write_mantissa_long(v.mantissa, result.offset(index + length + offset));
104        index as usize + length as usize + offset as usize
105    } else if length == 1 {
106        // 1e30
107        *result.offset(index) = b'0' + v.mantissa as u8;
108        *result.offset(index + 1) = b'e';
109        index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2))
110    } else {
111        // 1234e30 -> 1.234e33
112        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
113        *result.offset(index) = *result.offset(index + 1);
114        *result.offset(index + 1) = b'.';
115        *result.offset(index + length + 1) = b'e';
116        index as usize
117            + length as usize
118            + 2
119            + write_exponent3(kk - 1, result.offset(index + length + 2))
120    }
121}
122
123/// Print f32 to the given buffer and return number of bytes written.
124///
125/// At most 16 bytes will be written.
126///
127/// ## Special cases
128///
129/// This function **does not** check for NaN or infinity. If the input
130/// number is not a finite float, the printed representation will be some
131/// correctly formatted but unspecified numerical value.
132///
133/// Please check [`is_finite`] yourself before calling this function, or
134/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
135///
136/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_finite
137/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_nan
138/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_infinite
139///
140/// ## Safety
141///
142/// The `result` pointer argument must point to sufficiently many writable bytes
143/// to hold Ryū's representation of `f`.
144///
145/// ## Example
146///
147/// ```edition2018
148/// use std::{mem::MaybeUninit, slice, str};
149///
150/// let f = 1.234f32;
151///
152/// unsafe {
153///     let mut buffer = [MaybeUninit::<u8>::uninit(); 16];
154///     let len = ryu::raw::format32(f, buffer.as_mut_ptr() as *mut u8);
155///     let slice = slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
156///     let print = str::from_utf8_unchecked(slice);
157///     assert_eq!(print, "1.234");
158/// }
159/// ```
160#[cfg_attr(must_use_return, must_use)]
161#[cfg_attr(feature = "no-panic", no_panic)]
162pub unsafe fn format32(f: f32, result: *mut u8) -> usize {
163    let bits = mem::transmute::<f32, u32>(f);
164    let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
165    let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
166    let ieee_exponent =
167        ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32;
168
169    let mut index = 0isize;
170    if sign {
171        *result = b'-';
172        index += 1;
173    }
174
175    if ieee_exponent == 0 && ieee_mantissa == 0 {
176        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
177        return sign as usize + 3;
178    }
179
180    let v = f2d(ieee_mantissa, ieee_exponent);
181
182    let length = common::decimal_length9(v.mantissa) as isize;
183    let k = v.exponent as isize;
184    let kk = length + k; // 10^(kk-1) <= v < 10^kk
185    debug_assert!(k >= -45);
186
187    if 0 <= k && kk <= 13 {
188        // 1234e7 -> 12340000000.0
189        write_mantissa(v.mantissa, result.offset(index + length));
190        for i in length..kk {
191            *result.offset(index + i) = b'0';
192        }
193        *result.offset(index + kk) = b'.';
194        *result.offset(index + kk + 1) = b'0';
195        index as usize + kk as usize + 2
196    } else if 0 < kk && kk <= 13 {
197        // 1234e-2 -> 12.34
198        write_mantissa(v.mantissa, result.offset(index + length + 1));
199        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
200        *result.offset(index + kk) = b'.';
201        index as usize + length as usize + 1
202    } else if -6 < kk && kk <= 0 {
203        // 1234e-6 -> 0.001234
204        *result.offset(index) = b'0';
205        *result.offset(index + 1) = b'.';
206        let offset = 2 - kk;
207        for i in 2..offset {
208            *result.offset(index + i) = b'0';
209        }
210        write_mantissa(v.mantissa, result.offset(index + length + offset));
211        index as usize + length as usize + offset as usize
212    } else if length == 1 {
213        // 1e30
214        *result.offset(index) = b'0' + v.mantissa as u8;
215        *result.offset(index + 1) = b'e';
216        index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2))
217    } else {
218        // 1234e30 -> 1.234e33
219        write_mantissa(v.mantissa, result.offset(index + length + 1));
220        *result.offset(index) = *result.offset(index + 1);
221        *result.offset(index + 1) = b'.';
222        *result.offset(index + length + 1) = b'e';
223        index as usize
224            + length as usize
225            + 2
226            + write_exponent2(kk - 1, result.offset(index + length + 2))
227    }
228}