Skip to content

Commit 85fecf5

Browse files
HalidOdatphekidtolnay
authored
Sync to dtolnay/ryu master (#16)
Co-authored-by: Aphek <bilkow@tutanota.com> Co-authored-by: David Tolnay <dtolnay@gmail.com>
1 parent 38ee311 commit 85fecf5

File tree

10 files changed

+90
-14
lines changed

10 files changed

+90
-14
lines changed

.clippy.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
msrv = "1.31.0"

.github/workflows/ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,12 @@ jobs:
3939
- uses: dtolnay/rust-toolchain@nightly
4040
with:
4141
components: miri
42-
- run: cargo miri setup
4342
- run: cargo miri test
43+
44+
clippy:
45+
name: Clippy
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@v2
49+
- uses: dtolnay/rust-toolchain@clippy
50+
- run: cargo clippy -- -Dclippy::all -Dclippy::pedantic

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ C, [https://github.com/ulfjack/ryu][upstream].
2121
uses nothing from the Rust standard library so is usable from no_std crates.*
2222

2323
[paper]: https://dl.acm.org/citation.cfm?id=3192369
24-
[upstream]: https://github.com/ulfjack/ryu/tree/1c413e127f8d02afd12eb6259bc80163722f1385
24+
[upstream]: https://github.com/ulfjack/ryu/tree/abf76d252bc97300354857e64e80d4a2bf664291
2525

2626
```toml
2727
[dependencies]

src/buffer/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::raw;
2+
#[cfg(not(maybe_uninit))]
3+
use core::mem;
24
#[cfg(maybe_uninit)]
35
use core::mem::MaybeUninit;
46
use core::{slice, str};

src/d2s_small_table.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::common::*;
2222
#[cfg(not(integer128))]
2323
use crate::d2s_intrinsics::*;
2424

25-
pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 13] = [
25+
pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 15] = [
2626
(1, 2305843009213693952),
2727
(5955668970331000884, 1784059615882449851),
2828
(8982663654677661702, 1380349269358112757),
@@ -36,6 +36,8 @@ pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 13] = [
3636
(12533209867169019542, 1418129833677084982),
3737
(5577825024675947042, 2194449627517475473),
3838
(11006974540203867551, 1697873161311732311),
39+
(10313493231639821582, 1313665730009899186),
40+
(12701016819766672773, 2032799256770390445),
3941
];
4042

4143
pub static POW5_INV_OFFSETS: [u32; 19] = [
@@ -112,7 +114,7 @@ pub unsafe fn compute_pow5(i: u32) -> (u64, u64) {
112114
let b0 = m as u128 * mul.0 as u128;
113115
let b2 = m as u128 * mul.1 as u128;
114116
let delta = pow5bits(i as i32) - pow5bits(base2 as i32);
115-
debug_assert!(base < POW5_OFFSETS.len() as u32);
117+
debug_assert!(i / 16 < POW5_OFFSETS.len() as u32);
116118
let shifted_sum = (b0 >> delta)
117119
+ (b2 << (64 - delta))
118120
+ ((*POW5_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u128;
@@ -165,7 +167,7 @@ pub unsafe fn compute_pow5(i: u32) -> (u64, u64) {
165167
}
166168
// high1 | sum | low0
167169
let delta = pow5bits(i as i32) - pow5bits(base2 as i32);
168-
debug_assert!(base < POW5_OFFSETS.len() as u32);
170+
debug_assert!(i / 16 < POW5_OFFSETS.len() as u32);
169171
(
170172
shiftright128(low0, sum, delta as u32)
171173
+ ((*POW5_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u64,

src/lib.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,24 @@
6666
6767
#![no_std]
6868
#![doc(html_root_url = "https://docs.rs/ryu-js/0.2.1")]
69-
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
70-
#![cfg_attr(
71-
feature = "cargo-clippy",
72-
allow(cast_lossless, many_single_char_names, unreadable_literal,)
69+
#![allow(
70+
clippy::cast_lossless,
71+
clippy::cast_possible_truncation,
72+
clippy::cast_possible_wrap,
73+
clippy::cast_sign_loss,
74+
clippy::checked_conversions,
75+
clippy::doc_markdown,
76+
clippy::expl_impl_clone_on_copy,
77+
clippy::if_not_else,
78+
clippy::many_single_char_names,
79+
clippy::missing_panics_doc,
80+
clippy::module_name_repetitions,
81+
clippy::must_use_candidate,
82+
clippy::similar_names,
83+
clippy::too_many_lines,
84+
clippy::unreadable_literal,
85+
clippy::unseparated_literal_suffix,
86+
clippy::wildcard_imports
7387
)]
7488

7589
mod buffer;

src/s2d.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,13 @@ pub fn s2d(buffer: &[u8]) -> Result<f64, Error> {
202202
let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0);
203203

204204
let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u64);
205-
if ieee_m2 == (1_u64 << (d2s::DOUBLE_MANTISSA_BITS + 1)) {
205+
debug_assert!(ieee_m2 <= 1_u64 << (d2s::DOUBLE_MANTISSA_BITS + 1));
206+
ieee_m2 &= (1_u64 << d2s::DOUBLE_MANTISSA_BITS) - 1;
207+
if ieee_m2 == 0 && round_up {
206208
// Due to how the IEEE represents +/-Infinity, we don't need to check
207209
// for overflow here.
208210
ieee_e2 += 1;
209211
}
210-
ieee_m2 &= (1_u64 << d2s::DOUBLE_MANTISSA_BITS) - 1;
211212
let ieee = ((((signed_m as u64) << d2s::DOUBLE_EXPONENT_BITS) | ieee_e2 as u64)
212213
<< d2s::DOUBLE_MANTISSA_BITS)
213214
| ieee_m2;

src/s2f.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,28 @@ pub fn s2f(buffer: &[u8]) -> Result<f32, Error> {
151151
.wrapping_add(e10 as u32)
152152
.wrapping_sub(ceil_log2_pow5(-e10) as u32)
153153
.wrapping_sub(f2s::FLOAT_MANTISSA_BITS + 1) as i32;
154+
155+
// We now compute [m10 * 10^e10 / 2^e2] = [m10 / (5^(-e10) 2^(e2-e10))].
154156
let j = e2
155157
.wrapping_sub(e10)
156158
.wrapping_add(ceil_log2_pow5(-e10))
157159
.wrapping_sub(1)
158160
.wrapping_add(f2s::FLOAT_POW5_INV_BITCOUNT);
159161
m2 = mul_pow5_inv_div_pow2(m10, -e10 as u32, j);
160162

161-
multiple_of_power_of_5_32(m10, -e10 as u32)
163+
// We also compute if the result is exact, i.e.,
164+
// [m10 / (5^(-e10) 2^(e2-e10))] == m10 / (5^(-e10) 2^(e2-e10))
165+
//
166+
// If e2-e10 >= 0, we need to check whether (5^(-e10) 2^(e2-e10))
167+
// divides m10, which is the case iff pow5(m10) >= -e10 AND pow2(m10) >=
168+
// e2-e10.
169+
//
170+
// If e2-e10 < 0, we have actually computed [m10 * 2^(e10 e2) /
171+
// 5^(-e10)] above, and we need to check whether 5^(-e10) divides (m10 *
172+
// 2^(e10-e2)), which is the case iff pow5(m10 * 2^(e10-e2)) = pow5(m10)
173+
// >= -e10.
174+
(e2 < e10 || (e2 - e10 < 32 && multiple_of_power_of_2_32(m10, (e2 - e10) as u32)))
175+
&& multiple_of_power_of_5_32(m10, -e10 as u32)
162176
};
163177

164178
// Compute the final IEEE exponent.
@@ -193,12 +207,16 @@ pub fn s2f(buffer: &[u8]) -> Result<f32, Error> {
193207
let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0);
194208

195209
let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u32);
196-
if ieee_m2 == (1_u32 << (f2s::FLOAT_MANTISSA_BITS + 1)) {
210+
debug_assert!(ieee_m2 <= 1_u32 << (f2s::FLOAT_MANTISSA_BITS + 1));
211+
ieee_m2 &= (1_u32 << f2s::FLOAT_MANTISSA_BITS) - 1;
212+
if ieee_m2 == 0 && round_up {
213+
// Rounding up may overflow the mantissa.
214+
// In this case we move a trailing zero of the mantissa into the
215+
// exponent.
197216
// Due to how the IEEE represents +/-Infinity, we don't need to check
198217
// for overflow here.
199218
ieee_e2 += 1;
200219
}
201-
ieee_m2 &= (1_u32 << f2s::FLOAT_MANTISSA_BITS) - 1;
202220
let ieee = ((((signed_m as u32) << f2s::FLOAT_EXPONENT_BITS) | ieee_e2 as u32)
203221
<< f2s::FLOAT_MANTISSA_BITS)
204222
| ieee_m2;

tests/s2d_test.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ fn test_basic() {
7878
assert_eq!(1.0, s2d(b"1e0").unwrap());
7979
assert_eq!(1.0, s2d(b"1E0").unwrap());
8080
assert_eq!(1.0, s2d(b"000001.000000").unwrap());
81+
assert_eq!(0.2316419, s2d(b"0.2316419").unwrap());
8182
}
8283

8384
#[test]
@@ -130,3 +131,20 @@ fn test_issue157() {
130131
s2d(b"1.2999999999999999E+154").unwrap(),
131132
);
132133
}
134+
135+
#[test]
136+
fn test_issue173() {
137+
// Denormal boundary
138+
assert_eq!(
139+
2.2250738585072012e-308,
140+
s2d(b"2.2250738585072012e-308").unwrap(),
141+
);
142+
assert_eq!(
143+
2.2250738585072013e-308,
144+
s2d(b"2.2250738585072013e-308").unwrap(),
145+
);
146+
assert_eq!(
147+
2.2250738585072014e-308,
148+
s2d(b"2.2250738585072014e-308").unwrap(),
149+
);
150+
}

tests/s2f_test.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,17 @@ fn test_min_max() {
7575
fn test_mantissa_rounding_overflow() {
7676
assert_eq!(1.0, s2f(b"0.999999999").unwrap());
7777
assert_eq!(f32::INFINITY, s2f(b"3.4028236e+38").unwrap());
78+
assert_eq!(1.1754944e-38, s2f(b"1.17549430e-38").unwrap()); // FLT_MIN
79+
assert_eq!(1.1754944e-38, s2f(b"1.17549431e-38").unwrap());
80+
assert_eq!(1.1754944e-38, s2f(b"1.17549432e-38").unwrap());
81+
assert_eq!(1.1754944e-38, s2f(b"1.17549433e-38").unwrap());
82+
assert_eq!(1.1754944e-38, s2f(b"1.17549434e-38").unwrap());
83+
assert_eq!(1.1754944e-38, s2f(b"1.17549435e-38").unwrap());
84+
}
85+
86+
#[test]
87+
fn test_trailing_zeros() {
88+
assert_eq!(26843550.0, s2f(b"26843549.5").unwrap());
89+
assert_eq!(50000004.0, s2f(b"50000002.5").unwrap());
90+
assert_eq!(99999992.0, s2f(b"99999989.5").unwrap());
7891
}

0 commit comments

Comments
 (0)