Compare commits

...

69 Commits

Author SHA1 Message Date
bors[bot] 2f0cffd522
Merge #99
99: Revive Float+Real in no_std thanks to libm r=cuviper a=yoanlcq

Greetings,

This is a hopeful fix for #75.  
Basically: Add `libm` as an optional dependency, and handle three possible cases depending on which features are enabled:
- std and libm: std is used;
- std and not libm: std is used;
- libm and not std: libm and FloatCore are used.

It was briefly mentioned that `libm` wasn't ready yet, but this was months ago, and I believe it is better not to wait for too long.  
If anything, bugs in `libm` should be fixed in `libm`; `num-traits` is only delegating its implementations to it; not to mention that the more `libm` is used, the likelier issues are to be found and hopefully fixed.

Thanks in advance!

Co-authored-by: Yoan Lecoq <yoanlecoq.io@gmail.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-09-30 16:39:17 +00:00
bors[bot] 4fc3d8f72d
Merge #128
128: Fix unstable_name_collisions in Bounded for Wrapping r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-09-27 18:43:44 +00:00
Josh Stone 06b3f854d4 Fix unstable_name_collisions in Bounded for Wrapping 2019-09-27 11:07:25 -07:00
bors[bot] 5b9f6e4c47
Merge #127
127: Relax EPSILON comparisons in mul_add tests r=cuviper a=cuviper

Closes #124.

Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-09-27 18:02:41 +00:00
Josh Stone 93328dfc90 Add libm to no_std CI 2019-09-27 10:56:03 -07:00
Josh Stone c4256bd4df Don't use libm at all with std 2019-09-27 10:53:17 -07:00
Josh Stone b64ee3809c Use a single global guard in mod real 2019-09-27 10:53:17 -07:00
Josh Stone 27b9202ff3 Raise the minimum libm
Needed for some additional methods and correct overflow behavior.
2019-09-27 10:53:17 -07:00
Yoan Lecoq f050c60df9 Reference PR 99 in README 2019-09-27 10:53:17 -07:00
Yoan Lecoq 2d113f56c8 Indicate that libm feature only builds on latest Rust 2019-09-27 10:53:17 -07:00
Yoan Lecoq 63047365be CI: make the condition for testing libm the same as u128/i128 2019-09-27 10:53:17 -07:00
Yoan Lecoq 0547a355ee Run cargo fmt --all 2019-09-27 10:53:17 -07:00
Yoan Lecoq 4b1ea5fb12 Guard Real trait definition like its blanket impl for Float 2019-09-27 10:53:17 -07:00
Yoan Lecoq 1b28e6182d Add space before triple backticks 2019-09-27 10:53:17 -07:00
Yoan Lecoq 55c5b7455a CI: test with libm 2019-09-27 10:53:17 -07:00
Yoan Lecoq c28e2fe062 Real: Ignore doc tests if Float is disabled 2019-09-27 10:53:17 -07:00
Yoan Lecoq aaf3c267bd Real: Run doc-tests only if Float is enabled 2019-09-27 10:53:17 -07:00
Yoan Lecoq 849e2a0b1b Always enable Real, feature gate Float - Real forwarding 2019-09-27 10:53:17 -07:00
Yoan Lecoq 4234eb76aa libm fallback for Pow, factorize MulAdd 2019-09-27 10:53:17 -07:00
Yoan Lecoq 4d3cb0a4ba Impl MulAdd+MulAssign with libm fallback 2019-09-27 10:53:17 -07:00
Yoan Lecoq f523f532e6 Update README 2019-09-27 10:53:17 -07:00
Yoan Lecoq b4558d1c49 Make it compile on 1.8.0 2019-09-27 10:53:17 -07:00
Yoan Lecoq fec6c3610c Revive Float+Real in no_std with libm 2019-09-27 10:53:17 -07:00
bors[bot] d394467906
Merge #135
135: Debug-panic in clamp_min/max if min/max is NAN r=cuviper a=jturner314

This also improves the docs for `clamp`, `clamp_min`, and `clamp_max`.

Closes #134.

Co-authored-by: Jim Turner <git@turner.link>
2019-09-24 20:03:31 +00:00
Jim Turner 987ed8fd38 Split clamp panicking test into separate tests 2019-09-23 22:21:33 -04:00
Jim Turner d02f166765 Restrict panic testing to when std is enabled 2019-09-23 22:14:03 -04:00
Jim Turner 33b74618b6 Debug-panic in clamp_min/max if min/max is NAN
This also improves the docs for `clamp`, `clamp_min`, and `clamp_max`.
2019-09-23 20:59:34 -04:00
bors[bot] 428f89a7d5
Merge #122
122: NAN preserving clamp_lower/upper r=cuviper a=termoshtt

`NAN` preserving lower- and upper-clamp.

