Upgrade num-traits to 0.2.17

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update rust/crates/num-traits
For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I5da9b7c46bf3cfafd10bfe07ce2f799947d9abb9
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 1ec548f..6e76df7 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "1597c1c4d1b3e33548e4661c519b7246a5fc1c28"
+    "sha1": "0a27d8c95ad4cdf1b04793cc3b19520f2f19c4f4"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index e37cd0f..09b8faf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,9 +42,9 @@
     host_supported: true,
     crate_name: "num_traits",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.15",
+    cargo_pkg_version: "0.2.17",
     srcs: ["src/lib.rs"],
-    edition: "2015",
+    edition: "2018",
     features: [
         "default",
         "std",
@@ -52,8 +52,9 @@
     cfgs: [
         "has_copysign",
         "has_div_euclid",
-        "has_i128",
-        "has_int_assignop_ref",
+        "has_float_to_from_bytes",
+        "has_int_to_from_bytes",
+        "has_is_subnormal",
         "has_leading_trailing_ones",
         "has_reverse_bits",
         "has_to_int_unchecked",
@@ -75,14 +76,14 @@
     host_supported: true,
     crate_name: "num_traits",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.15",
+    cargo_pkg_version: "0.2.17",
     srcs: ["src/lib.rs"],
     test_suites: ["general-tests"],
     auto_gen_config: true,
     test_options: {
         unit_test: true,
     },
-    edition: "2015",
+    edition: "2018",
     features: [
         "default",
         "std",
@@ -90,8 +91,9 @@
     cfgs: [
         "has_copysign",
         "has_div_euclid",
-        "has_i128",
-        "has_int_assignop_ref",
+        "has_float_to_from_bytes",
+        "has_int_to_from_bytes",
+        "has_is_subnormal",
         "has_leading_trailing_ones",
         "has_reverse_bits",
         "has_to_int_unchecked",
@@ -103,14 +105,14 @@
     host_supported: true,
     crate_name: "cast",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.2.15",
+    cargo_pkg_version: "0.2.17",
     srcs: ["tests/cast.rs"],
     test_suites: ["general-tests"],
     auto_gen_config: true,
     test_options: {
         unit_test: true,
     },
-    edition: "2015",
+    edition: "2018",
     features: [
         "default",
         "std",
@@ -118,8 +120,9 @@
     cfgs: [
         "has_copysign",
         "has_div_euclid",
-        "has_i128",
-        "has_int_assignop_ref",
+        "has_float_to_from_bytes",
+        "has_int_to_from_bytes",
+        "has_is_subnormal",
         "has_leading_trailing_ones",
         "has_reverse_bits",
         "has_to_int_unchecked",
diff --git a/Cargo.toml b/Cargo.toml
index b30fca3..ef37eb7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,8 +10,10 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
+edition = "2018"
+rust-version = "1.31"
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.17"
 authors = ["The Rust Project Developers"]
 build = "build.rs"
 exclude = [
@@ -37,6 +39,7 @@
 
 [package.metadata.docs.rs]
 features = ["std"]
+rustdoc-args = ["--generate-link-to-definition"]
 
 [dependencies.libm]
 version = "0.2.0"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 340ac21..f97bc68 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -8,13 +8,16 @@
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-num/num-traits"
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.17"
 readme = "README.md"
 build = "build.rs"
 exclude = ["/bors.toml", "/ci/*", "/.github/*"]
+edition = "2018"
+rust-version = "1.31"
 
 [package.metadata.docs.rs]
 features = ["std"]
+rustdoc-args = ["--generate-link-to-definition"]
 
 [dependencies]
 libm = { version = "0.2.0", optional = true }
@@ -22,6 +25,8 @@
 [features]
 default = ["std"]
 std = []
+
+# vestigial features, now always in effect
 i128 = []
 
 [build-dependencies]
diff --git a/METADATA b/METADATA
index 0740892..0625c82 100644
--- a/METADATA
+++ b/METADATA
@@ -1,6 +1,6 @@
 # This project was upgraded with external_updater.
 # Usage: tools/external_updater/updater.sh update rust/crates/num-traits
-# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
 
 name: "num-traits"
 description: "Numeric traits for generic mathematics"
@@ -11,13 +11,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/num-traits/num-traits-0.2.15.crate"
+    value: "https://static.crates.io/crates/num-traits/num-traits-0.2.17.crate"
   }
-  version: "0.2.15"
+  version: "0.2.17"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
-    month: 12
-    day: 13
+    year: 2023
+    month: 11
+    day: 14
   }
 }
diff --git a/README.md b/README.md
index 3633962..fa2f297 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![crate](https://img.shields.io/crates/v/num-traits.svg)](https://crates.io/crates/num-traits)
 [![documentation](https://docs.rs/num-traits/badge.svg)](https://docs.rs/num-traits)
-[![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
+[![minimum rustc 1.31](https://img.shields.io/badge/rustc-1.31+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
 [![build status](https://github.com/rust-num/num-traits/workflows/master/badge.svg)](https://github.com/rust-num/num-traits/actions)
 
 Numeric traits for generic mathematics in Rust.
@@ -29,23 +29,18 @@
 ```
 
 The `Float` and `Real` traits are only available when either `std` or `libm` is enabled.  
-The `libm` feature is only available with Rust 1.31 and later ([see PR #99](https://github.com/rust-num/num-traits/pull/99)).
 
 The `FloatCore` trait is always available.  `MulAdd` and `MulAddAssign` for `f32`
 and `f64` also require `std` or `libm`, as do implementations of signed and floating-
 point exponents in `Pow`.
 
-Implementations for `i128` and `u128` are only available with Rust 1.26 and
-later.  The build script automatically detects this, but you can make it
-mandatory by enabling the `i128` crate feature.
-
 ## Releases
 
 Release notes are available in [RELEASES.md](RELEASES.md).
 
 ## Compatibility
 
-The `num-traits` crate is tested for rustc 1.8 and greater.
+The `num-traits` crate is tested for rustc 1.31 and greater.
 
 ## License
 
diff --git a/RELEASES.md b/RELEASES.md
index cd33c04..f0c0cf8 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,27 @@
+# Release 0.2.17 (2023-10-07)
+
+- [Fix a doc warning about custom classes with newer rustdoc.][286]
+
+**Contributors**: @robamu
+
+[286]: https://github.com/rust-num/num-traits/pull/286
+
+# Release 0.2.16 (2023-07-20)
+
+- [Upgrade to 2018 edition, **MSRV 1.31**][240]
+- [The new `ToBytes` and `FromBytes` traits][224] convert to and from byte
+  representations of a value, with little, big, and native-endian options.
+- [The new `Float::is_subnormal` method checks for subnormal values][279], with
+  a non-zero magnitude that is less than the normal minimum positive value.
+- Several other improvements to documentation and testing.
+
+**Contributors**: @ctrlcctrlv, @cuviper, @flier, @GuillaumeGomez, @kaidokert,
+@rs017991, @vicsn
+
+[224]: https://github.com/rust-num/num-traits/pull/224
+[240]: https://github.com/rust-num/num-traits/pull/240
+[279]: https://github.com/rust-num/num-traits/pull/279
+
 # Release 0.2.15 (2022-05-02)
 
 - [The new `Euclid` trait calculates Euclidean division][195], where the
diff --git a/build.rs b/build.rs
index c7bf364..bb78328 100644
--- a/build.rs
+++ b/build.rs
@@ -1,16 +1,8 @@
-extern crate autocfg;
-
 use std::env;
 
 fn main() {
     let ac = autocfg::new();
 
-    // If the "i128" feature is explicity requested, don't bother probing for it.
-    // It will still cause a build error if that was set improperly.
-    if env::var_os("CARGO_FEATURE_I128").is_some() || ac.probe_type("i128") {
-        autocfg::emit("has_i128");
-    }
-
     ac.emit_expression_cfg(
         "unsafe { 1f64.to_int_unchecked::<i32>() }",
         "has_to_int_unchecked",
@@ -18,12 +10,15 @@
 
     ac.emit_expression_cfg("1u32.reverse_bits()", "has_reverse_bits");
     ac.emit_expression_cfg("1u32.trailing_ones()", "has_leading_trailing_ones");
-    ac.emit_expression_cfg("{ let mut x = 1; x += &2; }", "has_int_assignop_ref");
     ac.emit_expression_cfg("1u32.div_euclid(1u32)", "has_div_euclid");
 
     if env::var_os("CARGO_FEATURE_STD").is_some() {
         ac.emit_expression_cfg("1f64.copysign(-1f64)", "has_copysign");
     }
+    ac.emit_expression_cfg("1f64.is_subnormal()", "has_is_subnormal");
+
+    ac.emit_expression_cfg("1u32.to_ne_bytes()", "has_int_to_from_bytes");
+    ac.emit_expression_cfg("3.14f64.to_ne_bytes()", "has_float_to_from_bytes");
 
     autocfg::rerun_path("build.rs");
 }
diff --git a/src/bounds.rs b/src/bounds.rs
index 36e1bbd..acc990e 100644
--- a/src/bounds.rs
+++ b/src/bounds.rs
@@ -1,9 +1,7 @@
 use core::num::Wrapping;
 use core::{f32, f64};
-#[cfg(has_i128)]
-use core::{i128, u128};
-use core::{i16, i32, i64, i8, isize};
-use core::{u16, u32, u64, u8, usize};
+use core::{i128, i16, i32, i64, i8, isize};
+use core::{u128, u16, u32, u64, u8, usize};
 
 /// Numbers which have upper and lower bounds
 pub trait Bounded {
@@ -61,7 +59,6 @@
 bounded_impl!(u16, u16::MIN, u16::MAX);
 bounded_impl!(u32, u32::MIN, u32::MAX);
 bounded_impl!(u64, u64::MIN, u64::MAX);
-#[cfg(has_i128)]
 bounded_impl!(u128, u128::MIN, u128::MAX);
 
 bounded_impl!(isize, isize::MIN, isize::MAX);
@@ -69,7 +66,6 @@
 bounded_impl!(i16, i16::MIN, i16::MAX);
 bounded_impl!(i32, i32::MIN, i32::MAX);
 bounded_impl!(i64, i64::MIN, i64::MAX);
-#[cfg(has_i128)]
 bounded_impl!(i128, i128::MIN, i128::MAX);
 
 impl<T: Bounded> Bounded for Wrapping<T> {
@@ -130,7 +126,6 @@
     test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
 }
 
-#[cfg(has_i128)]
 #[test]
 fn wrapping_bounded_i128() {
     macro_rules! test_wrapping_bounded {
diff --git a/src/cast.rs b/src/cast.rs
index d38c338..125e2e3 100644
--- a/src/cast.rs
+++ b/src/cast.rs
@@ -1,10 +1,8 @@
 use core::mem::size_of;
 use core::num::Wrapping;
 use core::{f32, f64};
-#[cfg(has_i128)]
-use core::{i128, u128};
-use core::{i16, i32, i64, i8, isize};
-use core::{u16, u32, u64, u8, usize};
+use core::{i128, i16, i32, i64, i8, isize};
+use core::{u128, u16, u32, u64, u8, usize};
 
 /// A generic trait for converting a value to a number.
 ///
@@ -53,12 +51,9 @@
     /// represented by an `i128` (`i64` under the default implementation), then
     /// `None` is returned.
     ///
-    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
-    ///
     /// The default implementation converts through `to_i64()`. Types implementing
     /// this trait should override this method if they can represent a greater range.
     #[inline]
-    #[cfg(has_i128)]
     fn to_i128(&self) -> Option<i128> {
         self.to_i64().map(From::from)
     }
@@ -99,12 +94,9 @@
     /// represented by a `u128` (`u64` under the default implementation), then
     /// `None` is returned.
     ///
-    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
-    ///
     /// The default implementation converts through `to_u64()`. Types implementing
     /// this trait should override this method if they can represent a greater range.
     #[inline]
-    #[cfg(has_i128)]
     fn to_u128(&self) -> Option<u128> {
         self.to_u64().map(From::from)
     }
@@ -173,7 +165,6 @@
                 fn to_i16 -> i16;
                 fn to_i32 -> i32;
                 fn to_i64 -> i64;
-                #[cfg(has_i128)]
                 fn to_i128 -> i128;
             }
 
@@ -183,7 +174,6 @@
                 fn to_u16 -> u16;
                 fn to_u32 -> u32;
                 fn to_u64 -> u64;
-                #[cfg(has_i128)]
                 fn to_u128 -> u128;
             }
 
@@ -204,7 +194,6 @@
 impl_to_primitive_int!(i16);
 impl_to_primitive_int!(i32);
 impl_to_primitive_int!(i64);
-#[cfg(has_i128)]
 impl_to_primitive_int!(i128);
 
 macro_rules! impl_to_primitive_uint_to_int {
@@ -246,7 +235,6 @@
                 fn to_i16 -> i16;
                 fn to_i32 -> i32;
                 fn to_i64 -> i64;
-                #[cfg(has_i128)]
                 fn to_i128 -> i128;
             }
 
@@ -256,7 +244,6 @@
                 fn to_u16 -> u16;
                 fn to_u32 -> u32;
                 fn to_u64 -> u64;
-                #[cfg(has_i128)]
                 fn to_u128 -> u128;
             }
 
@@ -277,7 +264,6 @@
 impl_to_primitive_uint!(u16);
 impl_to_primitive_uint!(u32);
 impl_to_primitive_uint!(u64);
-#[cfg(has_i128)]
 impl_to_primitive_uint!(u128);
 
 macro_rules! impl_to_primitive_float_to_float {
@@ -373,7 +359,6 @@
                 fn to_i16 -> i16;
                 fn to_i32 -> i32;
                 fn to_i64 -> i64;
-                #[cfg(has_i128)]
                 fn to_i128 -> i128;
             }
 
@@ -383,7 +368,6 @@
                 fn to_u16 -> u16;
                 fn to_u32 -> u32;
                 fn to_u64 -> u64;
-                #[cfg(has_i128)]
                 fn to_u128 -> u128;
             }
 
@@ -444,12 +428,9 @@
     /// Converts an `i128` to return an optional value of this type. If the
     /// value cannot be represented by this type, then `None` is returned.
     ///
-    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
-    ///
     /// The default implementation converts through `from_i64()`. Types implementing
     /// this trait should override this method if they can represent a greater range.
     #[inline]
-    #[cfg(has_i128)]
     fn from_i128(n: i128) -> Option<Self> {
         n.to_i64().and_then(FromPrimitive::from_i64)
     }
@@ -489,12 +470,9 @@
     /// Converts an `u128` to return an optional value of this type. If the
     /// value cannot be represented by this type, then `None` is returned.
     ///
-    /// This method is only available with feature `i128` enabled on Rust >= 1.26.
-    ///
     /// The default implementation converts through `from_u64()`. Types implementing
     /// this trait should override this method if they can represent a greater range.
     #[inline]
-    #[cfg(has_i128)]
     fn from_u128(n: u128) -> Option<Self> {
         n.to_u64().and_then(FromPrimitive::from_u64)
     }
@@ -545,7 +523,6 @@
             fn from_i64(n: i64) -> Option<$T> {
                 n.$to_ty()
             }
-            #[cfg(has_i128)]
             #[inline]
             fn from_i128(n: i128) -> Option<$T> {
                 n.$to_ty()
@@ -571,7 +548,6 @@
             fn from_u64(n: u64) -> Option<$T> {
                 n.$to_ty()
             }
-            #[cfg(has_i128)]
             #[inline]
             fn from_u128(n: u128) -> Option<$T> {
                 n.$to_ty()
@@ -594,14 +570,12 @@
 impl_from_primitive!(i16, to_i16);
 impl_from_primitive!(i32, to_i32);
 impl_from_primitive!(i64, to_i64);
-#[cfg(has_i128)]
 impl_from_primitive!(i128, to_i128);
 impl_from_primitive!(usize, to_usize);
 impl_from_primitive!(u8, to_u8);
 impl_from_primitive!(u16, to_u16);
 impl_from_primitive!(u32, to_u32);
 impl_from_primitive!(u64, to_u64);
-#[cfg(has_i128)]
 impl_from_primitive!(u128, to_u128);
 impl_from_primitive!(f32, to_f32);
 impl_from_primitive!(f64, to_f64);
@@ -623,7 +597,6 @@
         fn to_i16 -> i16;
         fn to_i32 -> i32;
         fn to_i64 -> i64;
-        #[cfg(has_i128)]
         fn to_i128 -> i128;
 
         fn to_usize -> usize;
@@ -631,7 +604,6 @@
         fn to_u16 -> u16;
         fn to_u32 -> u32;
         fn to_u64 -> u64;
-        #[cfg(has_i128)]
         fn to_u128 -> u128;
 
         fn to_f32 -> f32;
@@ -656,7 +628,6 @@
         fn from_i16(i16);
         fn from_i32(i32);
         fn from_i64(i64);
-        #[cfg(has_i128)]
         fn from_i128(i128);
 
         fn from_usize(usize);
@@ -664,7 +635,6 @@
         fn from_u16(u16);
         fn from_u32(u32);
         fn from_u64(u64);
-        #[cfg(has_i128)]
         fn from_u128(u128);
 
         fn from_f32(f32);
@@ -722,14 +692,12 @@
 impl_num_cast!(u16, to_u16);
 impl_num_cast!(u32, to_u32);
 impl_num_cast!(u64, to_u64);
-#[cfg(has_i128)]
 impl_num_cast!(u128, to_u128);
 impl_num_cast!(usize, to_usize);
 impl_num_cast!(i8, to_i8);
 impl_num_cast!(i16, to_i16);
 impl_num_cast!(i32, to_i32);
 impl_num_cast!(i64, to_i64);
-#[cfg(has_i128)]
 impl_num_cast!(i128, to_i128);
 impl_num_cast!(isize, to_isize);
 impl_num_cast!(f32, to_f32);
@@ -787,10 +755,8 @@
     )*};
     ($T: ty => { $( $U: ty ),* } ) => {
         impl_as_primitive!(@ $T => { $( $U ),* });
-        impl_as_primitive!(@ $T => { u8, u16, u32, u64, usize });
-        impl_as_primitive!(@ $T => #[cfg(has_i128)] impl u128);
-        impl_as_primitive!(@ $T => { i8, i16, i32, i64, isize });
-        impl_as_primitive!(@ $T => #[cfg(has_i128)] impl i128);
+        impl_as_primitive!(@ $T => { u8, u16, u32, u64, u128, usize });
+        impl_as_primitive!(@ $T => { i8, i16, i32, i64, i128, isize });
     };
 }
 
@@ -802,9 +768,7 @@
 impl_as_primitive!(i32 => { f32, f64 });
 impl_as_primitive!(u64 => { f32, f64 });
 impl_as_primitive!(i64 => { f32, f64 });
-#[cfg(has_i128)]
 impl_as_primitive!(u128 => { f32, f64 });
-#[cfg(has_i128)]
 impl_as_primitive!(i128 => { f32, f64 });
 impl_as_primitive!(usize => { f32, f64 });
 impl_as_primitive!(isize => { f32, f64 });
diff --git a/src/float.rs b/src/float.rs
index 47bd654..87f8387 100644
--- a/src/float.rs
+++ b/src/float.rs
@@ -1,14 +1,10 @@
-use core::mem;
 use core::num::FpCategory;
 use core::ops::{Add, Div, Neg};
 
 use core::f32;
 use core::f64;
 
-use {Num, NumCast, ToPrimitive};
-
-#[cfg(all(not(feature = "std"), feature = "libm"))]
-use libm;
+use crate::{Num, NumCast, ToPrimitive};
 
 /// Generic trait for floating point numbers that works with `no_std`.
 ///
@@ -170,6 +166,7 @@
     /// check(0.0f64, false);
     /// ```
     #[inline]
+    #[allow(clippy::eq_op)]
     fn is_nan(self) -> bool {
         self != self
     }
@@ -244,6 +241,32 @@
         self.classify() == FpCategory::Normal
     }
 
+    /// Returns `true` if the number is [subnormal].
+    ///
+    /// ```
+    /// use num_traits::float::FloatCore;
+    /// use std::f64;
+    ///
+    /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
+    /// let max = f64::MAX;
+    /// let lower_than_min = 1.0e-308_f64;
+    /// let zero = 0.0_f64;
+    ///
+    /// assert!(!min.is_subnormal());
+    /// assert!(!max.is_subnormal());
+    ///
+    /// assert!(!zero.is_subnormal());
+    /// assert!(!f64::NAN.is_subnormal());
+    /// assert!(!f64::INFINITY.is_subnormal());
+    /// // Values between `0` and `min` are Subnormal.
+    /// assert!(lower_than_min.is_subnormal());
+    /// ```
+    /// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number
+    #[inline]
+    fn is_subnormal(self) -> bool {
+        self.classify() == FpCategory::Subnormal
+    }
+
     /// Returns the floating point category of the number. If only one property
     /// is going to be tested, it is generally faster to use the specific
     /// predicate instead.
@@ -370,12 +393,10 @@
             } else {
                 self - f + one
             }
+        } else if -f < h {
+            self - f
         } else {
-            if -f < h {
-                self - f
-            } else {
-                self - f - one
-            }
+            self - f - one
         }
     }
 
@@ -508,8 +529,7 @@
     }
 
     /// Returns `true` if `self` is positive, including `+0.0` and
-    /// `FloatCore::infinity()`, and since Rust 1.20 also
-    /// `FloatCore::nan()`.
+    /// `FloatCore::infinity()`, and `FloatCore::nan()`.
     ///
     /// # Examples
     ///
@@ -527,6 +547,7 @@
     /// check(-0.0f64, false);
     /// check(f64::NEG_INFINITY, false);
     /// check(f64::MIN_POSITIVE, true);
+    /// check(f64::NAN, true);
     /// check(-f64::NAN, false);
     /// ```
     #[inline]
@@ -535,8 +556,7 @@
     }
 
     /// Returns `true` if `self` is negative, including `-0.0` and
-    /// `FloatCore::neg_infinity()`, and since Rust 1.20 also
-    /// `-FloatCore::nan()`.
+    /// `FloatCore::neg_infinity()`, and `-FloatCore::nan()`.
     ///
     /// # Examples
     ///
@@ -555,6 +575,7 @@
     /// check(f64::NEG_INFINITY, true);
     /// check(f64::MIN_POSITIVE, false);
     /// check(f64::NAN, false);
+    /// check(-f64::NAN, true);
     /// ```
     #[inline]
     fn is_sign_negative(self) -> bool {
@@ -763,56 +784,28 @@
         integer_decode_f32(self)
     }
 
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn classify(self) -> FpCategory {
-        const EXP_MASK: u32 = 0x7f800000;
-        const MAN_MASK: u32 = 0x007fffff;
-
-        // Safety: this identical to the implementation of f32::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u32 = unsafe { mem::transmute(self) };
-        match (bits & MAN_MASK, bits & EXP_MASK) {
-            (0, 0) => FpCategory::Zero,
-            (_, 0) => FpCategory::Subnormal,
-            (0, EXP_MASK) => FpCategory::Infinite,
-            (_, EXP_MASK) => FpCategory::Nan,
-            _ => FpCategory::Normal,
-        }
-    }
-
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn is_sign_negative(self) -> bool {
-        const SIGN_MASK: u32 = 0x80000000;
-
-        // Safety: this identical to the implementation of f32::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u32 = unsafe { mem::transmute(self) };
-        bits & SIGN_MASK != 0
-    }
-
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn to_degrees(self) -> Self {
-        // Use a constant for better precision.
-        const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32;
-        self * PIS_IN_180
-    }
-
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn to_radians(self) -> Self {
-        self * (f32::consts::PI / 180.0)
-    }
-
-    #[cfg(feature = "std")]
     forward! {
         Self::is_nan(self) -> bool;
         Self::is_infinite(self) -> bool;
         Self::is_finite(self) -> bool;
         Self::is_normal(self) -> bool;
         Self::classify(self) -> FpCategory;
+        Self::is_sign_positive(self) -> bool;
+        Self::is_sign_negative(self) -> bool;
+        Self::min(self, other: Self) -> Self;
+        Self::max(self, other: Self) -> Self;
+        Self::recip(self) -> Self;
+        Self::to_degrees(self) -> Self;
+        Self::to_radians(self) -> Self;
+    }
+
+    #[cfg(has_is_subnormal)]
+    forward! {
+        Self::is_subnormal(self) -> bool;
+    }
+
+    #[cfg(feature = "std")]
+    forward! {
         Self::floor(self) -> Self;
         Self::ceil(self) -> Self;
         Self::round(self) -> Self;
@@ -820,14 +813,7 @@
         Self::fract(self) -> Self;
         Self::abs(self) -> Self;
         Self::signum(self) -> Self;
-        Self::is_sign_positive(self) -> bool;
-        Self::is_sign_negative(self) -> bool;
-        Self::min(self, other: Self) -> Self;
-        Self::max(self, other: Self) -> Self;
-        Self::recip(self) -> Self;
         Self::powi(self, n: i32) -> Self;
-        Self::to_degrees(self) -> Self;
-        Self::to_radians(self) -> Self;
     }
 
     #[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -837,8 +823,6 @@
         libm::roundf as round(self) -> Self;
         libm::truncf as trunc(self) -> Self;
         libm::fabsf as abs(self) -> Self;
-        libm::fminf as min(self, other: Self) -> Self;
-        libm::fmaxf as max(self, other: Self) -> Self;
     }
 
     #[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -865,57 +849,28 @@
         integer_decode_f64(self)
     }
 
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn classify(self) -> FpCategory {
-        const EXP_MASK: u64 = 0x7ff0000000000000;
-        const MAN_MASK: u64 = 0x000fffffffffffff;
-
-        // Safety: this identical to the implementation of f64::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u64 = unsafe { mem::transmute(self) };
-        match (bits & MAN_MASK, bits & EXP_MASK) {
-            (0, 0) => FpCategory::Zero,
-            (_, 0) => FpCategory::Subnormal,
-            (0, EXP_MASK) => FpCategory::Infinite,
-            (_, EXP_MASK) => FpCategory::Nan,
-            _ => FpCategory::Normal,
-        }
-    }
-
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn is_sign_negative(self) -> bool {
-        const SIGN_MASK: u64 = 0x8000000000000000;
-
-        // Safety: this identical to the implementation of f64::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u64 = unsafe { mem::transmute(self) };
-        bits & SIGN_MASK != 0
-    }
-
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn to_degrees(self) -> Self {
-        // The division here is correctly rounded with respect to the true
-        // value of 180/π. (This differs from f32, where a constant must be
-        // used to ensure a correctly rounded result.)
-        self * (180.0 / f64::consts::PI)
-    }
-
-    #[inline]
-    #[cfg(not(feature = "std"))]
-    fn to_radians(self) -> Self {
-        self * (f64::consts::PI / 180.0)
-    }
-
-    #[cfg(feature = "std")]
     forward! {
         Self::is_nan(self) -> bool;
         Self::is_infinite(self) -> bool;
         Self::is_finite(self) -> bool;
         Self::is_normal(self) -> bool;
         Self::classify(self) -> FpCategory;
+        Self::is_sign_positive(self) -> bool;
+        Self::is_sign_negative(self) -> bool;
+        Self::min(self, other: Self) -> Self;
+        Self::max(self, other: Self) -> Self;
+        Self::recip(self) -> Self;
+        Self::to_degrees(self) -> Self;
+        Self::to_radians(self) -> Self;
+    }
+
+    #[cfg(has_is_subnormal)]
+    forward! {
+        Self::is_subnormal(self) -> bool;
+    }
+
+    #[cfg(feature = "std")]
+    forward! {
         Self::floor(self) -> Self;
         Self::ceil(self) -> Self;
         Self::round(self) -> Self;
@@ -923,14 +878,7 @@
         Self::fract(self) -> Self;
         Self::abs(self) -> Self;
         Self::signum(self) -> Self;
-        Self::is_sign_positive(self) -> bool;
-        Self::is_sign_negative(self) -> bool;
-        Self::min(self, other: Self) -> Self;
-        Self::max(self, other: Self) -> Self;
-        Self::recip(self) -> Self;
         Self::powi(self, n: i32) -> Self;
-        Self::to_degrees(self) -> Self;
-        Self::to_radians(self) -> Self;
     }
 
     #[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -940,8 +888,6 @@
         libm::round as round(self) -> Self;
         libm::trunc as trunc(self) -> Self;
         libm::fabs as abs(self) -> Self;
-        libm::fmin as min(self, other: Self) -> Self;
-        libm::fmax as max(self, other: Self) -> Self;
     }
 
     #[cfg(all(not(feature = "std"), feature = "libm"))]
@@ -1138,9 +1084,35 @@
     /// // Values between `0` and `min` are Subnormal.
     /// assert!(!lower_than_min.is_normal());
     /// ```
-    /// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number
+    /// [subnormal]: http://en.wikipedia.org/wiki/Subnormal_number
     fn is_normal(self) -> bool;
 
+    /// Returns `true` if the number is [subnormal].
+    ///
+    /// ```
+    /// use num_traits::Float;
+    /// use std::f64;
+    ///
+    /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
+    /// let max = f64::MAX;
+    /// let lower_than_min = 1.0e-308_f64;
+    /// let zero = 0.0_f64;
+    ///
+    /// assert!(!min.is_subnormal());
+    /// assert!(!max.is_subnormal());
+    ///
+    /// assert!(!zero.is_subnormal());
+    /// assert!(!f64::NAN.is_subnormal());
+    /// assert!(!f64::INFINITY.is_subnormal());
+    /// // Values between `0` and `min` are Subnormal.
+    /// assert!(lower_than_min.is_subnormal());
+    /// ```
+    /// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number
+    #[inline]
+    fn is_subnormal(self) -> bool {
+        self.classify() == FpCategory::Subnormal
+    }
+
     /// Returns the floating point category of the number. If only one property
     /// is going to be tested, it is generally faster to use the specific
     /// predicate instead.
@@ -1266,12 +1238,13 @@
     fn signum(self) -> Self;
 
     /// Returns `true` if `self` is positive, including `+0.0`,
-    /// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`.
+    /// `Float::infinity()`, and `Float::nan()`.
     ///
     /// ```
     /// use num_traits::Float;
     /// use std::f64;
     ///
+    /// let nan: f64 = f64::NAN;
     /// let neg_nan: f64 = -f64::NAN;
     ///
     /// let f = 7.0;
@@ -1279,18 +1252,20 @@
     ///
     /// assert!(f.is_sign_positive());
     /// assert!(!g.is_sign_positive());
+    /// assert!(nan.is_sign_positive());
     /// assert!(!neg_nan.is_sign_positive());
     /// ```
     fn is_sign_positive(self) -> bool;
 
     /// Returns `true` if `self` is negative, including `-0.0`,
-    /// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`.
+    /// `Float::neg_infinity()`, and `-Float::nan()`.
     ///
     /// ```
     /// use num_traits::Float;
     /// use std::f64;
     ///
     /// let nan: f64 = f64::NAN;
+    /// let neg_nan: f64 = -f64::NAN;
     ///
     /// let f = 7.0;
     /// let g = -7.0;
@@ -1298,6 +1273,7 @@
     /// assert!(!f.is_sign_negative());
     /// assert!(g.is_sign_negative());
     /// assert!(!nan.is_sign_negative());
+    /// assert!(neg_nan.is_sign_negative());
     /// ```
     fn is_sign_negative(self) -> bool;
 
@@ -1970,9 +1946,13 @@
             }
 
             #[cfg(has_copysign)]
-            #[inline]
-            fn copysign(self, sign: Self) -> Self {
-                Self::copysign(self, sign)
+            forward! {
+                Self::copysign(self, sign: Self) -> Self;
+            }
+
+            #[cfg(has_is_subnormal)]
+            forward! {
+                Self::is_subnormal(self) -> bool;
             }
         }
     };
@@ -2008,26 +1988,34 @@
         }
 
         forward! {
-            FloatCore::is_nan(self) -> bool;
-            FloatCore::is_infinite(self) -> bool;
-            FloatCore::is_finite(self) -> bool;
-            FloatCore::is_normal(self) -> bool;
-            FloatCore::classify(self) -> FpCategory;
+            Self::is_nan(self) -> bool;
+            Self::is_infinite(self) -> bool;
+            Self::is_finite(self) -> bool;
+            Self::is_normal(self) -> bool;
+            Self::classify(self) -> FpCategory;
+            Self::is_sign_positive(self) -> bool;
+            Self::is_sign_negative(self) -> bool;
+            Self::min(self, other: Self) -> Self;
+            Self::max(self, other: Self) -> Self;
+            Self::recip(self) -> Self;
+            Self::to_degrees(self) -> Self;
+            Self::to_radians(self) -> Self;
+        }
+
+        #[cfg(has_is_subnormal)]
+        forward! {
+            Self::is_subnormal(self) -> bool;
+        }
+
+        forward! {
             FloatCore::signum(self) -> Self;
-            FloatCore::is_sign_positive(self) -> bool;
-            FloatCore::is_sign_negative(self) -> bool;
-            FloatCore::recip(self) -> Self;
             FloatCore::powi(self, n: i32) -> Self;
-            FloatCore::to_degrees(self) -> Self;
-            FloatCore::to_radians(self) -> Self;
         }
     };
 }
 
 fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
