diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:45:24 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:45:24 +0000 |
commit | 05da7a31d0bff142b4e3817d028287cf69c825cd (patch) | |
tree | 87a8aab98a66595cccf5a7c95c7db70e8d5d51a6 | |
parent | d6e2173bf8206b23c780225ba4c813dda4dea598 (diff) | |
parent | 17edc3d1294b4aec6e1ff6ca68512b560cfd9bc9 (diff) | |
download | ryu-05da7a31d0bff142b4e3817d028287cf69c825cd.tar.gz |
Snap for 8730993 from 17edc3d1294b4aec6e1ff6ca68512b560cfd9bc9 to mainline-tzdata3-releaseaml_tz3_314012070aml_tz3_314012050aml_tz3_314012010aml_tz3_313110000aml_tz3_312511020aml_tz3_312511010aml_tz3_312410020aml_tz3_312410010android12-mainline-tzdata3-releaseaml_tz3_314012010
Change-Id: Id5d7750bc5cfe3039b35480df556c22f267cf08a
-rw-r--r-- | .cargo_vcs_info.json | 7 | ||||
-rw-r--r-- | .clippy.toml | 1 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 26 | ||||
-rw-r--r-- | Android.bp | 82 | ||||
-rw-r--r-- | Cargo.toml | 18 | ||||
-rw-r--r-- | Cargo.toml.orig | 9 | ||||
-rw-r--r-- | METADATA | 10 | ||||
-rw-r--r-- | README.md | 26 | ||||
-rw-r--r-- | TEST_MAPPING | 93 | ||||
-rw-r--r-- | build.rs | 40 | ||||
-rw-r--r-- | cargo2android.json | 3 | ||||
-rw-r--r-- | src/buffer/mod.rs | 28 | ||||
-rw-r--r-- | src/d2s.rs | 60 | ||||
-rw-r--r-- | src/d2s_intrinsics.rs | 82 | ||||
-rw-r--r-- | src/d2s_small_table.rs | 71 | ||||
-rw-r--r-- | src/lib.rs | 40 | ||||
-rw-r--r-- | src/pretty/exponent.rs | 6 | ||||
-rw-r--r-- | src/pretty/mantissa.rs | 48 | ||||
-rw-r--r-- | src/pretty/mod.rs | 6 | ||||
-rw-r--r-- | src/s2d.rs | 5 | ||||
-rw-r--r-- | src/s2f.rs | 26 | ||||
-rw-r--r-- | tests/common_test.rs | 8 | ||||
-rw-r--r-- | tests/d2s_table_test.rs | 9 | ||||
-rw-r--r-- | tests/d2s_test.rs | 10 | ||||
-rw-r--r-- | tests/f2s_test.rs | 8 | ||||
-rw-r--r-- | tests/s2d_test.rs | 37 | ||||
-rw-r--r-- | tests/s2f_test.rs | 33 |
27 files changed, 338 insertions, 454 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index af83192..5e45238 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,5 @@ { "git": { - "sha1": "fad77e77469c6e1ce51abc9d9d111668b3b65941" - }, - "path_in_vcs": "" -}
\ No newline at end of file + "sha1": "9edbbd939fa80fb364d0a1ae65ff05efbc2ac894" + } +} diff --git a/.clippy.toml b/.clippy.toml deleted file mode 100644 index 0a54853..0000000 --- a/.clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.36.0" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51809c3..ea91ef1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,16 +19,15 @@ jobs: with: toolchain: ${{matrix.rust}} - run: cargo test - - run: cargo test --features small - run: cargo build --tests --features no-panic --release if: matrix.rust == 'nightly' msrv: - name: Rust 1.36.0 + name: Rust 1.31.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@1.36.0 + - uses: dtolnay/rust-toolchain@1.31.0 - run: cargo build - run: cargo build --features small @@ -40,24 +39,5 @@ jobs: - uses: dtolnay/rust-toolchain@nightly with: components: miri + - run: cargo miri setup - run: cargo miri test - env: - MIRIFLAGS: "-Zmiri-tag-raw-pointers" - - clippy: - name: Clippy - runs-on: ubuntu-latest - if: github.event_name != 'pull_request' - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@clippy - - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic - - outdated: - name: Outdated - runs-on: ubuntu-latest - if: github.event_name != 'pull_request' - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/install@cargo-outdated - - run: cargo outdated --exit-code 1 @@ -43,88 +43,14 @@ rust_library { name: "libryu", host_supported: true, crate_name: "ryu", - cargo_env_compat: true, - cargo_pkg_version: "1.0.9", srcs: ["src/lib.rs"], edition: "2018", + cfgs: [ + "integer128", + "maybe_uninit", + ], apex_available: [ "//apex_available:platform", "com.android.virt", ], } - -rust_defaults { - name: "ryu_test_defaults", - crate_name: "ryu", - cargo_env_compat: true, - cargo_pkg_version: "1.0.9", - test_suites: ["general-tests"], - auto_gen_config: true, - edition: "2018", - rustlibs: [ - "libnum_cpus", - "librand", - "librand_xorshift", - "libryu", - ], -} - -rust_test { - name: "ryu_test_tests_common_test", - defaults: ["ryu_test_defaults"], - host_supported: true, - srcs: ["tests/common_test.rs"], - test_options: { - unit_test: true, - }, -} - -rust_test { - name: "ryu_test_tests_d2s_table_test", - defaults: ["ryu_test_defaults"], - host_supported: true, - srcs: ["tests/d2s_table_test.rs"], - test_options: { - unit_test: true, - }, -} - -rust_test { - name: "ryu_test_tests_d2s_test", - defaults: ["ryu_test_defaults"], - host_supported: true, - srcs: ["tests/d2s_test.rs"], - test_options: { - unit_test: true, - }, -} - -rust_test { - name: "ryu_test_tests_f2s_test", - defaults: ["ryu_test_defaults"], - host_supported: true, - srcs: ["tests/f2s_test.rs"], - test_options: { - unit_test: true, - }, -} - -rust_test { - name: "ryu_test_tests_s2d_test", - defaults: ["ryu_test_defaults"], - host_supported: true, - srcs: ["tests/s2d_test.rs"], - test_options: { - unit_test: true, - }, -} - -rust_test { - name: "ryu_test_tests_s2f_test", - defaults: ["ryu_test_defaults"], - host_supported: true, - srcs: ["tests/s2f_test.rs"], - test_options: { - unit_test: true, - }, -} @@ -3,23 +3,21 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. +# to registry (e.g., crates.io) dependencies # -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) [package] edition = "2018" -rust-version = "1.36" name = "ryu" -version = "1.0.9" +version = "1.0.5" authors = ["David Tolnay <dtolnay@gmail.com>"] -exclude = ["performance.png", "chart/**"] description = "Fast floating point to string conversion" documentation = "https://docs.rs/ryu" readme = "README.md" -categories = ["value-formatting"] license = "Apache-2.0 OR BSL-1.0" repository = "https://github.com/dtolnay/ryu" [package.metadata.docs.rs] @@ -31,10 +29,10 @@ optional = true version = "1.8" [dev-dependencies.rand] -version = "0.8" +version = "0.7" [dev-dependencies.rand_xorshift] -version = "0.3" +version = "0.2" [features] small = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index af29dff..ad0ba2c 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,16 +1,13 @@ [package] name = "ryu" -version = "1.0.9" # don't forget to update html_root_url +version = "1.0.5" # don't forget to update html_root_url authors = ["David Tolnay <dtolnay@gmail.com>"] license = "Apache-2.0 OR BSL-1.0" description = "Fast floating point to string conversion" repository = "https://github.com/dtolnay/ryu" documentation = "https://docs.rs/ryu" -categories = ["value-formatting"] readme = "README.md" -exclude = ["performance.png", "chart/**"] edition = "2018" -rust-version = "1.36" [features] # Use smaller lookup tables. Instead of storing every required power of @@ -24,8 +21,8 @@ no-panic = { version = "0.1", optional = true } [dev-dependencies] num_cpus = "1.8" -rand = "0.8" -rand_xorshift = "0.3" +rand = "0.7" +rand_xorshift = "0.2" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/ryu/ryu-1.0.9.crate" + value: "https://static.crates.io/crates/ryu/ryu-1.0.5.crate" } - version: "1.0.9" + version: "1.0.5" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 3 - day: 1 + year: 2020 + month: 8 + day: 21 } } @@ -15,19 +15,17 @@ under the creative commons CC-BY-SA license. This Rust implementation is a line-by-line port of Ulf Adams' implementation in C, [https://github.com/ulfjack/ryu][upstream]. -*Requirements: this crate supports any compiler version back to rustc 1.36; it +*Requirements: this crate supports any compiler version back to rustc 1.31; it uses nothing from the Rust standard library so is usable from no_std crates.* [paper]: https://dl.acm.org/citation.cfm?id=3192369 -[upstream]: https://github.com/ulfjack/ryu/tree/abf76d252bc97300354857e64e80d4a2bf664291 +[upstream]: https://github.com/ulfjack/ryu/tree/1c413e127f8d02afd12eb6259bc80163722f1385 ```toml [dependencies] ryu = "1.0" ``` -<br> - ## Example ```rust @@ -38,18 +36,14 @@ fn main() { } ``` -<br> - -## Performance (lower is better) - -![performance](https://raw.githubusercontent.com/dtolnay/ryu/master/performance.png) +## Performance You can run upstream's benchmarks with: ```console $ git clone https://github.com/ulfjack/ryu c-ryu $ cd c-ryu -$ bazel run -c opt //ryu/benchmark:ryu_benchmark +$ bazel run -c opt //ryu/benchmark ``` And the same benchmark against our implementation with: @@ -75,10 +69,20 @@ standard library which you can run with: $ cargo bench ``` -The benchmark shows Ryū approximately 2-5x faster than the standard library +The benchmark shows Ryū approximately 4-10x faster than the standard library across a range of f32 and f64 inputs. Measurements are in nanoseconds per iteration; smaller is better. +| type=f32 | 0.0 | 0.1234 | 2.718281828459045 | f32::MAX | +|:--------:|:----:|:------:|:-----------------:|:--------:| +| RYU | 3ns | 28ns | 23ns | 22ns | +| STD | 40ns | 106ns | 128ns | 110ns | + +| type=f64 | 0.0 | 0.1234 | 2.718281828459045 | f64::MAX | +|:--------:|:----:|:------:|:-----------------:|:--------:| +| RYU | 3ns | 50ns | 35ns | 32ns | +| STD | 39ns | 105ns | 128ns | 202ns | + ## Formatting This library tends to produce more human-readable output than the standard diff --git a/TEST_MAPPING b/TEST_MAPPING deleted file mode 100644 index 701f911..0000000 --- a/TEST_MAPPING +++ /dev/null @@ -1,93 +0,0 @@ -// Generated by update_crate_tests.py for tests that depend on this crate. -{ - "imports": [ - { - "path": "external/rust/crates/base64" - }, - { - "path": "external/rust/crates/bitflags" - }, - { - "path": "external/rust/crates/either" - }, - { - "path": "external/rust/crates/rand_chacha" - }, - { - "path": "external/rust/crates/tinytemplate" - }, - { - "path": "external/rust/crates/tinyvec" - }, - { - "path": "external/rust/crates/unicode-xid" - }, - { - "path": "external/rust/crates/url" - } - ], - "presubmit": [ - { - "name": "ZipFuseTest" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "microdroid_manager_test" - }, - { - "name": "ryu_test_tests_common_test" - }, - { - "name": "ryu_test_tests_d2s_table_test" - }, - { - "name": "ryu_test_tests_d2s_test" - }, - { - "name": "ryu_test_tests_f2s_test" - }, - { - "name": "ryu_test_tests_s2d_test" - }, - { - "name": "ryu_test_tests_s2f_test" - }, - { - "name": "virtualizationservice_device_test" - } - ], - "presubmit-rust": [ - { - "name": "ZipFuseTest" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "microdroid_manager_test" - }, - { - "name": "ryu_test_tests_common_test" - }, - { - "name": "ryu_test_tests_d2s_table_test" - }, - { - "name": "ryu_test_tests_d2s_test" - }, - { - "name": "ryu_test_tests_f2s_test" - }, - { - "name": "ryu_test_tests_s2d_test" - }, - { - "name": "ryu_test_tests_s2f_test" - }, - { - "name": "virtualizationservice_device_test" - } - ] -} diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..f48477a --- /dev/null +++ b/build.rs @@ -0,0 +1,40 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // 128-bit integers disabled on Emscripten targets as Emscripten doesn't + // currently support integers larger than 64 bits. + if !emscripten { + println!("cargo:rustc-cfg=integer128"); + } + + // MaybeUninit<T> stabilized in Rust 1.36: + // https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html + if minor >= 36 { + println!("cargo:rustc-cfg=maybe_uninit"); + } +} + +fn rustc_minor_version() -> Option<u32> { + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + let next = pieces.next()?; + u32::from_str(next).ok() +} diff --git a/cargo2android.json b/cargo2android.json index ac56e26..42b7833 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -5,6 +5,5 @@ ], "dependencies": true, "device": true, - "run": true, - "tests": true + "run": true }
\ No newline at end of file diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 2ccd9b0..df21fe0 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -1,12 +1,13 @@ use crate::raw; +#[cfg(maybe_uninit)] use core::mem::MaybeUninit; -use core::{slice, str}; +use core::{mem, slice, str}; #[cfg(feature = "no-panic")] use no_panic::no_panic; -const NAN: &str = "NaN"; -const INFINITY: &str = "inf"; -const NEG_INFINITY: &str = "-inf"; +const NAN: &'static str = "NaN"; +const INFINITY: &'static str = "inf"; +const NEG_INFINITY: &'static str = "-inf"; /// Safe API for formatting floating point numbers to text. /// @@ -18,7 +19,10 @@ const NEG_INFINITY: &str = "-inf"; /// assert_eq!(printed, "1.234"); /// ``` pub struct Buffer { + #[cfg(maybe_uninit)] bytes: [MaybeUninit<u8>; 24], + #[cfg(not(maybe_uninit))] + bytes: [u8; 24], } impl Buffer { @@ -27,8 +31,14 @@ impl Buffer { #[inline] #[cfg_attr(feature = "no-panic", no_panic)] pub fn new() -> Self { + // assume_init is safe here, since this is an array of MaybeUninit, which does not need + // to be initialized. + #[cfg(maybe_uninit)] let bytes = [MaybeUninit::<u8>::uninit(); 24]; - Buffer { bytes } + #[cfg(not(maybe_uninit))] + let bytes = unsafe { mem::uninitialized() }; + + Buffer { bytes: bytes } } /// Print a floating point number into this buffer and return a reference to @@ -115,7 +125,7 @@ impl Sealed for f32 { #[inline] fn is_nonfinite(self) -> bool { const EXP_MASK: u32 = 0x7f800000; - let bits = self.to_bits(); + let bits = unsafe { mem::transmute::<f32, u32>(self) }; bits & EXP_MASK == EXP_MASK } @@ -124,7 +134,7 @@ impl Sealed for f32 { fn format_nonfinite(self) -> &'static str { const MANTISSA_MASK: u32 = 0x007fffff; const SIGN_MASK: u32 = 0x80000000; - let bits = self.to_bits(); + let bits = unsafe { mem::transmute::<f32, u32>(self) }; if bits & MANTISSA_MASK != 0 { NAN } else if bits & SIGN_MASK != 0 { @@ -144,7 +154,7 @@ impl Sealed for f64 { #[inline] fn is_nonfinite(self) -> bool { const EXP_MASK: u64 = 0x7ff0000000000000; - let bits = self.to_bits(); + let bits = unsafe { mem::transmute::<f64, u64>(self) }; bits & EXP_MASK == EXP_MASK } @@ -153,7 +163,7 @@ impl Sealed for f64 { fn format_nonfinite(self) -> &'static str { const MANTISSA_MASK: u64 = 0x000fffffffffffff; const SIGN_MASK: u64 = 0x8000000000000000; - let bits = self.to_bits(); + let bits = unsafe { mem::transmute::<f64, u64>(self) }; if bits & MANTISSA_MASK != 0 { NAN } else if bits & SIGN_MASK != 0 { @@ -24,6 +24,9 @@ pub use crate::d2s_full_table::*; use crate::d2s_intrinsics::*; #[cfg(feature = "small")] pub use crate::d2s_small_table::*; +#[cfg(not(maybe_uninit))] +use core::mem; +#[cfg(maybe_uninit)] use core::mem::MaybeUninit; pub const DOUBLE_MANTISSA_BITS: u32 = 52; @@ -114,7 +117,14 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { let mut vr: u64; let mut vp: u64; let mut vm: u64; + #[cfg(not(maybe_uninit))] + { + vp = unsafe { mem::uninitialized() }; + vm = unsafe { mem::uninitialized() }; + } + #[cfg(maybe_uninit)] let mut vp_uninit: MaybeUninit<u64> = MaybeUninit::uninit(); + #[cfg(maybe_uninit)] let mut vm_uninit: MaybeUninit<u64> = MaybeUninit::uninit(); let e10: i32; let mut vm_is_trailing_zeros = false; @@ -137,13 +147,30 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize) }, i as u32, - vp_uninit.as_mut_ptr(), - vm_uninit.as_mut_ptr(), + #[cfg(maybe_uninit)] + { + vp_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vp + }, + #[cfg(maybe_uninit)] + { + vm_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vm + }, mm_shift, ) }; - vp = unsafe { vp_uninit.assume_init() }; - vm = unsafe { vm_uninit.assume_init() }; + #[cfg(maybe_uninit)] + { + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; + } if q <= 21 { // This should use q <= 22, but I think 21 is also safe. Smaller values // may still be safe, but it's more difficult to reason about them. @@ -179,13 +206,30 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { DOUBLE_POW5_SPLIT.get_unchecked(i as usize) }, j as u32, - vp_uninit.as_mut_ptr(), - vm_uninit.as_mut_ptr(), + #[cfg(maybe_uninit)] + { + vp_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vp + }, + #[cfg(maybe_uninit)] + { + vm_uninit.as_mut_ptr() + }, + #[cfg(not(maybe_uninit))] + { + &mut vm + }, mm_shift, ) }; - vp = unsafe { vp_uninit.assume_init() }; - vm = unsafe { vm_uninit.assume_init() }; + #[cfg(maybe_uninit)] + { + vp = unsafe { vp_uninit.assume_init() }; + vm = unsafe { vm_uninit.assume_init() }; + } if q <= 1 { // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. // mv = 4 * m2, so it always has at least two trailing 0 bits. diff --git a/src/d2s_intrinsics.rs b/src/d2s_intrinsics.rs index f244a4d..918ccab 100644 --- a/src/d2s_intrinsics.rs +++ b/src/d2s_intrinsics.rs @@ -20,6 +20,46 @@ use core::ptr; +// Returns (lo, hi). +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub fn umul128(a: u64, b: u64) -> (u64, u64) { + let a_lo = a as u32; + let a_hi = (a >> 32) as u32; + let b_lo = b as u32; + let b_hi = (b >> 32) as u32; + + let b00 = a_lo as u64 * b_lo as u64; + let b01 = a_lo as u64 * b_hi as u64; + let b10 = a_hi as u64 * b_lo as u64; + let b11 = a_hi as u64 * b_hi as u64; + + let b00_lo = b00 as u32; + let b00_hi = (b00 >> 32) as u32; + + let mid1 = b10 + b00_hi as u64; + let mid1_lo = mid1 as u32; + let mid1_hi = (mid1 >> 32) as u32; + + let mid2 = b01 + mid1_lo as u64; + let mid2_lo = mid2 as u32; + let mid2_hi = (mid2 >> 32) as u32; + + let p_hi = b11 + mid1_hi as u64 + mid2_hi as u64; + let p_lo = ((mid2_lo as u64) << 32) | b00_lo as u64; + + (p_lo, p_hi) +} + +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 { + // We don't need to handle the case dist >= 64 here (see above). + debug_assert!(dist > 0); + debug_assert!(dist < 64); + (hi << (64 - dist)) | (lo >> dist) +} + #[cfg_attr(feature = "no-panic", inline)] pub fn div5(x: u64) -> u64 { x / 5 @@ -67,6 +107,7 @@ pub fn multiple_of_power_of_2(value: u64, p: u32) -> bool { (value & ((1u64 << p) - 1)) == 0 } +#[cfg(integer128)] #[cfg_attr(feature = "no-panic", inline)] pub fn mul_shift_64(m: u64, mul: &(u64, u64), j: u32) -> u64 { let b0 = m as u128 * mul.0 as u128; @@ -74,6 +115,7 @@ pub fn mul_shift_64(m: u64, mul: &(u64, u64), j: u32) -> u64 { (((b0 >> 64) + b2) >> (j - 64)) as u64 } +#[cfg(integer128)] #[cfg_attr(feature = "no-panic", inline)] pub unsafe fn mul_shift_all_64( m: u64, @@ -87,3 +129,43 @@ pub unsafe fn mul_shift_all_64( ptr::write(vm, mul_shift_64(4 * m - 1 - mm_shift as u64, mul, j)); mul_shift_64(4 * m, mul, j) } + +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn mul_shift_all_64( + mut m: u64, + mul: &(u64, u64), + j: u32, + vp: *mut u64, + vm: *mut u64, + mm_shift: u32, +) -> u64 { + m <<= 1; + // m is maximum 55 bits + let (lo, tmp) = umul128(m, mul.0); + let (mut mid, mut hi) = umul128(m, mul.1); + mid = mid.wrapping_add(tmp); + hi = hi.wrapping_add((mid < tmp) as u64); // overflow into hi + + let lo2 = lo.wrapping_add(mul.0); + let mid2 = mid.wrapping_add(mul.1).wrapping_add((lo2 < lo) as u64); + let hi2 = hi.wrapping_add((mid2 < mid) as u64); + ptr::write(vp, shiftright128(mid2, hi2, j - 64 - 1)); + + if mm_shift == 1 { + let lo3 = lo.wrapping_sub(mul.0); + let mid3 = mid.wrapping_sub(mul.1).wrapping_sub((lo3 > lo) as u64); + let hi3 = hi.wrapping_sub((mid3 > mid) as u64); + ptr::write(vm, shiftright128(mid3, hi3, j - 64 - 1)); + } else { + let lo3 = lo + lo; + let mid3 = mid.wrapping_add(mid).wrapping_add((lo3 < lo) as u64); + let hi3 = hi.wrapping_add(hi).wrapping_add((mid3 < mid) as u64); + let lo4 = lo3.wrapping_sub(mul.0); + let mid4 = mid3.wrapping_sub(mul.1).wrapping_sub((lo4 > lo3) as u64); + let hi4 = hi3.wrapping_sub((mid4 > mid3) as u64); + ptr::write(vm, shiftright128(mid4, hi4, j - 64)); + } + + shiftright128(mid, hi, j - 64 - 1) +} diff --git a/src/d2s_small_table.rs b/src/d2s_small_table.rs index 262fc04..08519a2 100644 --- a/src/d2s_small_table.rs +++ b/src/d2s_small_table.rs @@ -19,8 +19,10 @@ // KIND, either express or implied. use crate::common::*; +#[cfg(not(integer128))] +use crate::d2s_intrinsics::*; -pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 15] = [ +pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 13] = [ (1, 2305843009213693952), (5955668970331000884, 1784059615882449851), (8982663654677661702, 1380349269358112757), @@ -34,8 +36,6 @@ pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 15] = [ (12533209867169019542, 1418129833677084982), (5577825024675947042, 2194449627517475473), (11006974540203867551, 1697873161311732311), - (10313493231639821582, 1313665730009899186), - (12701016819766672773, 2032799256770390445), ]; pub static POW5_INV_OFFSETS: [u32; 19] = [ @@ -96,6 +96,7 @@ pub static DOUBLE_POW5_TABLE: [u64; 26] = [ ]; // Computes 5^i in the form required by Ryū. +#[cfg(integer128)] #[cfg_attr(feature = "no-panic", inline)] pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { let base = i / DOUBLE_POW5_TABLE.len() as u32; @@ -111,7 +112,7 @@ pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { let b0 = m as u128 * mul.0 as u128; let b2 = m as u128 * mul.1 as u128; let delta = pow5bits(i as i32) - pow5bits(base2 as i32); - debug_assert!(i / 16 < POW5_OFFSETS.len() as u32); + debug_assert!(base < POW5_OFFSETS.len() as u32); let shifted_sum = (b0 >> delta) + (b2 << (64 - delta)) + ((*POW5_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u128; @@ -119,6 +120,7 @@ pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { } // Computes 5^-i in the form required by Ryū. +#[cfg(integer128)] #[cfg_attr(feature = "no-panic", inline)] pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32; @@ -140,3 +142,64 @@ pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { + ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u128; (shifted_sum as u64, (shifted_sum >> 64) as u64) } + +// Computes 5^i in the form required by Ryū, and stores it in the given pointer. +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { + let base = i / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = i - base2; + debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize); + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let (low1, mut high1) = umul128(m, mul.1); + let (low0, high0) = umul128(m, mul.0); + let sum = high0 + low1; + if sum < high0 { + high1 += 1; // overflow into high1 + } + // high1 | sum | low0 + let delta = pow5bits(i as i32) - pow5bits(base2 as i32); + debug_assert!(base < POW5_OFFSETS.len() as u32); + ( + shiftright128(low0, sum, delta as u32) + + ((*POW5_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u64, + shiftright128(sum, high1, delta as u32), + ) +} + +// Computes 5^-i in the form required by Ryū, and stores it in the given pointer. +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { + let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = base2 - i; + debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2 + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let (low1, mut high1) = umul128(m, mul.1); + let (low0, high0) = umul128(m, mul.0 - 1); + let sum = high0 + low1; + if sum < high0 { + high1 += 1; // overflow into high1 + } + // high1 | sum | low0 + let delta = pow5bits(base2 as i32) - pow5bits(i as i32); + debug_assert!(base < POW5_INV_OFFSETS.len() as u32); + ( + shiftright128(low0, sum, delta as u32) + + 1 + + ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u64, + shiftright128(sum, high1, delta as u32), + ) +} @@ -29,9 +29,7 @@ //! } //! ``` //! -//! ## Performance (lower is better) -//! -//! ![performance](https://raw.githubusercontent.com/dtolnay/ryu/master/performance.png) +//! ## Performance //! //! You can run upstream's benchmarks with: //! @@ -64,10 +62,20 @@ //! $ cargo bench //! ``` //! -//! The benchmark shows Ryū approximately 2-5x faster than the standard library +//! The benchmark shows Ryū approximately 4-10x faster than the standard library //! across a range of f32 and f64 inputs. Measurements are in nanoseconds per //! iteration; smaller is better. //! +//! | type=f32 | 0.0 | 0.1234 | 2.718281828459045 | f32::MAX | +//! |:--------:|:----:|:------:|:-----------------:|:--------:| +//! | RYU | 3ns | 28ns | 23ns | 22ns | +//! | STD | 40ns | 106ns | 128ns | 110ns | +//! +//! | type=f64 | 0.0 | 0.1234 | 2.718281828459045 | f64::MAX | +//! |:--------:|:----:|:------:|:-----------------:|:--------:| +//! | RYU | 3ns | 50ns | 35ns | 32ns | +//! | STD | 39ns | 105ns | 128ns | 202ns | +//! //! ## Formatting //! //! This library tends to produce more human-readable output than the standard @@ -81,25 +89,11 @@ //! notation. #![no_std] -#![doc(html_root_url = "https://docs.rs/ryu/1.0.9")] -#![allow( - clippy::cast_lossless, - clippy::cast_possible_truncation, - clippy::cast_possible_wrap, - clippy::cast_sign_loss, - clippy::checked_conversions, - clippy::doc_markdown, - clippy::expl_impl_clone_on_copy, - clippy::if_not_else, - clippy::many_single_char_names, - clippy::missing_panics_doc, - clippy::module_name_repetitions, - clippy::must_use_candidate, - clippy::similar_names, - clippy::too_many_lines, - clippy::unreadable_literal, - clippy::unseparated_literal_suffix, - clippy::wildcard_imports +#![doc(html_root_url = "https://docs.rs/ryu/1.0.5")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr( + feature = "cargo-clippy", + allow(cast_lossless, many_single_char_names, unreadable_literal,) )] mod buffer; diff --git a/src/pretty/exponent.rs b/src/pretty/exponent.rs index b72add5..84053d5 100644 --- a/src/pretty/exponent.rs +++ b/src/pretty/exponent.rs @@ -14,11 +14,11 @@ pub unsafe fn write_exponent3(mut k: isize, mut result: *mut u8) -> usize { if k >= 100 { *result = b'0' + (k / 100) as u8; k %= 100; - let d = DIGIT_TABLE.as_ptr().offset(k * 2); + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); ptr::copy_nonoverlapping(d, result.offset(1), 2); sign as usize + 3 } else if k >= 10 { - let d = DIGIT_TABLE.as_ptr().offset(k * 2); + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); ptr::copy_nonoverlapping(d, result, 2); sign as usize + 2 } else { @@ -38,7 +38,7 @@ pub unsafe fn write_exponent2(mut k: isize, mut result: *mut u8) -> usize { debug_assert!(k < 100); if k >= 10 { - let d = DIGIT_TABLE.as_ptr().offset(k * 2); + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); ptr::copy_nonoverlapping(d, result, 2); sign as usize + 2 } else { diff --git a/src/pretty/mantissa.rs b/src/pretty/mantissa.rs index 150c79c..e5fc202 100644 --- a/src/pretty/mantissa.rs +++ b/src/pretty/mantissa.rs @@ -15,26 +15,10 @@ pub unsafe fn write_mantissa_long(mut output: u64, mut result: *mut u8) { let c1 = (c / 100) << 1; let d0 = (d % 100) << 1; let d1 = (d / 100) << 1; - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(c0 as isize), - result.offset(-2), - 2, - ); - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(c1 as isize), - result.offset(-4), - 2, - ); - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(d0 as isize), - result.offset(-6), - 2, - ); - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(d1 as isize), - result.offset(-8), - 2, - ); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d0 as usize), result.offset(-6), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d1 as usize), result.offset(-8), 2); result = result.offset(-8); } write_mantissa(output as u32, result); @@ -47,35 +31,19 @@ pub unsafe fn write_mantissa(mut output: u32, mut result: *mut u8) { output /= 10_000; let c0 = (c % 100) << 1; let c1 = (c / 100) << 1; - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(c0 as isize), - result.offset(-2), - 2, - ); - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(c1 as isize), - result.offset(-4), - 2, - ); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2); result = result.offset(-4); } if output >= 100 { let c = ((output % 100) << 1) as u32; output /= 100; - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(c as isize), - result.offset(-2), - 2, - ); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2); result = result.offset(-2); } if output >= 10 { let c = (output << 1) as u32; - ptr::copy_nonoverlapping( - DIGIT_TABLE.as_ptr().offset(c as isize), - result.offset(-2), - 2, - ); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2); } else { *result.offset(-1) = b'0' + output as u8; } diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index b196a11..a82692d 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -6,7 +6,7 @@ use self::mantissa::*; use crate::common; use crate::d2s::{self, *}; use crate::f2s::*; -use core::ptr; +use core::{mem, ptr}; #[cfg(feature = "no-panic")] use no_panic::no_panic; @@ -50,7 +50,7 @@ use no_panic::no_panic; #[must_use] #[cfg_attr(feature = "no-panic", no_panic)] pub unsafe fn format64(f: f64, result: *mut u8) -> usize { - let bits = f.to_bits(); + let bits = mem::transmute::<f64, u64>(f); let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0; let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1); let ieee_exponent = @@ -157,7 +157,7 @@ pub unsafe fn format64(f: f64, result: *mut u8) -> usize { #[must_use] #[cfg_attr(feature = "no-panic", no_panic)] pub unsafe fn format32(f: f32, result: *mut u8) -> usize { - let bits = f.to_bits(); + let bits = mem::transmute::<f32, u32>(f); let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0; let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1); let ieee_exponent = @@ -203,13 +203,12 @@ pub fn s2d(buffer: &[u8]) -> Result<f64, Error> { let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0); let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u64); - debug_assert!(ieee_m2 <= 1_u64 << (d2s::DOUBLE_MANTISSA_BITS + 1)); - ieee_m2 &= (1_u64 << d2s::DOUBLE_MANTISSA_BITS) - 1; - if ieee_m2 == 0 && round_up { + if ieee_m2 == (1_u64 << (d2s::DOUBLE_MANTISSA_BITS + 1)) { // Due to how the IEEE represents +/-Infinity, we don't need to check // for overflow here. ieee_e2 += 1; } + ieee_m2 &= (1_u64 << d2s::DOUBLE_MANTISSA_BITS) - 1; let ieee = ((((signed_m as u64) << d2s::DOUBLE_EXPONENT_BITS) | ieee_e2 as u64) << d2s::DOUBLE_MANTISSA_BITS) | ieee_m2; @@ -153,29 +153,13 @@ pub fn s2f(buffer: &[u8]) -> Result<f32, Error> { .wrapping_add(e10 as u32) .wrapping_sub(ceil_log2_pow5(-e10) as u32) .wrapping_sub(f2s::FLOAT_MANTISSA_BITS + 1) as i32; - - // We now compute [m10 * 10^e10 / 2^e2] = [m10 / (5^(-e10) 2^(e2-e10))]. let j = e2 .wrapping_sub(e10) .wrapping_add(ceil_log2_pow5(-e10)) .wrapping_sub(1) .wrapping_add(f2s::FLOAT_POW5_INV_BITCOUNT); m2 = mul_pow5_inv_div_pow2(m10, -e10 as u32, j); - - // We also compute if the result is exact, i.e., - // [m10 / (5^(-e10) 2^(e2-e10))] == m10 / (5^(-e10) 2^(e2-e10)) - // - // If e2-e10 >= 0, we need to check whether (5^(-e10) 2^(e2-e10)) - // divides m10, which is the case iff pow5(m10) >= -e10 AND pow2(m10) >= - // e2-e10. - // - // If e2-e10 < 0, we have actually computed [m10 * 2^(e10 e2) / - // 5^(-e10)] above, and we need to check whether 5^(-e10) divides (m10 * - // 2^(e10-e2)), which is the case iff pow5(m10 * 2^(e10-e2)) = pow5(m10) - // >= -e10. - trailing_zeros = (e2 < e10 - || (e2 - e10 < 32 && multiple_of_power_of_2_32(m10, (e2 - e10) as u32))) - && multiple_of_power_of_5_32(m10, -e10 as u32); + trailing_zeros = multiple_of_power_of_5_32(m10, -e10 as u32); } // Compute the final IEEE exponent. @@ -210,16 +194,12 @@ pub fn s2f(buffer: &[u8]) -> Result<f32, Error> { let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0); let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u32); - debug_assert!(ieee_m2 <= 1_u32 << (f2s::FLOAT_MANTISSA_BITS + 1)); - ieee_m2 &= (1_u32 << f2s::FLOAT_MANTISSA_BITS) - 1; - if ieee_m2 == 0 && round_up { - // Rounding up may overflow the mantissa. - // In this case we move a trailing zero of the mantissa into the - // exponent. + if ieee_m2 == (1_u32 << (f2s::FLOAT_MANTISSA_BITS + 1)) { // Due to how the IEEE represents +/-Infinity, we don't need to check // for overflow here. ieee_e2 += 1; } + ieee_m2 &= (1_u32 << f2s::FLOAT_MANTISSA_BITS) - 1; let ieee = ((((signed_m as u32) << f2s::FLOAT_EXPONENT_BITS) | ieee_e2 as u32) << f2s::FLOAT_MANTISSA_BITS) | ieee_m2; diff --git a/tests/common_test.rs b/tests/common_test.rs index 2f05b33..a6010e9 100644 --- a/tests/common_test.rs +++ b/tests/common_test.rs @@ -19,14 +19,6 @@ // KIND, either express or implied. #![allow(dead_code)] -#![allow( - clippy::approx_constant, - clippy::cast_possible_wrap, - clippy::cast_sign_loss, - clippy::excessive_precision, - clippy::unreadable_literal, - clippy::wildcard_imports -)] #[path = "../src/common.rs"] mod common; diff --git a/tests/d2s_table_test.rs b/tests/d2s_table_test.rs index dce1be3..aa45c55 100644 --- a/tests/d2s_table_test.rs +++ b/tests/d2s_table_test.rs @@ -19,15 +19,6 @@ // KIND, either express or implied. #![allow(dead_code)] -#![allow( - clippy::cast_lossless, - clippy::cast_possible_truncation, - clippy::cast_possible_wrap, - clippy::cast_sign_loss, - clippy::unreadable_literal, - clippy::unseparated_literal_suffix, - clippy::wildcard_imports -)] #[path = "../src/common.rs"] mod common; diff --git a/tests/d2s_test.rs b/tests/d2s_test.rs index 368cab6..604ab69 100644 --- a/tests/d2s_test.rs +++ b/tests/d2s_test.rs @@ -18,16 +18,6 @@ // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. -#![allow( - clippy::approx_constant, - clippy::cast_lossless, - clippy::float_cmp, - clippy::int_plus_one, - clippy::non_ascii_literal, - clippy::unreadable_literal, - clippy::unseparated_literal_suffix -)] - #[macro_use] mod macros; diff --git a/tests/f2s_test.rs b/tests/f2s_test.rs index 927fa7e..916250e 100644 --- a/tests/f2s_test.rs +++ b/tests/f2s_test.rs @@ -18,14 +18,6 @@ // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. -#![allow( - clippy::approx_constant, - clippy::float_cmp, - clippy::non_ascii_literal, - clippy::unreadable_literal, - clippy::unseparated_literal_suffix -)] - #[macro_use] mod macros; diff --git a/tests/s2d_test.rs b/tests/s2d_test.rs index 7b42164..f51c1ed 100644 --- a/tests/s2d_test.rs +++ b/tests/s2d_test.rs @@ -20,35 +20,16 @@ #![cfg(not(feature = "small"))] #![allow(dead_code)] -#![allow( - clippy::cast_lossless, - clippy::cast_possible_truncation, - clippy::cast_possible_wrap, - clippy::cast_sign_loss, - clippy::excessive_precision, - clippy::float_cmp, - clippy::manual_range_contains, - clippy::similar_names, - clippy::too_many_lines, - clippy::unreadable_literal, - clippy::unseparated_literal_suffix, - clippy::wildcard_imports -)] #[path = "../src/common.rs"] mod common; -#[cfg(not(feature = "small"))] #[path = "../src/d2s_full_table.rs"] mod d2s_full_table; #[path = "../src/d2s_intrinsics.rs"] mod d2s_intrinsics; -#[cfg(feature = "small")] -#[path = "../src/d2s_small_table.rs"] -mod d2s_small_table; - #[path = "../src/d2s.rs"] mod d2s; @@ -96,7 +77,6 @@ fn test_basic() { assert_eq!(1.0, s2d(b"1e0").unwrap()); assert_eq!(1.0, s2d(b"1E0").unwrap()); assert_eq!(1.0, s2d(b"000001.000000").unwrap()); - assert_eq!(0.2316419, s2d(b"0.2316419").unwrap()); } #[test] @@ -148,20 +128,3 @@ fn test_issue157() { s2d(b"1.2999999999999999E+154").unwrap(), ); } - -#[test] -fn test_issue173() { - // Denormal boundary - assert_eq!( - 2.2250738585072012e-308, - s2d(b"2.2250738585072012e-308").unwrap(), - ); - assert_eq!( - 2.2250738585072013e-308, - s2d(b"2.2250738585072013e-308").unwrap(), - ); - assert_eq!( - 2.2250738585072014e-308, - s2d(b"2.2250738585072014e-308").unwrap(), - ); -} diff --git a/tests/s2f_test.rs b/tests/s2f_test.rs index 5bae935..f49824a 100644 --- a/tests/s2f_test.rs +++ b/tests/s2f_test.rs @@ -19,36 +19,16 @@ // KIND, either express or implied. #![allow(dead_code)] -#![allow( - clippy::cast_lossless, - clippy::cast_possible_truncation, - clippy::cast_possible_wrap, - clippy::cast_possible_wrap, - clippy::cast_sign_loss, - clippy::checked_conversions, - clippy::float_cmp, - clippy::manual_range_contains, - clippy::similar_names, - clippy::too_many_lines, - clippy::unreadable_literal, - clippy::unseparated_literal_suffix, - clippy::wildcard_imports -)] #[path = "../src/common.rs"] mod common; -#[cfg(not(feature = "small"))] #[path = "../src/d2s_full_table.rs"] mod d2s_full_table; #[path = "../src/d2s_intrinsics.rs"] mod d2s_intrinsics; -#[cfg(feature = "small")] -#[path = "../src/d2s_small_table.rs"] -mod d2s_small_table; - #[path = "../src/d2s.rs"] mod d2s; @@ -94,17 +74,4 @@ fn test_min_max() { fn test_mantissa_rounding_overflow() { assert_eq!(1.0, s2f(b"0.999999999").unwrap()); assert_eq!(f32::INFINITY, s2f(b"3.4028236e+38").unwrap()); - assert_eq!(1.1754944e-38, s2f(b"1.17549430e-38").unwrap()); // FLT_MIN - assert_eq!(1.1754944e-38, s2f(b"1.17549431e-38").unwrap()); - assert_eq!(1.1754944e-38, s2f(b"1.17549432e-38").unwrap()); - assert_eq!(1.1754944e-38, s2f(b"1.17549433e-38").unwrap()); - assert_eq!(1.1754944e-38, s2f(b"1.17549434e-38").unwrap()); - assert_eq!(1.1754944e-38, s2f(b"1.17549435e-38").unwrap()); -} - -#[test] -fn test_trailing_zeros() { - assert_eq!(26843550.0, s2f(b"26843549.5").unwrap()); - assert_eq!(50000004.0, s2f(b"50000002.5").unwrap()); - assert_eq!(99999992.0, s2f(b"99999989.5").unwrap()); } |