Cc: https://github.com/rust-ndarray/ndarray/issues/470#issuecomment-521809782

Co-authored-by: Toshiki Teramura <toshiki.teramura@gmail.com>
2019-09-14 18:23:57 +00:00
Toshiki Teramura 0e7c2a4a00 s/less/greater/g 2019-09-14 15:59:10 +09:00
bors[bot] 3add713434
Merge #132
132: Add comments explaining why transmutes are safe r=cuviper a=Shnatsel

Add comments explaining why transmutes are safe so that people auditing unsafe code don't have to spend time figuring it out by themselves.

Co-authored-by: Sergey "Shnatsel" Davidoff <sdavydov@google.com>
2019-09-09 17:42:57 +00:00
Sergey "Shnatsel" Davidoff 40898e5071
Add comments explaining why transmutes are safe 2019-09-08 15:12:21 +02:00
Toshiki Teramura 973ba72e4f Fix doc comment 2019-08-31 15:34:40 +09:00
Toshiki Teramura e7ba9b62dc Replace lower/upper to min/max 2019-08-31 15:31:30 +09:00
Toshiki Teramura 2fb8a6e8a9 Add NaN preserving test for clamp 2019-08-31 15:14:49 +09:00
Josh Stone b8906eff1b Add i586 to CI 2019-08-30 15:54:41 -07:00
Josh Stone 7a61e79757 Relax EPSILON comparisons in mul_add tests 2019-08-30 15:24:38 -07:00
bors[bot] 45067c1357
Merge #126
126: Fix num parsing for invalid multi-byte sign chars r=cuviper a=HeroicKatora

Ensure that splitting the potential sign character from the remainder
respects UTF8 boundaries. This lets invalid characters fail correctly
with an error, instead of panicking.

Closes: #125 

Co-authored-by: Andreas Molzer <andreas.molzer@gmx.de>
2019-08-30 21:26:40 +00:00
Andreas Molzer cd0da1ae5e Fix num parsing for invalid multi-byte sign chars
Ensure that splitting the potential sign character from the remainder
respects UTF8 boundaries. This lets invalid characters fail correctly
with an error, instead of panicking.
2019-08-30 22:27:32 +02:00
Toshiki Teramura f20d74fce8 Use core::f32 instead of std::f32 2019-08-17 17:58:02 +09:00
Toshiki Teramura e8dce19146 Add clamp_{lower,upper} 2019-08-17 16:45:04 +09:00
bors[bot] 58f02a8677 Merge #119
119: Doc fixes r=cuviper a=waywardmonkeys



Co-authored-by: Bruce Mitchener <bruce.mitchener@gmail.com>
2019-07-09 17:13:44 +00:00
Bruce Mitchener d1f5658bfe Typo fixes. 2019-07-09 17:50:59 +07:00
Bruce Mitchener 107a326745 Missing backticks. 2019-07-09 17:50:50 +07:00
bors[bot] 84e14d4f36 Merge #116
116: bump autocfg to fix no_std probing r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-05-22 00:47:08 +00:00
Josh Stone 2c2cfe1bf3 Release 0.2.8 2019-05-21 17:46:08 -07:00
Josh Stone a194d91625 bump autocfg to fix no_std probing 2019-05-21 17:38:28 -07:00
bors[bot] 8e765ee1ff Merge #114
114: Release 0.2.7 r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-05-20 20:21:48 +00:00
Josh Stone 6d62b6a228 Release 0.2.7 2019-05-20 13:16:20 -07:00
bors[bot] 852ec9380f Merge #113
113: Use autocfg to probe for i128 r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-05-11 00:00:41 +00:00
Josh Stone 615d83a5b6 Use autocfg to probe for i128 2019-05-10 16:42:23 -07:00
bors[bot] 38655c91c1 Merge #110
110: Check formatting in CI r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-04-16 21:39:50 +00:00
Josh Stone a1688f6991 Check formatting in CI 2019-04-16 14:32:21 -07:00
Josh Stone c38b4b601d cargo fmt 2019-04-16 14:30:46 -07:00
bors[bot] 4ab251b0a2 Merge #108
108: int: document PrimInt trait r=cuviper a=dvdhrm

This documents the PrimInt trait, explains its intentions and features
as well as mentions its origins for future reference.

Closes #11.

Co-authored-by: David Rheinsberg <david.rheinsberg@gmail.com>
2019-03-28 20:41:04 +00:00
bors[bot] 5404658360 Merge #104
104: Add inplace methods to `Zero` and `One` r=cuviper a=lcnr

Adds the following default implemented methods to `Zero` and `One`:

```rust
fn set_zero(&mut self) {
    *self = Zero::zero();
}
```

```rust
fn set_one(&mut self) {
    *self = One::one();
}
```

This allows for reuse of BigNums.