-    // Safety: this identical to the implementation of f32::to_bits(),
-    // which is only available starting at Rust 1.20
-    let bits: u32 = unsafe { mem::transmute(f) };
+    let bits: u32 = f.to_bits();
     let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
     let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
     let mantissa = if exponent == 0 {
@@ -2041,9 +2029,7 @@
 }
 
 fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
-    // Safety: this identical to the implementation of f64::to_bits(),
-    // which is only available starting at Rust 1.20
-    let bits: u64 = unsafe { mem::transmute(f) };
+    let bits: u64 = f.to_bits();
     let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
     let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
     let mantissa = if exponent == 0 {
@@ -2103,8 +2089,6 @@
         libm::asinhf as asinh(self) -> Self;
         libm::acoshf as acosh(self) -> Self;
         libm::atanhf as atanh(self) -> Self;
-        libm::fmaxf as max(self, other: Self) -> Self;
-        libm::fminf as min(self, other: Self) -> Self;
         libm::copysignf as copysign(self, other: Self) -> Self;
     }
 }
@@ -2151,8 +2135,6 @@
         libm::asinh as asinh(self) -> Self;
         libm::acosh as acosh(self) -> Self;
         libm::atanh as atanh(self) -> Self;
-        libm::fmax as max(self, other: Self) -> Self;
-        libm::fmin as min(self, other: Self) -> Self;
         libm::copysign as copysign(self, sign: Self) -> Self;
     }
 }
