ryu/pretty/
mod.rs

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