Co-authored-by: lcnr/Bastian Kauschke <bastian_kauschke@hotmail.de>
Co-authored-by: Josh Stone <cuviper@gmail.com>
2019-03-28 19:31:51 +00:00
Josh Stone 09e27abaa0 Remove a stale doc comment on `set_zero()` 2019-03-28 12:30:22 -07:00
lcnr/Bastian Kauschke 87d4dbc418 do not return &mut Self in set_one/zero 2019-03-26 17:39:11 +01:00
David Rheinsberg 398c298fa9 int: document PrimInt trait
This documents the PrimInt trait, explains its intentions and features
as well as mentions its origins for future reference.
2019-03-15 11:16:59 +01:00
bors[bot] 8915b74ae4 Merge #105
105: fix unsigned_shr docs r=cuviper a=lcnr



Co-authored-by: lcnr/Bastian Kauschke <bastian_kauschke@hotmail.de>
2019-03-07 19:06:33 +00:00
lcnr/Bastian Kauschke 9cd2422221 fix 2019-03-07 17:22:19 +01:00
lcnr/Bastian Kauschke d2a1e035ad update 2019-03-07 17:07:07 +01:00
lcnr/Bastian Kauschke 8ac6a62a6e fix unsigned_shr docs 2019-03-06 12:47:12 +01:00
lcnr/Bastian Kauschke f06893feb0 remove mem::replace 2019-03-06 12:40:05 +01:00
lcnr/Bastian Kauschke 80052795ba fix 2019-03-05 14:45:54 +01:00
lcnr/Bastian Kauschke f3869040c7 add to_zero/one to Zero/One 2019-03-05 14:34:49 +01:00
bors[bot] d668985fae Merge #92
92: exclude CI files from crates.io r=cuviper a=ignatenkobrain



Co-authored-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2018-10-31 19:14:02 +00:00
Igor Gnatenko ff45e00849
exclude CI files from crates.io 2018-10-31 11:24:01 +01:00
bors[bot] 2925f10f40 Merge #90
90: Fix CheckedShl/CheckedShr documentation r=cuviper a=samueltardieu

Fix #57 and more:

- CheckedShl was hinting that None was returned on overflow rather than
  on too large a rhs.
- Ditto for CheckedShr.
- CheckedShr documentation erroneously indicated that a left shift was
  going to be performed instead of a right shift.

Co-authored-by: Samuel Tardieu <sam@rfc1149.net>
2018-10-09 19:23:03 +00:00
Samuel Tardieu fc4f1afdf6 Fix CheckedShl/CheckedShr documentation
Fix #57 and more:

- CheckedShl was hinting that None was returned on overflow rather than
  on too large a rhs.
- Ditto for CheckedShr.
- CheckedShr documentation erroneously indicated that a left shift was
  going to be performed instead of a right shift.
2018-10-09 11:55:18 +02:00
17 changed files with 402 additions and 130 deletions

View File

@ -1,15 +1,46 @@
language: rust
sudo: false
rust:
- 1.8.0
- 1.15.0
- 1.20.0
- 1.26.0 # has_i128
- 1.31.0 # 2018!
- stable
- beta
- nightly
sudo: false
script:
- cargo build --verbose
- ./ci/test_full.sh
matrix:
include:
# i586 presents floating point challenges for lack of SSE/SSE2
- name: "i586"
rust: stable
env: TARGET=i586-unknown-linux-gnu
addons:
apt:
packages:
- gcc-multilib
before_script:
- rustup target add $TARGET
script:
- cargo test --verbose --target $TARGET --all-features
# try a target that doesn't have std at all
- name: "no_std"
rust: stable
env: TARGET=thumbv6m-none-eabi
before_script:
- rustup target add $TARGET
script:
- cargo build --verbose --target $TARGET --no-default-features --features i128
- cargo build --verbose --target $TARGET --no-default-features --features libm
- name: "rustfmt"
rust: 1.31.0
before_script:
- rustup component add rustfmt
script:
- cargo fmt --all -- --check
notifications:
email:
on_success: never

View File

@ -8,16 +8,21 @@ categories = ["algorithms", "science", "no-std"]
license = "MIT/Apache-2.0"
repository = "https://github.com/rust-num/num-traits"
name = "num-traits"
version = "0.2.6"
version = "0.2.8"
readme = "README.md"
build = "build.rs"
exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
[package.metadata.docs.rs]
features = ["std"]
[dependencies]
libm = { version = "0.1.4", optional = true }
[features]
default = ["std"]
std = []
i128 = []
[build-dependencies]
autocfg = "0.1.3"

View File

@ -31,11 +31,14 @@ the default `std` feature. Use this in `Cargo.toml`:
[dependencies.num-traits]
version = "0.2"
default-features = false
# features = ["libm"] # <--- Uncomment if you wish to use `Float` and `Real` without `std`
```
The `Float` and `Real` traits are only available when `std` is enabled. The
`FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
and `f64` also require `std`, as do implementations of signed and floating-
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