@@ -2244,7 +2226,7 @@
 
     #[test]
     fn convert_deg_rad() {
-        use float::FloatCore;
+        use crate::float::FloatCore;
 
         for &(deg, rad) in &DEG_RAD_PAIRS {
             assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-6);
@@ -2260,7 +2242,7 @@
     #[test]
     fn convert_deg_rad_std() {
         for &(deg, rad) in &DEG_RAD_PAIRS {
-            use Float;
+            use crate::Float;
 
             assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);
             assert!((Float::to_radians(deg) - rad).abs() < 1e-6);
@@ -2272,11 +2254,8 @@
     }
 
     #[test]
-    // This fails with the forwarded `std` implementation in Rust 1.8.
-    // To avoid the failure, the test is limited to `no_std` builds.
-    #[cfg(not(feature = "std"))]
     fn to_degrees_rounding() {
-        use float::FloatCore;
+        use crate::float::FloatCore;
 
         assert_eq!(
             FloatCore::to_degrees(1_f32),
@@ -2287,7 +2266,7 @@
     #[test]
     #[cfg(any(feature = "std", feature = "libm"))]
     fn extra_logs() {
-        use float::{Float, FloatConst};
+        use crate::float::{Float, FloatConst};
 
         fn check<F: Float + FloatConst>(diff: F) {
             let _2 = F::from(2.0).unwrap();
@@ -2306,7 +2285,7 @@
     #[test]
     #[cfg(any(feature = "std", feature = "libm"))]
     fn copysign() {
-        use float::Float;
+        use crate::float::Float;
         test_copysign_generic(2.0_f32, -2.0_f32, f32::nan());
         test_copysign_generic(2.0_f64, -2.0_f64, f64::nan());
         test_copysignf(2.0_f32, -2.0_f32, f32::nan());
@@ -2314,8 +2293,8 @@
 
     #[cfg(any(feature = "std", feature = "libm"))]
     fn test_copysignf(p: f32, n: f32, nan: f32) {
+        use crate::float::Float;
         use core::ops::Neg;
-        use float::Float;
 
         assert!(p.is_sign_positive());
         assert!(n.is_sign_negative());
@@ -2327,16 +2306,16 @@
         assert_eq!(n, Float::copysign(n, n));
         assert_eq!(n.neg(), Float::copysign(n, p));
 
-        // FIXME: is_sign... only works on NaN starting in Rust 1.20
-        // assert!(Float::copysign(nan, p).is_sign_positive());
-        // assert!(Float::copysign(nan, n).is_sign_negative());
+        assert!(Float::copysign(nan, p).is_sign_positive());
+        assert!(Float::copysign(nan, n).is_sign_negative());
     }
 
     #[cfg(any(feature = "std", feature = "libm"))]
-    fn test_copysign_generic<F: ::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) {
+    fn test_copysign_generic<F: crate::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) {
         assert!(p.is_sign_positive());
         assert!(n.is_sign_negative());
         assert!(nan.is_nan());
+        assert!(!nan.is_subnormal());
 
         assert_eq!(p, p.copysign(p));
         assert_eq!(p.neg(), p.copysign(n));
@@ -2344,8 +2323,22 @@
         assert_eq!(n, n.copysign(n));
         assert_eq!(n.neg(), n.copysign(p));
 
-        // FIXME: is_sign... only works on NaN starting in Rust 1.20
-        // assert!(nan.copysign(p).is_sign_positive());
-        // assert!(nan.copysign(n).is_sign_negative());
+        assert!(nan.copysign(p).is_sign_positive());
+        assert!(nan.copysign(n).is_sign_negative());
+    }
+
+    #[cfg(any(feature = "std", feature = "libm"))]
+    fn test_subnormal<F: crate::float::Float + ::core::fmt::Debug>() {
+        let min_positive = F::min_positive_value();
+        let lower_than_min = min_positive / F::from(2.0f32).unwrap();
+        assert!(!min_positive.is_subnormal());
+        assert!(lower_than_min.is_subnormal());
+    }
+
+    #[test]
+    #[cfg(any(feature = "std", feature = "libm"))]
+    fn subnormal() {
+        test_subnormal::<f64>();
+        test_subnormal::<f32>();
     }
 }
diff --git a/src/identities.rs b/src/identities.rs
index 7a99566..2486cb1 100644
--- a/src/identities.rs
+++ b/src/identities.rs
@@ -5,7 +5,7 @@
 ///
 /// # Laws
 ///
-/// ```{.text}
+/// ```text
 /// a + 0 = a       ∀ a ∈ Self
 /// 0 + a = a       ∀ a ∈ Self
 /// ```
@@ -48,7 +48,6 @@
 zero_impl!(u16, 0);
 zero_impl!(u32, 0);
 zero_impl!(u64, 0);
-#[cfg(has_i128)]
 zero_impl!(u128, 0);
 
 zero_impl!(isize, 0);
@@ -56,7 +55,6 @@
 zero_impl!(i16, 0);
 zero_impl!(i32, 0);
 zero_impl!(i64, 0);
-#[cfg(has_i128)]
 zero_impl!(i128, 0);
 
 zero_impl!(f32, 0.0);
@@ -83,7 +81,7 @@
 ///
 /// # Laws
 ///
-/// ```{.text}
+/// ```text
 /// a * 1 = a       ∀ a ∈ Self
 /// 1 * a = a       ∀ a ∈ Self
 /// ```
@@ -137,7 +135,6 @@
 one_impl!(u16, 1);
 one_impl!(u32, 1);
 one_impl!(u64, 1);
-#[cfg(has_i128)]
 one_impl!(u128, 1);
 
 one_impl!(isize, 1);
@@ -145,7 +142,6 @@
 one_impl!(i16, 1);
 one_impl!(i32, 1);
 one_impl!(i64, 1);
-#[cfg(has_i128)]
 one_impl!(i128, 1);
 
 one_impl!(f32, 1.0);
diff --git a/src/int.rs b/src/int.rs
index c7dbf12..e3ca72c 100644
--- a/src/int.rs
+++ b/src/int.rs
@@ -1,9 +1,9 @@
 use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
 
-use bounds::Bounded;
-use ops::checked::*;
-use ops::saturating::Saturating;
-use {Num, NumCast};
+use crate::bounds::Bounded;
+use crate::ops::checked::*;
+use crate::ops::saturating::Saturating;
+use crate::{Num, NumCast};
 
 /// Generic trait for primitive integers.
 ///
@@ -500,20 +500,18 @@
 prim_int_impl!(u16, i16, u16);
 prim_int_impl!(u32, i32, u32);
 prim_int_impl!(u64, i64, u64);
-#[cfg(has_i128)]
 prim_int_impl!(u128, i128, u128);
 prim_int_impl!(usize, isize, usize);
 prim_int_impl!(i8, i8, u8);
 prim_int_impl!(i16, i16, u16);
 prim_int_impl!(i32, i32, u32);
 prim_int_impl!(i64, i64, u64);
-#[cfg(has_i128)]
 prim_int_impl!(i128, i128, u128);
 prim_int_impl!(isize, isize, usize);
 
 #[cfg(test)]
 mod tests {
-    use int::PrimInt;
+    use crate::int::PrimInt;
 
     #[test]
     pub fn reverse_bits() {
@@ -554,7 +552,6 @@
     }
 
     #[test]
-    #[cfg(has_i128)]
     pub fn reverse_bits_i128() {
         use core::i128;
 
diff --git a/src/lib.rs b/src/lib.rs
index bed87f3..54dab6e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,43 +12,42 @@
 //!
 //! ## Compatibility
 //!
-//! The `num-traits` crate is tested for rustc 1.8 and greater.
+//! The `num-traits` crate is tested for rustc 1.31 and greater.
 
 #![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
 #![deny(unconditional_recursion)]
 #![no_std]
+
+// Need to explicitly bring the crate in for inherent float methods
 #[cfg(feature = "std")]
 extern crate std;
 
-// Only `no_std` builds actually use `libm`.
-#[cfg(all(not(feature = "std"), feature = "libm"))]
-extern crate libm;
-
 use core::fmt;
 use core::num::Wrapping;
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
 
-pub use bounds::Bounded;
+pub use crate::bounds::Bounded;
 #[cfg(any(feature = "std", feature = "libm"))]
-pub use float::Float;
-pub use float::FloatConst;
+pub use crate::float::Float;
+pub use crate::float::FloatConst;
 // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
-pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
-pub use identities::{one, zero, One, Zero};
-pub use int::PrimInt;
-pub use ops::checked::{
+pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
+pub use crate::identities::{one, zero, One, Zero};
+pub use crate::int::PrimInt;
+pub use crate::ops::bytes::{FromBytes, ToBytes};
+pub use crate::ops::checked::{
     CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
 };
-pub use ops::euclid::{CheckedEuclid, Euclid};
-pub use ops::inv::Inv;
-pub use ops::mul_add::{MulAdd, MulAddAssign};
-pub use ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
-pub use ops::wrapping::{
+pub use crate::ops::euclid::{CheckedEuclid, Euclid};
+pub use crate::ops::inv::Inv;
+pub use crate::ops::mul_add::{MulAdd, MulAddAssign};
+pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
+pub use crate::ops::wrapping::{
     WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
 };
-pub use pow::{checked_pow, pow, Pow};
-pub use sign::{abs, abs_sub, signum, Signed, Unsigned};
+pub use crate::pow::{checked_pow, pow, Pow};
+pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned};
 
 #[macro_use]
 mod macros;
@@ -172,9 +171,8 @@
         }
     )*)
 }
-int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
-#[cfg(has_i128)]
-int_trait_impl!(Num for u128 i128);
+int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
+int_trait_impl!(Num for isize i8 i16 i32 i64 i128);
 
 impl<T: Num> Num for Wrapping<T>
 where
@@ -199,7 +197,7 @@
 }
 
 impl fmt::Display for ParseFloatError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let description = match self.kind {
             FloatErrorKind::Empty => "cannot parse float from empty string",
             FloatErrorKind::Invalid => "invalid float literal",
@@ -255,11 +253,7 @@
 
                 fn slice_shift_char(src: &str) -> Option<(char, &str)> {
                     let mut chars = src.chars();
-                    if let Some(ch) = chars.next() {
-                        Some((ch, chars.as_str()))
-                    } else {
-                        None
-                    }
+                    Some((chars.next()?, chars.as_str()))
                 }
 
                 let (is_positive, src) =  match slice_shift_char(src) {
@@ -282,13 +276,13 @@
                     match c.to_digit(radix) {
                         Some(digit) => {
                             // shift significand one digit left
-                            sig = sig * (radix as $t);
+                            sig *= radix as $t;
 
                             // add/subtract current digit depending on sign
                             if is_positive {
-                                sig = sig + ((digit as isize) as $t);
+                                sig += (digit as isize) as $t;
                             } else {
-                                sig = sig - ((digit as isize) as $t);
+                                sig -= (digit as isize) as $t;
                             }
 
                             // Detect overflow by comparing to last value, except
@@ -330,7 +324,7 @@
                         match c.to_digit(radix) {
                             Some(digit) => {
                                 // Decrease power one order of magnitude
-                                power = power / (radix as $t);
+                                power /= radix as $t;
                                 // add/subtract current digit depending on sign
                                 sig = if is_positive {
                                     sig + (digit as $t) * power
@@ -424,6 +418,7 @@
 ///
 /// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
 #[inline]
+#[allow(clippy::eq_op)]
 pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
     debug_assert!(min == min, "min must not be NAN");
     if input < min {
@@ -441,6 +436,7 @@
 ///
 /// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
 #[inline]
+#[allow(clippy::eq_op)]
 pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
     debug_assert!(max == max, "max must not be NAN");
     if input > max {
@@ -625,7 +621,6 @@
     assert_eq!(compute(1, 2), 1)
 }
 
-#[cfg(has_int_assignop_ref)]
 #[test]
 fn check_numassignref_ops() {
     fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T {
diff --git a/src/ops/bytes.rs b/src/ops/bytes.rs
new file mode 100644
index 0000000..4df9ecd
--- /dev/null
+++ b/src/ops/bytes.rs
@@ -0,0 +1,403 @@
+use core::borrow::{Borrow, BorrowMut};
+use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
+use core::fmt::Debug;
+use core::hash::Hash;
+#[cfg(not(has_int_to_from_bytes))]
+use core::mem::transmute;
+
+pub trait NumBytes:
+    Debug
+    + AsRef<[u8]>
+    + AsMut<[u8]>
+    + PartialEq
+    + Eq
+    + PartialOrd
+    + Ord
+    + Hash
+    + Borrow<[u8]>
+    + BorrowMut<[u8]>
+{
+}
+
+impl<T> NumBytes for T where
+    T: Debug
+        + AsRef<[u8]>
+        + AsMut<[u8]>
+        + PartialEq
+        + Eq
+        + PartialOrd
+        + Ord
+        + Hash
+        + Borrow<[u8]>
+        + BorrowMut<[u8]>
+        + ?Sized
+{
+}
+
+pub trait ToBytes {
+    type Bytes: NumBytes;
+
+    /// Return the memory representation of this number as a byte array in big-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::ToBytes;
+    ///
+    /// let bytes = ToBytes::to_be_bytes(&0x12345678u32);
+    /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
+    /// ```
+    fn to_be_bytes(&self) -> Self::Bytes;
+
+    /// Return the memory representation of this number as a byte array in little-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::ToBytes;
+    ///
+    /// let bytes = ToBytes::to_le_bytes(&0x12345678u32);
+    /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
+    /// ```
+    fn to_le_bytes(&self) -> Self::Bytes;
+
+    /// Return the memory representation of this number as a byte array in native byte order.
+    ///
+    /// As the target platform's native endianness is used,
+    /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead.
+    ///
+    /// [`to_be_bytes`]: #method.to_be_bytes
+    /// [`to_le_bytes`]: #method.to_le_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::ToBytes;
+    ///
+    /// #[cfg(target_endian = "big")]
+    /// let expected = [0x12, 0x34, 0x56, 0x78];
+    ///
+    /// #[cfg(target_endian = "little")]
+    /// let expected = [0x78, 0x56, 0x34, 0x12];
+    ///
+    /// let bytes = ToBytes::to_ne_bytes(&0x12345678u32);
+    /// assert_eq!(bytes, expected)
+    /// ```
+    fn to_ne_bytes(&self) -> Self::Bytes {
+        #[cfg(target_endian = "big")]
+        let bytes = self.to_be_bytes();
+        #[cfg(target_endian = "little")]
+        let bytes = self.to_le_bytes();
+        bytes
+    }
+}
+
+pub trait FromBytes: Sized {
+    type Bytes: NumBytes + ?Sized;
+
+    /// Create a number from its representation as a byte array in big endian.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::FromBytes;
+    ///
+    /// let value: u32 = FromBytes::from_be_bytes(&[0x12, 0x34, 0x56, 0x78]);
+    /// assert_eq!(value, 0x12345678);
+    /// ```
+    fn from_be_bytes(bytes: &Self::Bytes) -> Self;
+
+    /// Create a number from its representation as a byte array in little endian.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::FromBytes;
+    ///
+    /// let value: u32 = FromBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]);
+    /// assert_eq!(value, 0x12345678);
+    /// ```
+    fn from_le_bytes(bytes: &Self::Bytes) -> Self;
+
+    /// Create a number from its memory representation as a byte array in native endianness.
+    ///
+    /// As the target platform's native endianness is used,
+    /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead.
+    ///
+    /// [`from_be_bytes`]: #method.from_be_bytes
+    /// [`from_le_bytes`]: #method.from_le_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_traits::FromBytes;
+    ///
+    /// #[cfg(target_endian = "big")]
+    /// let bytes = [0x12, 0x34, 0x56, 0x78];
+    ///
+    /// #[cfg(target_endian = "little")]
+    /// let bytes = [0x78, 0x56, 0x34, 0x12];
+    ///
+    /// let value: u32 = FromBytes::from_ne_bytes(&bytes);
+    /// assert_eq!(value, 0x12345678)
+    /// ```
+    fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
+        #[cfg(target_endian = "big")]
+        let this = Self::from_be_bytes(bytes);
+        #[cfg(target_endian = "little")]
+        let this = Self::from_le_bytes(bytes);
+        this
+    }
+}
+
+macro_rules! float_to_from_bytes_impl {
+    ($T:ty, $L:expr) => {
+        #[cfg(has_float_to_from_bytes)]
+        impl ToBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn to_be_bytes(&self) -> Self::Bytes {
+                <$T>::to_be_bytes(*self)
+            }
+
+            #[inline]
+            fn to_le_bytes(&self) -> Self::Bytes {
+                <$T>::to_le_bytes(*self)
+            }
+
+            #[inline]
+            fn to_ne_bytes(&self) -> Self::Bytes {
+                <$T>::to_ne_bytes(*self)
+            }
+        }
+
+        #[cfg(has_float_to_from_bytes)]
+        impl FromBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn from_be_bytes(bytes: &Self::Bytes) -> Self {
+                <$T>::from_be_bytes(*bytes)
+            }
+
+            #[inline]
+            fn from_le_bytes(bytes: &Self::Bytes) -> Self {
+                <$T>::from_le_bytes(*bytes)
+            }
+
+            #[inline]
+            fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
+                <$T>::from_ne_bytes(*bytes)
+            }
+        }
+
+        #[cfg(not(has_float_to_from_bytes))]
+        impl ToBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn to_be_bytes(&self) -> Self::Bytes {
+                ToBytes::to_be_bytes(&self.to_bits())
+            }
+
+            #[inline]
+            fn to_le_bytes(&self) -> Self::Bytes {
+                ToBytes::to_le_bytes(&self.to_bits())
+            }
+
+            #[inline]
+            fn to_ne_bytes(&self) -> Self::Bytes {
+                ToBytes::to_ne_bytes(&self.to_bits())
+            }
+        }
+
+        #[cfg(not(has_float_to_from_bytes))]
+        impl FromBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn from_be_bytes(bytes: &Self::Bytes) -> Self {
+                Self::from_bits(FromBytes::from_be_bytes(bytes))
+            }
+
+            #[inline]
+            fn from_le_bytes(bytes: &Self::Bytes) -> Self {
+                Self::from_bits(FromBytes::from_le_bytes(bytes))
+            }
+
+            #[inline]
+            fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
+                Self::from_bits(FromBytes::from_ne_bytes(bytes))
+            }
+        }
+    };
+}
+
+macro_rules! int_to_from_bytes_impl {
+    ($T:ty, $L:expr) => {
+        #[cfg(has_int_to_from_bytes)]
+        impl ToBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn to_be_bytes(&self) -> Self::Bytes {
+                <$T>::to_be_bytes(*self)
+            }
+
+            #[inline]
+            fn to_le_bytes(&self) -> Self::Bytes {
+                <$T>::to_le_bytes(*self)
+            }
+
+            #[inline]
+            fn to_ne_bytes(&self) -> Self::Bytes {
+                <$T>::to_ne_bytes(*self)
+            }
+        }
+
+        #[cfg(has_int_to_from_bytes)]
+        impl FromBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn from_be_bytes(bytes: &Self::Bytes) -> Self {
+                <$T>::from_be_bytes(*bytes)
+            }
+
+            #[inline]
+            fn from_le_bytes(bytes: &Self::Bytes) -> Self {
+                <$T>::from_le_bytes(*bytes)
+            }
+
+            #[inline]
+            fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
+                <$T>::from_ne_bytes(*bytes)
+            }
+        }
+
+        #[cfg(not(has_int_to_from_bytes))]
+        impl ToBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn to_be_bytes(&self) -> Self::Bytes {
+                <$T as ToBytes>::to_ne_bytes(&<$T>::to_be(*self))
+            }
+
+            #[inline]
+            fn to_le_bytes(&self) -> Self::Bytes {
+                <$T as ToBytes>::to_ne_bytes(&<$T>::to_le(*self))
+            }
+
+            #[inline]
+            fn to_ne_bytes(&self) -> Self::Bytes {
+                unsafe { transmute(*self) }
+            }
+        }
+
+        #[cfg(not(has_int_to_from_bytes))]
+        impl FromBytes for $T {
+            type Bytes = [u8; $L];
+
+            #[inline]
+            fn from_be_bytes(bytes: &Self::Bytes) -> Self {
+                Self::from_be(<Self as FromBytes>::from_ne_bytes(bytes))
+            }
+
+            #[inline]
+            fn from_le_bytes(bytes: &Self::Bytes) -> Self {
+                Self::from_le(<Self as FromBytes>::from_ne_bytes(bytes))
+            }
+
+            #[inline]
+            fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
+                unsafe { transmute(*bytes) }
+            }
+        }
+    };
+}
+
+int_to_from_bytes_impl!(u8, 1);
+int_to_from_bytes_impl!(u16, 2);
+int_to_from_bytes_impl!(u32, 4);
+int_to_from_bytes_impl!(u64, 8);
+int_to_from_bytes_impl!(u128, 16);
+#[cfg(target_pointer_width = "64")]
+int_to_from_bytes_impl!(usize, 8);
+#[cfg(target_pointer_width = "32")]
+int_to_from_bytes_impl!(usize, 4);
+
+int_to_from_bytes_impl!(i8, 1);
+int_to_from_bytes_impl!(i16, 2);
+int_to_from_bytes_impl!(i32, 4);
+int_to_from_bytes_impl!(i64, 8);
+int_to_from_bytes_impl!(i128, 16);
+#[cfg(target_pointer_width = "64")]
+int_to_from_bytes_impl!(isize, 8);
+#[cfg(target_pointer_width = "32")]
+int_to_from_bytes_impl!(isize, 4);
+
+float_to_from_bytes_impl!(f32, 4);
+float_to_from_bytes_impl!(f64, 8);
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    macro_rules! check_to_from_bytes {
+        ($( $ty:ty )+) => {$({
+            let n = 1;
+            let be = <$ty as ToBytes>::to_be_bytes(&n);
+            let le = <$ty as ToBytes>::to_le_bytes(&n);
+            let ne = <$ty as ToBytes>::to_ne_bytes(&n);
+
+            assert_eq!(*be.last().unwrap(), 1);
+            assert_eq!(*le.first().unwrap(), 1);
+            if cfg!(target_endian = "big") {
+                assert_eq!(*ne.last().unwrap(), 1);
+            } else {
+                assert_eq!(*ne.first().unwrap(), 1);
+            }
+
+            assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
+            assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
+            if cfg!(target_endian = "big") {
+                assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
+            } else {
+                assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
+            }
+        })+}
+    }
+
+    #[test]
+    fn convert_between_int_and_bytes() {
+        check_to_from_bytes!(u8 u16 u32 u64 u128 usize);
+        check_to_from_bytes!(i8 i16 i32 i64 i128 isize);
+    }
+
+    #[test]
+    fn convert_between_float_and_bytes() {
+        macro_rules! check_to_from_bytes {
+            ($( $ty:ty )+) => {$(
+                let n: $ty = 3.14;
+
+                let be = <$ty as ToBytes>::to_be_bytes(&n);
+                let le = <$ty as ToBytes>::to_le_bytes(&n);
+                let ne = <$ty as ToBytes>::to_ne_bytes(&n);
+
+                assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n);
+                assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n);
+                if cfg!(target_endian = "big") {
+                    assert_eq!(ne, be);
+                    assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n);
+                } else {
+                    assert_eq!(ne, le);
+                    assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n);
+                }
+            )+}
+        }
+
+        check_to_from_bytes!(f32 f64);
+    }
+}
diff --git a/src/ops/checked.rs b/src/ops/checked.rs
index 3865570..da1eb3e 100644
--- a/src/ops/checked.rs
+++ b/src/ops/checked.rs
@@ -24,7 +24,6 @@
 checked_impl!(CheckedAdd, checked_add, u32);
 checked_impl!(CheckedAdd, checked_add, u64);
 checked_impl!(CheckedAdd, checked_add, usize);
