Skip to main content

ryu/pretty/
mod.rs

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