Skip to main content

ryu/pretty/
mod.rs

1mod exponent;
2mod mantissa;
3
4use core::ptr;
5
6use self::{
7    exponent::{write_exponent2, write_exponent3},
8    mantissa::{write_mantissa, write_mantissa_long},
9};
10use crate::{
11    common,
12    d2s::{self, DOUBLE_EXPONENT_BITS, DOUBLE_MANTISSA_BITS, d2d},
13    f2s::{FLOAT_EXPONENT_BITS, FLOAT_MANTISSA_BITS, f2d},
14};
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/// ```
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#[must_use]
54pub unsafe fn format64(f: f64, result: *mut u8) -> usize {
55    unsafe {
56        let bits = f.to_bits();
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 = (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);
60
61        let mut index = 0isize;
62        if sign {
63            *result = b'-';
64            index += 1;
65        }
66
67        if ieee_exponent == 0 && ieee_mantissa == 0 {
68            ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
69            return sign as usize + 3;
70        }
71
72        let v = d2d(ieee_mantissa, ieee_exponent);
73
74        let length = d2s::decimal_length17(v.mantissa) as isize;
75        let k = v.exponent as isize;
76        let kk = length + k; // 10^(kk-1) <= v < 10^kk
77        debug_assert!(k >= -324);
78
79        if 0 <= k && kk <= 16 {
80            // 1234e7 -> 12340000000.0
81            write_mantissa_long(v.mantissa, result.offset(index + length));
82            for i in length..kk {
83                *result.offset(index + i) = b'0';
84            }
85            *result.offset(index + kk) = b'.';
86            *result.offset(index + kk + 1) = b'0';
87            index as usize + kk as usize + 2
88        } else if 0 < kk && kk <= 16 {
89            // 1234e-2 -> 12.34
90            write_mantissa_long(v.mantissa, result.offset(index + length + 1));
91            ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
92            *result.offset(index + kk) = b'.';
93            index as usize + length as usize + 1
94        } else if -5 < kk && kk <= 0 {
95            // 1234e-6 -> 0.001234
96            *result.offset(index) = b'0';
97            *result.offset(index + 1) = b'.';
98            let offset = 2 - kk;
99            for i in 2..offset {
100                *result.offset(index + i) = b'0';
101            }
102            write_mantissa_long(v.mantissa, result.offset(index + length + offset));
103            index as usize + length as usize + offset as usize
104        } else if length == 1 {
105            // 1e30
106            *result.offset(index) = b'0' + v.mantissa as u8;
107            *result.offset(index + 1) = b'e';
108            index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2))
109        } else {
110            // 1234e30 -> 1.234e33
111            write_mantissa_long(v.mantissa, result.offset(index + length + 1));
112            *result.offset(index) = *result.offset(index + 1);
113            *result.offset(index + 1) = b'.';
114            *result.offset(index + length + 1) = b'e';
115            index as usize + length as usize + 2 + write_exponent3(kk - 1, result.offset(index + length + 2))
116        }
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`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_finite
134/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_nan
135/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.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]
158pub unsafe fn format32(f: f32, result: *mut u8) -> usize {
159    unsafe {
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 + length as usize + 2 + write_exponent2(kk - 1, result.offset(index + length + 2))
220        }
221    }
222}