-#[cfg(has_i128)]
 checked_impl!(CheckedAdd, checked_add, u128);
 
 checked_impl!(CheckedAdd, checked_add, i8);
@@ -32,7 +31,6 @@
 checked_impl!(CheckedAdd, checked_add, i32);
 checked_impl!(CheckedAdd, checked_add, i64);
 checked_impl!(CheckedAdd, checked_add, isize);
-#[cfg(has_i128)]
 checked_impl!(CheckedAdd, checked_add, i128);
 
 /// Performs subtraction that returns `None` instead of wrapping around on underflow.
@@ -47,7 +45,6 @@
 checked_impl!(CheckedSub, checked_sub, u32);
 checked_impl!(CheckedSub, checked_sub, u64);
 checked_impl!(CheckedSub, checked_sub, usize);
-#[cfg(has_i128)]
 checked_impl!(CheckedSub, checked_sub, u128);
 
 checked_impl!(CheckedSub, checked_sub, i8);
@@ -55,7 +52,6 @@
 checked_impl!(CheckedSub, checked_sub, i32);
 checked_impl!(CheckedSub, checked_sub, i64);
 checked_impl!(CheckedSub, checked_sub, isize);
-#[cfg(has_i128)]
 checked_impl!(CheckedSub, checked_sub, i128);
 
 /// Performs multiplication that returns `None` instead of wrapping around on underflow or