View File

@ -1,3 +1,24 @@
# Release 0.2.8 (2019-05-21)
- [Fixed feature detection on `no_std` targets][116].
**Contributors**: @cuviper
[116]: https://github.com/rust-num/num-traits/pull/116
# Release 0.2.7 (2019-05-20)
- [Documented when `CheckedShl` and `CheckedShr` return `None`][90].
- [The new `Zero::set_zero` and `One::set_one`][104] will set values to their
identities in place, possibly optimized better than direct assignment.
- [Documented general features and intentions of `PrimInt`][108].
**Contributors**: @cuviper, @dvdhrm, @ignatenkobrain, @lcnr, @samueltardieu
[90]: https://github.com/rust-num/num-traits/pull/90
[104]: https://github.com/rust-num/num-traits/pull/104
[108]: https://github.com/rust-num/num-traits/pull/108
# Release 0.2.6 (2018-09-13)
- [Documented that `pow(0, 0)` returns `1`][79]. Mathematically, this is not

View File

@ -1,35 +1,14 @@
extern crate autocfg;
use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
fn main() {
if probe("fn main() { 0i128; }") {
let ac = autocfg::new();
if ac.probe_type("i128") {
println!("cargo:rustc-cfg=has_i128");
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
panic!("i128 support was not detected!");
}
}
/// Test if a code snippet can be compiled
fn probe(code: &str) -> bool {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");
let mut child = Command::new(rustc)
.arg("--out-dir")
.arg(out_dir)
.arg("--emit=obj")
.arg("-")
.stdin(Stdio::piped())
.spawn()
.expect("rustc probe");
child
.stdin
.as_mut()
.expect("rustc stdin")
.write_all(code.as_bytes())
.expect("write rustc stdin");
child.wait().expect("rustc probe").success()
autocfg::rerun_path(file!());
}

View File

@ -12,8 +12,16 @@ cargo test --verbose
cargo build --verbose --no-default-features
cargo test --verbose --no-default-features
# test `i128`
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then
# test `i128`
cargo build --verbose --features=i128
cargo test --verbose --features=i128
# test with std and libm (libm build fails on Rust 1.26 and earlier)
cargo build --verbose --features "libm"
cargo test --verbose --features "libm"
# test `no_std` with libm (libm build fails on Rust 1.26 and earlier)
cargo build --verbose --no-default-features --features "libm"
cargo test --verbose --no-default-features --features "libm"
fi

View File

@ -95,8 +95,8 @@ fn wrapping_bounded() {
macro_rules! test_wrapping_bounded {
($($t:ty)+) => {
$(
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
)+
};
}
@ -110,8 +110,8 @@ fn wrapping_bounded_i128() {
macro_rules! test_wrapping_bounded {
($($t:ty)+) => {
$(
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
)+
};
}

View File

@ -682,7 +682,7 @@ impl<T: NumCast> NumCast for Wrapping<T> {
/// A generic interface for casting between machine scalars with the
/// `as` operator, which admits narrowing and precision loss.
/// Implementers of this trait AsPrimitive should behave like a primitive
/// Implementers of this trait `AsPrimitive` should behave like a primitive
/// numeric type (e.g. a newtype around another primitive), and the
/// intended conversion must never fail.
///

View File

@ -7,6 +7,9 @@ use core::f64;
use {Num, NumCast, ToPrimitive};
#[cfg(all(not(feature = "std"), feature = "libm"))]
use libm::{F32Ext, F64Ext};
/// Generic trait for floating point numbers that works with `no_std`.
///
/// This trait implements a subset of the `Float` trait.
@ -766,6 +769,8 @@ impl FloatCore for f32 {
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,
@ -838,6 +843,8 @@ impl FloatCore for f64 {
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,
@ -893,8 +900,8 @@ impl FloatCore for f64 {
/// Generic trait for floating point numbers
///
/// This trait is only available with the `std` feature.
#[cfg(feature = "std")]
/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
#[cfg(any(feature = "std", feature = "libm"))]
pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// Returns the `NaN` value.
///
@ -1802,7 +1809,7 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
}
#[cfg(feature = "std")]
macro_rules! float_impl {
macro_rules! float_impl_std {
($T:ident $decode:ident) => {
impl Float for $T {
constant! {
@ -1880,7 +1887,88 @@ macro_rules! float_impl {
};
}
#[cfg(all(not(feature = "std"), feature = "libm"))]
macro_rules! float_impl_libm {
($T:ident $decode:ident $LibmImpl:ident) => {
impl Float for $T {
constant! {
nan() -> $T::NAN;
infinity() -> $T::INFINITY;
neg_infinity() -> $T::NEG_INFINITY;
neg_zero() -> -0.0;
min_value() -> $T::MIN;
min_positive_value() -> $T::MIN_POSITIVE;
epsilon() -> $T::EPSILON;
max_value() -> $T::MAX;
}
#[inline]
#[allow(deprecated)]
fn abs_sub(self, other: Self) -> Self {
<$T as $LibmImpl>::fdim(self, other)
}
#[inline]
fn integer_decode(self) -> (u64, i16, i8) {
$decode(self)
}
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;
$LibmImpl::floor(self) -> Self;
$LibmImpl::ceil(self) -> Self;
$LibmImpl::round(self) -> Self;
$LibmImpl::trunc(self) -> Self;
$LibmImpl::fract(self) -> Self;
$LibmImpl::abs(self) -> Self;
FloatCore::signum(self) -> Self;
FloatCore::is_sign_positive(self) -> bool;
FloatCore::is_sign_negative(self) -> bool;
$LibmImpl::mul_add(self, a: Self, b: Self) -> Self;
FloatCore::recip(self) -> Self;
FloatCore::powi(self, n: i32) -> Self;
$LibmImpl::powf(self, n: Self) -> Self;
$LibmImpl::sqrt(self) -> Self;
$LibmImpl::exp(self) -> Self;
$LibmImpl::exp2(self) -> Self;
$LibmImpl::ln(self) -> Self;
$LibmImpl::log(self, base: Self) -> Self;
$LibmImpl::log2(self) -> Self;
$LibmImpl::log10(self) -> Self;
FloatCore::to_degrees(self) -> Self;
FloatCore::to_radians(self) -> Self;
FloatCore::max(self, other: Self) -> Self;
FloatCore::min(self, other: Self) -> Self;
$LibmImpl::cbrt(self) -> Self;
$LibmImpl::hypot(self, other: Self) -> Self;
$LibmImpl::sin(self) -> Self;
$LibmImpl::cos(self) -> Self;
$LibmImpl::tan(self) -> Self;
$LibmImpl::asin(self) -> Self;
$LibmImpl::acos(self) -> Self;
$LibmImpl::atan(self) -> Self;
$LibmImpl::atan2(self, other: Self) -> Self;
$LibmImpl::sin_cos(self) -> (Self, Self);
$LibmImpl::exp_m1(self) -> Self;
$LibmImpl::ln_1p(self) -> Self;
$LibmImpl::sinh(self) -> Self;
$LibmImpl::cosh(self) -> Self;
$LibmImpl::tanh(self) -> Self;
$LibmImpl::asinh(self) -> Self;
$LibmImpl::acosh(self) -> Self;
$LibmImpl::atanh(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 sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
@ -1895,6 +1983,8 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
}
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 sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
@ -1909,9 +1999,14 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
}
#[cfg(feature = "std")]
float_impl!(f32 integer_decode_f32);
float_impl_std!(f32 integer_decode_f32);
#[cfg(feature = "std")]
float_impl!(f64 integer_decode_f64);
float_impl_std!(f64 integer_decode_f64);
#[cfg(all(not(feature = "std"), feature = "libm"))]
float_impl_libm!(f32 integer_decode_f32 F32Ext);
#[cfg(all(not(feature = "std"), feature = "libm"))]
float_impl_libm!(f64 integer_decode_f64 F64Ext);
macro_rules! float_const_impl {
($(#[$doc:meta] $constant:ident,)+) => (
@ -1994,7 +2089,7 @@ mod tests {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
#[test]
fn convert_deg_rad_std() {
for &(deg, rad) in &DEG_RAD_PAIRS {

View File

@ -2,16 +2,15 @@ use core::num::Wrapping;
use core::ops::{Add, Mul};
/// Defines an additive identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// a + 0 = a ∀ a ∈ Self
/// 0 + a = a ∀ a ∈ Self
/// ```
pub trait Zero: Sized + Add<Self, Output = Self> {
/// Returns the additive identity element of `Self`, `0`.
///
/// # Laws
///
/// ```{.text}
/// a + 0 = a ∀ a ∈ Self
/// 0 + a = a ∀ a ∈ Self
/// ```
///
/// # Purity
///
/// This function should return the same result at all times regardless of
@ -20,6 +19,11 @@ pub trait Zero: Sized + Add<Self, Output = Self> {
// This cannot be an associated constant, because of bignums.
fn zero() -> Self;
/// Sets `self` to the additive identity element of `Self`, `0`.
fn set_zero(&mut self) {
*self = Zero::zero();
}
/// Returns `true` if `self` is equal to the additive identity.
#[inline]
fn is_zero(&self) -> bool;
@ -66,22 +70,27 @@ where
fn is_zero(&self) -> bool {
self.0.is_zero()
}
fn set_zero(&mut self) {
self.0.set_zero();
}
fn zero() -> Self {
Wrapping(T::zero())
}
}
/// Defines a multiplicative identity element for `Self`.
///
/// # Laws
///
/// ```{.text}
/// a * 1 = a ∀ a ∈ Self
/// 1 * a = a ∀ a ∈ Self
/// ```
pub trait One: Sized + Mul<Self, Output = Self> {
/// Returns the multiplicative identity element of `Self`, `1`.
///
/// # Laws
///
/// ```{.text}
/// a * 1 = a ∀ a ∈ Self
/// 1 * a = a ∀ a ∈ Self
/// ```
///
/// # Purity
///
/// This function should return the same result at all times regardless of
@ -90,6 +99,11 @@ pub trait One: Sized + Mul<Self, Output = Self> {
// This cannot be an associated constant, because of bignums.
fn one() -> Self;
/// Sets `self` to the multiplicative identity element of `Self`, `1`.
fn set_one(&mut self) {
*self = One::one();
}
/// Returns `true` if `self` is equal to the multiplicative identity.
///
/// For performance reasons, it's best to implement this manually.
@ -111,6 +125,10 @@ macro_rules! one_impl {
fn one() -> $t {
$v
}
#[inline]
fn is_one(&self) -> bool {
*self == $v
}
}
};
}
@ -138,6 +156,10 @@ impl<T: One> One for Wrapping<T>
where
Wrapping<T>: Mul<Output = Wrapping<T>>,
{
fn set_one(&mut self) {
self.0.set_one();
}
fn one() -> Self {
Wrapping(T::one())
}

View File

@ -5,6 +5,32 @@ use ops::checked::*;
use ops::saturating::Saturating;
use {Num, NumCast};
/// Generic trait for primitive integers.
///
/// The `PrimInt` trait is an abstraction over the builtin primitive integer types (e.g., `u8`,
/// `u32`, `isize`, `i128`, ...). It inherits the basic numeric traits and extends them with
/// bitwise operators and non-wrapping arithmetic.
///
/// The trait explicitly inherits `Copy`, `Eq`, `Ord`, and `Sized`. The intention is that all
/// types implementing this trait behave like primitive types that are passed by value by default
/// and behave like builtin integers. Furthermore, the types are expected to expose the integer
/// value in binary representation and support bitwise operators. The standard bitwise operations
/// (e.g., bitwise-and, bitwise-or, right-shift, left-shift) are inherited and the trait extends
/// these with introspective queries (e.g., `PrimInt::count_ones()`, `PrimInt::leading_zeros()`),
/// bitwise combinators (e.g., `PrimInt::rotate_left()`), and endianness converters (e.g.,
/// `PrimInt::to_be()`).
///
/// All `PrimInt` types are expected to be fixed-width binary integers. The width can be queried
/// via `T::zero().count_zeros()`. The trait currently lacks a way to query the width at
/// compile-time.
///
/// While a default implementation for all builtin primitive integers is provided, the trait is in
/// no way restricted to these. Other integer types that fulfil the requirements are free to
/// implement the trait was well.
///
/// This trait and many of the method names originate in the unstable `core::num::Int` trait from
/// the rust standard library. The original trait was never stabilized and thus removed from the
/// standard library.
pub trait PrimInt:
Sized
+ Copy
@ -171,10 +197,10 @@ pub trait PrimInt:
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0xFEDCBA9876543210i64;
/// let m = 0x000FEDCBA9876543i64;
/// let n = -8i8; // 0b11111000
/// let m = 62i8; // 0b00111110
///
/// assert_eq!(n.unsigned_shr(12), m);
/// assert_eq!(n.unsigned_shr(2), m);
/// ```
fn unsigned_shr(self, n: u32) -> Self;

View File

@ -20,13 +20,17 @@
#[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;
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
pub use float::Float;
pub use float::FloatConst;
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
@ -53,7 +57,6 @@ pub mod identities;
pub mod int;
pub mod ops;
pub mod pow;
#[cfg(feature = "std")]
pub mod real;
pub mod sign;
@ -90,13 +93,12 @@ pub trait NumOps<Rhs = Self, Output = Self>:
{
}
impl<T, Rhs, Output> NumOps<Rhs, Output> for T
where
impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
T: Add<Rhs, Output = Output>
+ Sub<Rhs, Output = Output>
+ Mul<Rhs, Output = Output>
+ Div<Rhs, Output = Output>
+ Rem<Rhs, Output = Output>,
+ Rem<Rhs, Output = Output>
{
}
@ -105,22 +107,14 @@ where
///
/// This is automatically implemented for types which implement the operators.
pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
impl<T> NumRef for T
where
T: Num + for<'r> NumOps<&'r T>,
{
}
impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
/// The trait for references which implement numeric operations, taking the
/// second operand either by value or by reference.
///
/// This is automatically implemented for types which implement the operators.
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
impl<T, Base> RefNum<Base> for T
where
T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base>,
{
}
impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
/// The trait for types implementing numeric assignment operators (like `+=`).
///
@ -130,9 +124,8 @@ pub trait NumAssignOps<Rhs = Self>:
{
}
impl<T, Rhs> NumAssignOps<Rhs> for T
where
T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>,
impl<T, Rhs> NumAssignOps<Rhs> for T where
T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
{
}
@ -140,22 +133,14 @@ where
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssign: Num + NumAssignOps {}
impl<T> NumAssign for T
where
T: Num + NumAssignOps,
{
}
impl<T> NumAssign for T where T: Num + NumAssignOps {}
/// The trait for `NumAssign` types which also implement assignment operations
/// taking the second operand by reference.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
impl<T> NumAssignRef for T
where
T: NumAssign + for<'r> NumAssignOps<&'r T>,
{
}
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
macro_rules! int_trait_impl {
($name:ident for $($t:ty)*) => ($(
@ -234,7 +219,12 @@ macro_rules! float_trait_impl {
}
fn slice_shift_char(src: &str) -> Option<(char, &str)> {
src.chars().nth(0).map(|ch| (ch, &src[1..]))
let mut chars = src.chars();
if let Some(ch) = chars.next() {
Some((ch, chars.as_str()))
} else {
None
}
}
let (is_positive, src) = match slice_shift_char(src) {
@ -377,6 +367,8 @@ float_trait_impl!(Num for f32 f64);
/// If input is less than min then this returns min.
/// If input is greater than max then this returns max.
/// Otherwise this returns input.
///
/// **Panics** in debug mode if `!(min <= max)`.
#[inline]
pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
debug_assert!(min <= max, "min must be less than or equal to max");
@ -389,17 +381,97 @@ pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
}
}
/// A value bounded by a minimum value
///
/// If input is less than min then this returns min.
/// Otherwise this returns input.
/// `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
///
/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
#[inline]
pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
debug_assert!(min == min, "min must not be NAN");
if input < min {
min
} else {
input
}
}
/// A value bounded by a maximum value
///
/// If input is greater than max then this returns max.
/// Otherwise this returns input.
/// `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
///
/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
#[inline]
pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
debug_assert!(max == max, "max must not be NAN");
if input > max {
max
} else {
input
}
}
#[test]
fn clamp_test() {
// Int test
assert_eq!(1, clamp(1, -1, 2));
assert_eq!(-1, clamp(-2, -1, 2));
assert_eq!(2, clamp(3, -1, 2));
assert_eq!(1, clamp_min(1, -1));
assert_eq!(-1, clamp_min(-2, -1));
assert_eq!(-1, clamp_max(1, -1));
assert_eq!(-2, clamp_max(-2, -1));
// Float test
assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
assert_eq!(1.0, clamp_min(1.0, -1.0));
assert_eq!(-1.0, clamp_min(-2.0, -1.0));
assert_eq!(-1.0, clamp_max(1.0, -1.0));
assert_eq!(-2.0, clamp_max(-2.0, -1.0));
assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());
assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());
assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_nan_min() {
clamp(0., ::core::f32::NAN, 1.);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_nan_max() {
clamp(0., -1., ::core::f32::NAN);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_nan_min_max() {
clamp(0., ::core::f32::NAN, ::core::f32::NAN);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_min_nan_min() {
clamp_min(0., ::core::f32::NAN);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn clamp_max_nan_max() {
clamp_max(0., ::core::f32::NAN);
}
#[test]
@ -413,6 +485,15 @@ fn from_str_radix_unwrap() {
assert_eq!(f, 0.0);
}
#[test]
fn from_str_radix_multi_byte_fail() {
// Ensure parsing doesn't panic, even on invalid sign characters
assert!(f32::from_str_radix("™0.2", 10).is_err());
// Even when parsing the exponent sign
assert!(f32::from_str_radix("0.2E™1", 10).is_err());
}
#[test]
fn wrapping_is_num() {
fn require_num<T: Num>(_: &T) {}

View File

@ -195,10 +195,11 @@ 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 overflow.
/// Performs a left shift that returns `None` on shifts larger than
/// the type width.
pub trait CheckedShl: Sized + Shl<u32, Output = Self> {
/// Shifts a number to the left, checking for overflow. If overflow happens,
/// `None` is returned.
/// Checked shift left. Computes `self << rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
///
/// ```
/// use num_traits::CheckedShl;
@ -240,10 +241,11 @@ 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 overflow.
/// Performs a right shift that returns `None` on shifts larger than
/// the type width.
pub trait CheckedShr: Sized + Shr<u32, Output = Self> {
/// Shifts a number to the left, checking for overflow. If overflow happens,
/// `None` is returned.
/// Checked shift right. Computes `self >> rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
///
/// ```
/// use num_traits::CheckedShr;

View File

@ -18,7 +18,7 @@
/// // 100.0
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// assert!(abs_difference <= 100.0 * f32::EPSILON);
/// ```
pub trait MulAdd<A = Self, B = Self> {
/// The resulting type after applying the fused multiply-add.
@ -34,23 +34,23 @@ pub trait MulAddAssign<A = Self, B = Self> {
fn mul_add_assign(&mut self, a: A, b: B);
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
impl MulAdd<f32, f32> for f32 {
type Output = Self;
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self::Output {
f32::mul_add(self, a, b)
<Self as ::Float>::mul_add(self, a, b)
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
impl MulAdd<f64, f64> for f64 {
type Output = Self;
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self::Output {
f64::mul_add(self, a, b)
<Self as ::Float>::mul_add(self, a, b)
}
}
@ -71,19 +71,19 @@ 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);
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
impl MulAddAssign<f32, f32> for f32 {
#[inline]
fn mul_add_assign(&mut self, a: Self, b: Self) {
*self = f32::mul_add(*self, a, b)
*self = <Self as ::Float>::mul_add(*self, a, b)
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
impl MulAddAssign<f64, f64> for f64 {
#[inline]
fn mul_add_assign(&mut self, a: Self, b: Self) {
*self = f64::mul_add(*self, a, b)
*self = <Self as ::Float>::mul_add(*self, a, b)
}
}
@ -140,7 +140,7 @@ mod tests {
let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs();
assert!(abs_difference <= $t::EPSILON);
assert!(abs_difference <= 46.4 * $t::EPSILON);
}
)+
};

View File

@ -152,28 +152,29 @@ pow_impl!(Wrapping<isize>);
// pow_impl!(usize, u64);
// pow_impl!(isize, u64);
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "libm"))]
mod float_impls {
use super::Pow;
use Float;
pow_impl!(f32, i8, i32, f32::powi);
pow_impl!(f32, u8, i32, f32::powi);
pow_impl!(f32, i16, i32, f32::powi);
pow_impl!(f32, u16, i32, f32::powi);
pow_impl!(f32, i32, i32, f32::powi);
pow_impl!(f64, i8, i32, f64::powi);
pow_impl!(f64, u8, i32, f64::powi);
pow_impl!(f64, i16, i32, f64::powi);
pow_impl!(f64, u16, i32, f64::powi);
pow_impl!(f64, i32, i32, f64::powi);
pow_impl!(f32, f32, f32, f32::powf);
pow_impl!(f64, f32, f64, f64::powf);
pow_impl!(f64, f64, f64, f64::powf);
pow_impl!(f32, i8, i32, <f32 as Float>::powi);
pow_impl!(f32, u8, i32, <f32 as Float>::powi);
pow_impl!(f32, i16, i32, <f32 as Float>::powi);
pow_impl!(f32, u16, i32, <f32 as Float>::powi);
pow_impl!(f32, i32, i32, <f32 as Float>::powi);
pow_impl!(f64, i8, i32, <f64 as Float>::powi);
pow_impl!(f64, u8, i32, <f64 as Float>::powi);
pow_impl!(f64, i16, i32, <f64 as Float>::powi);
pow_impl!(f64, u16, i32, <f64 as Float>::powi);
pow_impl!(f64, i32, i32, <f64 as Float>::powi);
pow_impl!(f32, f32, f32, <f32 as Float>::powf);
pow_impl!(f64, f32, f64, <f64 as Float>::powf);
pow_impl!(f64, f64, f64, <f64 as Float>::powf);
}
/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// Note that `0⁰` (`pow(0, 0)`) returnes `1`. Mathematically this is undefined.
/// Note that `0⁰` (`pow(0, 0)`) returns `1`. Mathematically this is undefined.
///
/// # Example
///
@ -211,7 +212,7 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Note that `0⁰` (`checked_pow(0, 0)`) returnes `Some(1)`. Mathematically this is undefined.
/// Note that `0⁰` (`checked_pow(0, 0)`) returns `Some(1)`. Mathematically this is undefined.
///
/// Otherwise same as the `pow` function.
///

View File

@ -1,4 +1,6 @@
use std::ops::Neg;
#![cfg(any(feature = "std", feature = "libm"))]
use core::ops::Neg;
use {Float, Num, NumCast};
@ -11,7 +13,7 @@ use {Float, Num, NumCast};
/// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type)
/// for a list of data types that could meaningfully implement this trait.
///
/// This trait is only available with the `std` feature.
/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// Returns the smallest finite value that this type can represent.
///

View File

@ -206,11 +206,7 @@ empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
#[cfg(has_i128)]
empty_trait_impl!(Unsigned for u128);
impl<T: Unsigned> Unsigned for Wrapping<T>
where
Wrapping<T>: Num,
{
}
impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
#[test]
fn unsigned_wrapping_is_unsigned() {