@@ -71,7 +67,6 @@
 checked_impl!(CheckedMul, checked_mul, u32);
 checked_impl!(CheckedMul, checked_mul, u64);
 checked_impl!(CheckedMul, checked_mul, usize);
-#[cfg(has_i128)]
 checked_impl!(CheckedMul, checked_mul, u128);
 
 checked_impl!(CheckedMul, checked_mul, i8);
@@ -79,7 +74,6 @@
 checked_impl!(CheckedMul, checked_mul, i32);
 checked_impl!(CheckedMul, checked_mul, i64);
 checked_impl!(CheckedMul, checked_mul, isize);
-#[cfg(has_i128)]
 checked_impl!(CheckedMul, checked_mul, i128);
 
 /// Performs division that returns `None` instead of panicking on division by zero and instead of
@@ -95,7 +89,6 @@
 checked_impl!(CheckedDiv, checked_div, u32);
 checked_impl!(CheckedDiv, checked_div, u64);
 checked_impl!(CheckedDiv, checked_div, usize);
-#[cfg(has_i128)]
 checked_impl!(CheckedDiv, checked_div, u128);
 
 checked_impl!(CheckedDiv, checked_div, i8);
@@ -103,7 +96,6 @@
 checked_impl!(CheckedDiv, checked_div, i32);
 checked_impl!(CheckedDiv, checked_div, i64);
 checked_impl!(CheckedDiv, checked_div, isize);
-#[cfg(has_i128)]
 checked_impl!(CheckedDiv, checked_div, i128);
 
 /// Performs an integral remainder that returns `None` instead of panicking on division by zero and
@@ -136,7 +128,6 @@
 checked_impl!(CheckedRem, checked_rem, u32);
 checked_impl!(CheckedRem, checked_rem, u64);
 checked_impl!(CheckedRem, checked_rem, usize);
-#[cfg(has_i128)]
 checked_impl!(CheckedRem, checked_rem, u128);
 
 checked_impl!(CheckedRem, checked_rem, i8);
@@ -144,7 +135,6 @@
 checked_impl!(CheckedRem, checked_rem, i32);
 checked_impl!(CheckedRem, checked_rem, i64);
 checked_impl!(CheckedRem, checked_rem, isize);
-#[cfg(has_i128)]
 checked_impl!(CheckedRem, checked_rem, i128);
 
 macro_rules! checked_impl_unary {
@@ -184,7 +174,6 @@
 checked_impl_unary!(CheckedNeg, checked_neg, u32);
 checked_impl_unary!(CheckedNeg, checked_neg, u64);
 checked_impl_unary!(CheckedNeg, checked_neg, usize);
-#[cfg(has_i128)]
 checked_impl_unary!(CheckedNeg, checked_neg, u128);
 
 checked_impl_unary!(CheckedNeg, checked_neg, i8);
@@ -192,11 +181,10 @@
 checked_impl_unary!(CheckedNeg, checked_neg, i32);
 checked_impl_unary!(CheckedNeg, checked_neg, i64);
 checked_impl_unary!(CheckedNeg, checked_neg, isize);
-#[cfg(has_i128)]
 checked_impl_unary!(CheckedNeg, checked_neg, i128);
 
 /// Performs a left shift that returns `None` on shifts larger than
-/// the type width.
+/// or equal to the type width.
 pub trait CheckedShl: Sized + Shl<u32, Output = Self> {
     /// Checked shift left. Computes `self << rhs`, returning `None`
     /// if `rhs` is larger than or equal to the number of bits in `self`.
@@ -230,7 +218,6 @@
 checked_shift_impl!(CheckedShl, checked_shl, u32);
 checked_shift_impl!(CheckedShl, checked_shl, u64);
 checked_shift_impl!(CheckedShl, checked_shl, usize);
-#[cfg(has_i128)]
 checked_shift_impl!(CheckedShl, checked_shl, u128);
 
 checked_shift_impl!(CheckedShl, checked_shl, i8);
@@ -238,11 +225,10 @@
 checked_shift_impl!(CheckedShl, checked_shl, i32);
 checked_shift_impl!(CheckedShl, checked_shl, i64);
 checked_shift_impl!(CheckedShl, checked_shl, isize);
-#[cfg(has_i128)]
 checked_shift_impl!(CheckedShl, checked_shl, i128);
 
 /// Performs a right shift that returns `None` on shifts larger than
-/// the type width.
+/// or equal to the type width.
 pub trait CheckedShr: Sized + Shr<u32, Output = Self> {
     /// Checked shift right. Computes `self >> rhs`, returning `None`
     /// if `rhs` is larger than or equal to the number of bits in `self`.
@@ -265,7 +251,6 @@
 checked_shift_impl!(CheckedShr, checked_shr, u32);
 checked_shift_impl!(CheckedShr, checked_shr, u64);
 checked_shift_impl!(CheckedShr, checked_shr, usize);
-#[cfg(has_i128)]
 checked_shift_impl!(CheckedShr, checked_shr, u128);
 
 checked_shift_impl!(CheckedShr, checked_shr, i8);
@@ -273,5 +258,4 @@
 checked_shift_impl!(CheckedShr, checked_shr, i32);
 checked_shift_impl!(CheckedShr, checked_shr, i64);
 checked_shift_impl!(CheckedShr, checked_shr, isize);
-#[cfg(has_i128)]
 checked_shift_impl!(CheckedShr, checked_shr, i128);
diff --git a/src/ops/euclid.rs b/src/ops/euclid.rs
index 99b5127..4547fee 100644
--- a/src/ops/euclid.rs
+++ b/src/ops/euclid.rs
@@ -116,12 +116,8 @@
     )*}
 }
 
-euclid_int_impl!(isize i8 i16 i32 i64);
-euclid_uint_impl!(usize u8 u16 u32 u64);
-#[cfg(has_i128)]
-euclid_int_impl!(i128);
-#[cfg(has_i128)]
-euclid_uint_impl!(u128);
+euclid_int_impl!(isize i8 i16 i32 i64 i128);
+euclid_uint_impl!(usize u8 u16 u32 u64 u128);
 
 #[cfg(all(has_div_euclid, feature = "std"))]
 euclid_forward_impl!(f32 f64);
@@ -130,7 +126,7 @@
 impl Euclid for f32 {
     #[inline]
     fn div_euclid(&self, v: &f32) -> f32 {
-        let q = <f32 as ::float::FloatCore>::trunc(self / v);
+        let q = <f32 as crate::float::FloatCore>::trunc(self / v);
         if self % v < 0.0 {
             return if *v > 0.0 { q - 1.0 } else { q + 1.0 };
         }
@@ -141,7 +137,7 @@
     fn rem_euclid(&self, v: &f32) -> f32 {
         let r = self % v;
         if r < 0.0 {
-            r + <f32 as ::float::FloatCore>::abs(*v)
+            r + <f32 as crate::float::FloatCore>::abs(*v)
         } else {
             r
         }
@@ -152,7 +148,7 @@
 impl Euclid for f64 {
     #[inline]
     fn div_euclid(&self, v: &f64) -> f64 {
-        let q = <f64 as ::float::FloatCore>::trunc(self / v);
+        let q = <f64 as crate::float::FloatCore>::trunc(self / v);
         if self % v < 0.0 {
             return if *v > 0.0 { q - 1.0 } else { q + 1.0 };
         }
@@ -163,7 +159,7 @@
     fn rem_euclid(&self, v: &f64) -> f64 {
         let r = self % v;
         if r < 0.0 {
-            r + <f64 as ::float::FloatCore>::abs(*v)
+            r + <f64 as crate::float::FloatCore>::abs(*v)
         } else {
             r
         }
@@ -251,12 +247,8 @@
     )*}
 }
 
-checked_euclid_int_impl!(isize i8 i16 i32 i64);
-checked_euclid_uint_impl!(usize u8 u16 u32 u64);
-#[cfg(has_i128)]
-checked_euclid_int_impl!(i128);
-#[cfg(has_i128)]
-checked_euclid_uint_impl!(u128);
+checked_euclid_int_impl!(isize i8 i16 i32 i64 i128);
+checked_euclid_uint_impl!(usize u8 u16 u32 u64 u128);
 
 #[cfg(test)]
 mod tests {
@@ -300,7 +292,7 @@
             };
         }
 
-        test_euclid!(isize i8 i16 i32 i64);
+        test_euclid!(isize i8 i16 i32 i64 i128);
     }
 
     #[test]
@@ -312,13 +304,13 @@
                         let x: $t = 12.1;
                         let y: $t = 3.2;
                         assert!(Euclid::div_euclid(&x, &y) * y + Euclid::rem_euclid(&x, &y) - x
-                        <= 46.4 * <$t as ::float::FloatCore>::epsilon());
+                        <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
                         assert!(Euclid::div_euclid(&x, &-y) * -y + Euclid::rem_euclid(&x, &-y) - x
-                        <= 46.4 * <$t as ::float::FloatCore>::epsilon());
+                        <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
                         assert!(Euclid::div_euclid(&-x, &y) * y + Euclid::rem_euclid(&-x, &y) + x
-                        <= 46.4 * <$t as ::float::FloatCore>::epsilon());
+                        <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
                         assert!(Euclid::div_euclid(&-x, &-y) * -y + Euclid::rem_euclid(&-x, &-y) + x
-                        <= 46.4 * <$t as ::float::FloatCore>::epsilon());
+                        <= 46.4 * <$t as crate::float::FloatCore>::epsilon());
                     }
                 )+
             };
@@ -342,6 +334,6 @@
             };
         }
 
-        test_euclid_checked!(isize i8 i16 i32 i64);
+        test_euclid_checked!(isize i8 i16 i32 i64 i128);
     }
 }
diff --git a/src/ops/mod.rs b/src/ops/mod.rs
index 585879f..2128d86 100644
--- a/src/ops/mod.rs
+++ b/src/ops/mod.rs
@@ -1,3 +1,4 @@
+pub mod bytes;
 pub mod checked;
 pub mod euclid;
 pub mod inv;
diff --git a/src/ops/mul_add.rs b/src/ops/mul_add.rs
index c5835d3..51beb55 100644
--- a/src/ops/mul_add.rs
+++ b/src/ops/mul_add.rs
@@ -24,13 +24,13 @@
     /// The resulting type after applying the fused multiply-add.
     type Output;
 
-    /// Performs the fused multiply-add operation.
+    /// Performs the fused multiply-add operation `(self * a) + b`
     fn mul_add(self, a: A, b: B) -> Self::Output;
 }
 
-/// The fused multiply-add assignment operation.
+/// The fused multiply-add assignment operation `*self = (*self * a) + b`
 pub trait MulAddAssign<A = Self, B = Self> {
-    /// Performs the fused multiply-add operation.
+    /// Performs the fused multiply-add assignment operation `*self = (*self * a) + b`
     fn mul_add_assign(&mut self, a: A, b: B);
 }
 
@@ -40,7 +40,7 @@
 
     #[inline]
     fn mul_add(self, a: Self, b: Self) -> Self::Output {
-        <Self as ::Float>::mul_add(self, a, b)
+        <Self as crate::Float>::mul_add(self, a, b)
     }
 }
 
@@ -50,7 +50,7 @@
 
     #[inline]
     fn mul_add(self, a: Self, b: Self) -> Self::Output {
-        <Self as ::Float>::mul_add(self, a, b)
+        <Self as crate::Float>::mul_add(self, a, b)
     }
 }
 
@@ -67,15 +67,14 @@
     )*}
 }
 
-mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
-#[cfg(has_i128)]
-mul_add_impl!(MulAdd for i128 u128);
+mul_add_impl!(MulAdd for isize i8 i16 i32 i64 i128);
+mul_add_impl!(MulAdd for usize u8 u16 u32 u64 u128);
 
 #[cfg(any(feature = "std", feature = "libm"))]
 impl MulAddAssign<f32, f32> for f32 {
     #[inline]
     fn mul_add_assign(&mut self, a: Self, b: Self) {
-        *self = <Self as ::Float>::mul_add(*self, a, b)
+        *self = <Self as crate::Float>::mul_add(*self, a, b)
     }
 }
 
@@ -83,7 +82,7 @@
 impl MulAddAssign<f64, f64> for f64 {
     #[inline]
     fn mul_add_assign(&mut self, a: Self, b: Self) {
-        *self = <Self as ::Float>::mul_add(*self, a, b)
+        *self = <Self as crate::Float>::mul_add(*self, a, b)
     }
 }
 
@@ -98,9 +97,8 @@
     )*}
 }
 
-mul_add_assign_impl!(MulAddAssign for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
-#[cfg(has_i128)]
-mul_add_assign_impl!(MulAddAssign for i128 u128);
+mul_add_assign_impl!(MulAddAssign for isize i8 i16 i32 i64 i128);
+mul_add_assign_impl!(MulAddAssign for usize u8 u16 u32 u64 u128);
 
 #[cfg(test)]
 mod tests {
diff --git a/src/ops/overflowing.rs b/src/ops/overflowing.rs
index 56118a0..c7a35a5 100644
--- a/src/ops/overflowing.rs
+++ b/src/ops/overflowing.rs
@@ -1,8 +1,6 @@
 use core::ops::{Add, Mul, Sub};
-#[cfg(has_i128)]
-use core::{i128, u128};
-use core::{i16, i32, i64, i8, isize};
-use core::{u16, u32, u64, u8, usize};
+use core::{i128, i16, i32, i64, i8, isize};
+use core::{u128, u16, u32, u64, u8, usize};
 
 macro_rules! overflowing_impl {
     ($trait_name:ident, $method:ident, $t:ty) => {
@@ -27,7 +25,6 @@
 overflowing_impl!(OverflowingAdd, overflowing_add, u32);
 overflowing_impl!(OverflowingAdd, overflowing_add, u64);
 overflowing_impl!(OverflowingAdd, overflowing_add, usize);
-#[cfg(has_i128)]
 overflowing_impl!(OverflowingAdd, overflowing_add, u128);
 
 overflowing_impl!(OverflowingAdd, overflowing_add, i8);
@@ -35,7 +32,6 @@
 overflowing_impl!(OverflowingAdd, overflowing_add, i32);
 overflowing_impl!(OverflowingAdd, overflowing_add, i64);
 overflowing_impl!(OverflowingAdd, overflowing_add, isize);
-#[cfg(has_i128)]
 overflowing_impl!(OverflowingAdd, overflowing_add, i128);
 
 /// Performs substraction with a flag for overflow.
@@ -50,7 +46,6 @@
 overflowing_impl!(OverflowingSub, overflowing_sub, u32);
 overflowing_impl!(OverflowingSub, overflowing_sub, u64);
 overflowing_impl!(OverflowingSub, overflowing_sub, usize);
-#[cfg(has_i128)]
 overflowing_impl!(OverflowingSub, overflowing_sub, u128);
 
 overflowing_impl!(OverflowingSub, overflowing_sub, i8);
@@ -58,7 +53,6 @@
 overflowing_impl!(OverflowingSub, overflowing_sub, i32);
 overflowing_impl!(OverflowingSub, overflowing_sub, i64);
 overflowing_impl!(OverflowingSub, overflowing_sub, isize);
-#[cfg(has_i128)]
 overflowing_impl!(OverflowingSub, overflowing_sub, i128);
 
 /// Performs multiplication with a flag for overflow.
@@ -73,7 +67,6 @@
 overflowing_impl!(OverflowingMul, overflowing_mul, u32);
 overflowing_impl!(OverflowingMul, overflowing_mul, u64);
 overflowing_impl!(OverflowingMul, overflowing_mul, usize);
-#[cfg(has_i128)]
 overflowing_impl!(OverflowingMul, overflowing_mul, u128);
 
 overflowing_impl!(OverflowingMul, overflowing_mul, i8);
@@ -81,7 +74,6 @@
 overflowing_impl!(OverflowingMul, overflowing_mul, i32);
 overflowing_impl!(OverflowingMul, overflowing_mul, i64);
 overflowing_impl!(OverflowingMul, overflowing_mul, isize);
-#[cfg(has_i128)]
 overflowing_impl!(OverflowingMul, overflowing_mul, i128);
 
 #[test]
diff --git a/src/ops/saturating.rs b/src/ops/saturating.rs
index e39cfd7..16a0045 100644
--- a/src/ops/saturating.rs
+++ b/src/ops/saturating.rs
@@ -28,9 +28,8 @@
     )*}
 }
 
-deprecated_saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
-#[cfg(has_i128)]
-deprecated_saturating_impl!(Saturating for i128 u128);
+deprecated_saturating_impl!(Saturating for isize i8 i16 i32 i64 i128);
+deprecated_saturating_impl!(Saturating for usize u8 u16 u32 u64 u128);
 
 macro_rules! saturating_impl {
     ($trait_name:ident, $method:ident, $t:ty) => {
@@ -55,7 +54,6 @@
 saturating_impl!(SaturatingAdd, saturating_add, u32);
 saturating_impl!(SaturatingAdd, saturating_add, u64);
 saturating_impl!(SaturatingAdd, saturating_add, usize);
-#[cfg(has_i128)]
 saturating_impl!(SaturatingAdd, saturating_add, u128);
 
 saturating_impl!(SaturatingAdd, saturating_add, i8);
@@ -63,7 +61,6 @@
 saturating_impl!(SaturatingAdd, saturating_add, i32);
 saturating_impl!(SaturatingAdd, saturating_add, i64);
 saturating_impl!(SaturatingAdd, saturating_add, isize);
-#[cfg(has_i128)]
 saturating_impl!(SaturatingAdd, saturating_add, i128);
 
 /// Performs subtraction that saturates at the numeric bounds instead of overflowing.
@@ -78,7 +75,6 @@
 saturating_impl!(SaturatingSub, saturating_sub, u32);
 saturating_impl!(SaturatingSub, saturating_sub, u64);
 saturating_impl!(SaturatingSub, saturating_sub, usize);
-#[cfg(has_i128)]
 saturating_impl!(SaturatingSub, saturating_sub, u128);
 
 saturating_impl!(SaturatingSub, saturating_sub, i8);
@@ -86,7 +82,6 @@
 saturating_impl!(SaturatingSub, saturating_sub, i32);
 saturating_impl!(SaturatingSub, saturating_sub, i64);
 saturating_impl!(SaturatingSub, saturating_sub, isize);
-#[cfg(has_i128)]
 saturating_impl!(SaturatingSub, saturating_sub, i128);
 
 /// Performs multiplication that saturates at the numeric bounds instead of overflowing.
@@ -101,7 +96,6 @@
 saturating_impl!(SaturatingMul, saturating_mul, u32);
 saturating_impl!(SaturatingMul, saturating_mul, u64);
 saturating_impl!(SaturatingMul, saturating_mul, usize);
-#[cfg(has_i128)]
 saturating_impl!(SaturatingMul, saturating_mul, u128);
 
 saturating_impl!(SaturatingMul, saturating_mul, i8);
@@ -109,7 +103,6 @@
 saturating_impl!(SaturatingMul, saturating_mul, i32);
 saturating_impl!(SaturatingMul, saturating_mul, i64);
 saturating_impl!(SaturatingMul, saturating_mul, isize);
-#[cfg(has_i128)]
 saturating_impl!(SaturatingMul, saturating_mul, i128);
 
 // TODO: add SaturatingNeg for signed integer primitives once the saturating_neg() API is stable.
diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs
index 265b8f3..3a8b331 100644
--- a/src/ops/wrapping.rs
+++ b/src/ops/wrapping.rs
@@ -32,7 +32,6 @@
 wrapping_impl!(WrappingAdd, wrapping_add, u32);
 wrapping_impl!(WrappingAdd, wrapping_add, u64);
 wrapping_impl!(WrappingAdd, wrapping_add, usize);
-#[cfg(has_i128)]
 wrapping_impl!(WrappingAdd, wrapping_add, u128);
 
 wrapping_impl!(WrappingAdd, wrapping_add, i8);
@@ -40,7 +39,6 @@
 wrapping_impl!(WrappingAdd, wrapping_add, i32);
 wrapping_impl!(WrappingAdd, wrapping_add, i64);
 wrapping_impl!(WrappingAdd, wrapping_add, isize);
-#[cfg(has_i128)]
 wrapping_impl!(WrappingAdd, wrapping_add, i128);
 
 /// Performs subtraction that wraps around on overflow.
@@ -55,7 +53,6 @@
 wrapping_impl!(WrappingSub, wrapping_sub, u32);
 wrapping_impl!(WrappingSub, wrapping_sub, u64);
 wrapping_impl!(WrappingSub, wrapping_sub, usize);
-#[cfg(has_i128)]
 wrapping_impl!(WrappingSub, wrapping_sub, u128);
 
 wrapping_impl!(WrappingSub, wrapping_sub, i8);
@@ -63,7 +60,6 @@
 wrapping_impl!(WrappingSub, wrapping_sub, i32);
 wrapping_impl!(WrappingSub, wrapping_sub, i64);
 wrapping_impl!(WrappingSub, wrapping_sub, isize);
-#[cfg(has_i128)]
 wrapping_impl!(WrappingSub, wrapping_sub, i128);
 
 /// Performs multiplication that wraps around on overflow.
@@ -78,7 +74,6 @@
 wrapping_impl!(WrappingMul, wrapping_mul, u32);
 wrapping_impl!(WrappingMul, wrapping_mul, u64);
 wrapping_impl!(WrappingMul, wrapping_mul, usize);
-#[cfg(has_i128)]
 wrapping_impl!(WrappingMul, wrapping_mul, u128);
 
 wrapping_impl!(WrappingMul, wrapping_mul, i8);
@@ -86,7 +81,6 @@
 wrapping_impl!(WrappingMul, wrapping_mul, i32);
 wrapping_impl!(WrappingMul, wrapping_mul, i64);
 wrapping_impl!(WrappingMul, wrapping_mul, isize);
-#[cfg(has_i128)]
 wrapping_impl!(WrappingMul, wrapping_mul, i128);
 
 macro_rules! wrapping_unary_impl {
@@ -127,14 +121,12 @@
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, u32);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, u64);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, usize);
-#[cfg(has_i128)]
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, u128);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, i8);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, i16);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, i32);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, i64);
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, isize);
-#[cfg(has_i128)]
 wrapping_unary_impl!(WrappingNeg, wrapping_neg, i128);
 
 macro_rules! wrapping_shift_impl {
@@ -172,7 +164,6 @@
 wrapping_shift_impl!(WrappingShl, wrapping_shl, u32);
 wrapping_shift_impl!(WrappingShl, wrapping_shl, u64);
 wrapping_shift_impl!(WrappingShl, wrapping_shl, usize);
-#[cfg(has_i128)]
 wrapping_shift_impl!(WrappingShl, wrapping_shl, u128);
 
 wrapping_shift_impl!(WrappingShl, wrapping_shl, i8);
@@ -180,7 +171,6 @@
 wrapping_shift_impl!(WrappingShl, wrapping_shl, i32);
 wrapping_shift_impl!(WrappingShl, wrapping_shl, i64);
 wrapping_shift_impl!(WrappingShl, wrapping_shl, isize);
-#[cfg(has_i128)]
 wrapping_shift_impl!(WrappingShl, wrapping_shl, i128);
 
 /// Performs a right shift that does not panic.
@@ -207,7 +197,6 @@
 wrapping_shift_impl!(WrappingShr, wrapping_shr, u32);
 wrapping_shift_impl!(WrappingShr, wrapping_shr, u64);
 wrapping_shift_impl!(WrappingShr, wrapping_shr, usize);
-#[cfg(has_i128)]
 wrapping_shift_impl!(WrappingShr, wrapping_shr, u128);
 
 wrapping_shift_impl!(WrappingShr, wrapping_shr, i8);
@@ -215,7 +204,6 @@
 wrapping_shift_impl!(WrappingShr, wrapping_shr, i32);
 wrapping_shift_impl!(WrappingShr, wrapping_shr, i64);
 wrapping_shift_impl!(WrappingShr, wrapping_shr, isize);
-#[cfg(has_i128)]
 wrapping_shift_impl!(WrappingShr, wrapping_shr, i128);
 
 // Well this is a bit funny, but all the more appropriate.
@@ -297,8 +285,7 @@
     assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0);
     assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0);
     assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0);
-    // TODO: Test for Wrapping::Neg. Not possible yet since core::ops::Neg was
-    // only added to core::num::Wrapping<_> in Rust 1.10.
+    assert_eq!(wrapping_neg(255), (-Wrapping(255u8)).0);
     assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0);
     assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0);
 }
@@ -321,8 +308,11 @@
     require_wrappingmul(&Wrapping(42));
 }
 
-// TODO: Test for Wrapping::Neg. Not possible yet since core::ops::Neg was
-// only added to core::num::Wrapping<_> in Rust 1.10.
+#[test]
+fn wrapping_is_wrappingneg() {
+    fn require_wrappingneg<T: WrappingNeg>(_: &T) {}
+    require_wrappingneg(&Wrapping(42));
+}
 
 #[test]
 fn wrapping_is_wrappingshl() {
diff --git a/src/pow.rs b/src/pow.rs
index 8addc21..ef51c95 100644
--- a/src/pow.rs
+++ b/src/pow.rs
@@ -1,6 +1,6 @@
+use crate::{CheckedMul, One};
 use core::num::Wrapping;
 use core::ops::Mul;
-use {CheckedMul, One};
 
 /// Binary operator for raising a value to a power.
 pub trait Pow<RHS> {
@@ -99,22 +99,14 @@
 pow_impl!(i64, u32, u32, i64::pow);
 pow_impl!(i64, usize);
 
-#[cfg(has_i128)]
 pow_impl!(u128, u8, u32, u128::pow);
-#[cfg(has_i128)]
 pow_impl!(u128, u16, u32, u128::pow);
-#[cfg(has_i128)]
 pow_impl!(u128, u32, u32, u128::pow);
-#[cfg(has_i128)]
 pow_impl!(u128, usize);
 
-#[cfg(has_i128)]
 pow_impl!(i128, u8, u32, i128::pow);
-#[cfg(has_i128)]
 pow_impl!(i128, u16, u32, i128::pow);
-#[cfg(has_i128)]
 pow_impl!(i128, u32, u32, i128::pow);
-#[cfg(has_i128)]
 pow_impl!(i128, usize);
 
 pow_impl!(usize, u8, u32, usize::pow);
@@ -133,9 +125,7 @@
 pow_impl!(Wrapping<i32>);
 pow_impl!(Wrapping<u64>);
 pow_impl!(Wrapping<i64>);
-#[cfg(has_i128)]
 pow_impl!(Wrapping<u128>);
-#[cfg(has_i128)]
 pow_impl!(Wrapping<i128>);
 pow_impl!(Wrapping<usize>);
 pow_impl!(Wrapping<isize>);
@@ -155,7 +145,7 @@
 #[cfg(any(feature = "std", feature = "libm"))]
 mod float_impls {
     use super::Pow;
-    use Float;
+    use crate::Float;
 
     pow_impl!(f32, i8, i32, <f32 as Float>::powi);
     pow_impl!(f32, u8, i32, <f32 as Float>::powi);
@@ -232,18 +222,8 @@
         return Some(T::one());
     }
 
-    macro_rules! optry {
-        ($expr:expr) => {
-            if let Some(val) = $expr {
-                val
-            } else {
-                return None;
-            }
-        };
-    }
-
     while exp & 1 == 0 {
-        base = optry!(base.checked_mul(&base));
+        base = base.checked_mul(&base)?;
         exp >>= 1;
     }
     if exp == 1 {
@@ -253,9 +233,9 @@
     let mut acc = base.clone();
     while exp > 1 {
         exp >>= 1;
-        base = optry!(base.checked_mul(&base));
+        base = base.checked_mul(&base)?;
         if exp & 1 == 1 {
-            acc = optry!(acc.checked_mul(&base));
+            acc = acc.checked_mul(&base)?;
         }
     }
     Some(acc)
diff --git a/src/real.rs b/src/real.rs
index 8b31cce..d4feee0 100644
--- a/src/real.rs
+++ b/src/real.rs
@@ -2,7 +2,7 @@
 
 use core::ops::Neg;
 
-use {Float, Num, NumCast};
+use crate::{Float, Num, NumCast};
 
 // NOTE: These doctests have the same issue as those in src/float.rs.
 // They're testing the inherent methods directly, and not those of `Real`.
diff --git a/src/sign.rs b/src/sign.rs
index 5c32071..a0d6b0f 100644
--- a/src/sign.rs
+++ b/src/sign.rs
@@ -1,8 +1,8 @@
 use core::num::Wrapping;
 use core::ops::Neg;
 
-use float::FloatCore;
-use Num;
+use crate::float::FloatCore;
+use crate::Num;
 
 /// Useful functions for signed numbers (i.e. numbers that can be negative).
 pub trait Signed: Sized + Num + Neg<Output = Self> {
@@ -72,10 +72,7 @@
     )*)
 }
 
-signed_impl!(isize i8 i16 i32 i64);
-
-#[cfg(has_i128)]
-signed_impl!(i128);
+signed_impl!(isize i8 i16 i32 i64 i128);
 
 impl<T: Signed> Signed for Wrapping<T>
 where
@@ -202,9 +199,7 @@
     )*)
 }
 
-empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
-#[cfg(has_i128)]
-empty_trait_impl!(Unsigned for u128);
+empty_trait_impl!(Unsigned for usize u8 u16 u32 u64 u128);
 
 impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
 
@@ -214,11 +209,8 @@
     require_unsigned(&Wrapping(42_u32));
 }
 
-// Commenting this out since it doesn't compile on Rust 1.8,
-// because on this version Wrapping doesn't implement Neg and therefore can't
-// implement Signed.
-// #[test]
-// fn signed_wrapping_is_signed() {
-//     fn require_signed<T: Signed>(_: &T) {}
-//     require_signed(&Wrapping(-42));
-// }
+#[test]
+fn signed_wrapping_is_signed() {
+    fn require_signed<T: Signed>(_: &T) {}
+    require_signed(&Wrapping(-42));
+}
diff --git a/tests/cast.rs b/tests/cast.rs
index 69310d0..4f01d74 100644
--- a/tests/cast.rs
+++ b/tests/cast.rs
@@ -1,21 +1,13 @@
 //! Tests of `num_traits::cast`.
 
-#![no_std]
-
-#[cfg(feature = "std")]
-#[macro_use]
-extern crate std;
-
-extern crate num_traits;
+#![cfg_attr(not(feature = "std"), no_std)]
 
 use num_traits::cast::*;
 use num_traits::Bounded;
 
 use core::{f32, f64};
-#[cfg(has_i128)]
-use core::{i128, u128};
-use core::{i16, i32, i64, i8, isize};
-use core::{u16, u32, u64, u8, usize};
+use core::{i128, i16, i32, i64, i8, isize};
+use core::{u128, u16, u32, u64, u8, usize};
 
 use core::fmt::Debug;
 use core::mem;
@@ -147,7 +139,6 @@
 }
 
 #[test]
-#[cfg(has_i128)]
 fn cast_to_i128_checks_overflow() {
     let big_f: f64 = 1.0e123;
     let normal_f: f64 = 1.0;
@@ -163,7 +154,7 @@
 }
 
 #[cfg(feature = "std")]
-fn dbg(args: ::core::fmt::Arguments) {
+fn dbg(args: ::core::fmt::Arguments<'_>) {
     println!("{}", args);
 }
 
@@ -180,9 +171,9 @@
         let small = if $t::MIN == 0 || mem::size_of::<$t>() < mem::size_of::<$f>() {
             $t::MIN as $f - 1.0
         } else {
-            ($t::MIN as $f).raw_offset(1).floor()
+            ($t::MIN as $f).raw_inc().floor()
         };
-        let fmin = small.raw_offset(-1);
+        let fmin = small.raw_dec();
         dbg!("  testing min {}\n\tvs. {:.0}\n\tand {:.0}", $t::MIN, fmin, small);
         assert_eq!(Some($t::MIN), cast::<$f, $t>($t::MIN as $f));
         assert_eq!(Some($t::MIN), cast::<$f, $t>(fmin));
@@ -192,11 +183,11 @@
             ($t::MAX, $t::MAX as $f + 1.0)
         } else {
             let large = $t::MAX as $f; // rounds up!
-            let max = large.raw_offset(-1) as $t; // the next smallest possible
+            let max = large.raw_dec() as $t; // the next smallest possible
             assert_eq!(max.count_ones(), $f::MANTISSA_DIGITS);
             (max, large)
         };
-        let fmax = large.raw_offset(-1);
+        let fmax = large.raw_dec();
         dbg!("  testing max {}\n\tvs. {:.0}\n\tand {:.0}", max, fmax, large);
         assert_eq!(Some(max), cast::<$f, $t>(max as $f));
         assert_eq!(Some(max), cast::<$f, $t>(fmax));
@@ -210,27 +201,27 @@
 }
 
 trait RawOffset: Sized {
-    type Raw;
-    fn raw_offset(self, offset: Self::Raw) -> Self;
+    fn raw_inc(self) -> Self;
+    fn raw_dec(self) -> Self;
 }
 
 impl RawOffset for f32 {
-    type Raw = i32;
-    fn raw_offset(self, offset: Self::Raw) -> Self {
-        unsafe {
-            let raw: Self::Raw = mem::transmute(self);
-            mem::transmute(raw + offset)
-        }
+    fn raw_inc(self) -> Self {
+        Self::from_bits(self.to_bits() + 1)
+    }
+
+    fn raw_dec(self) -> Self {
+        Self::from_bits(self.to_bits() - 1)
     }
 }
 
 impl RawOffset for f64 {
-    type Raw = i64;
-    fn raw_offset(self, offset: Self::Raw) -> Self {
-        unsafe {
-            let raw: Self::Raw = mem::transmute(self);
-            mem::transmute(raw + offset)
-        }
+    fn raw_inc(self) -> Self {
+        Self::from_bits(self.to_bits() + 1)
+    }
+
+    fn raw_dec(self) -> Self {
+        Self::from_bits(self.to_bits() - 1)
     }
 }
 
@@ -243,7 +234,6 @@
 }
 
 #[test]
-#[cfg(has_i128)]
 fn cast_float_to_i128_edge_cases() {
     float_test_edge!(f32 -> i128 u128);
     float_test_edge!(f64 -> i128 u128);
@@ -251,6 +241,7 @@
 
 macro_rules! int_test_edge {
     ($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({
+        #[allow(arithmetic_overflow)] // https://github.com/rust-lang/rust/issues/109731
         fn test_edge() {
             dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t));
 
@@ -302,7 +293,6 @@
 }
 
 #[test]
-#[cfg(has_i128)]
 fn cast_int_to_128_edge_cases() {
     use core::cmp::Ordering::*;