Compare commits

..

No commits in common. "master" and "num-0.1.31" have entirely different histories.

45 changed files with 11331 additions and 6999 deletions

16
.multirust.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
# Use multirust to locally run the same suite of tests as .travis.yml.
# (You should first install/update 1.0.0, beta, and nightly.)
set -ex
for toolchain in 1.0.0 beta nightly; do
run="multirust run $toolchain"
$run cargo build --verbose
$run cargo test --verbose
$run .travis/test_features.sh
if [ $toolchain = nightly ]; then
$run .travis/test_nightly.sh
fi
$run cargo doc
done

View File

@ -1,52 +1,22 @@
language: rust
sudo: false
rust:
- 1.8.0
- 1.15.0
- 1.20.0
- 1.26.0 # has_i128
- 1.31.0 # 2018!
- stable
- 1.0.0
- 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
- cargo test --verbose
- .travis/test_features.sh
- |
[ $TRAVIS_RUST_VERSION != nightly ] ||
.travis/test_nightly.sh
- cargo doc
after_success: |
[ $TRAVIS_BRANCH = master ] &&
[ $TRAVIS_PULL_REQUEST = false ] &&
[ $TRAVIS_RUST_VERSION = nightly ] &&
ssh-agent .travis/deploy.sh
notifications:
email:
on_success: never
branches:
only:
- master
- next
- staging
- trying

1
.travis/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/deploy

BIN
.travis/deploy.enc Normal file

Binary file not shown.

12
.travis/deploy.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
set -ex
cp doc/* target/doc/
pip install ghp-import --user
$HOME/.local/bin/ghp-import -n target/doc
openssl aes-256-cbc -K $encrypted_9e86330b283d_key -iv $encrypted_9e86330b283d_iv -in .travis/deploy.enc -out .travis/deploy -d
chmod 600 .travis/deploy
ssh-add .travis/deploy
git push -qf ssh://git@github.com/${TRAVIS_REPO_SLUG}.git gh-pages

9
.travis/test_features.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set -ex
for feature in '' bigint rational complex; do
cargo build --verbose --no-default-features --features="$feature"
cargo test --verbose --no-default-features --features="$feature"
done

7
.travis/test_nightly.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
set -ex
cargo bench --verbose
cargo test --verbose --manifest-path=num-macros/Cargo.toml

View File

@ -1,28 +1,37 @@
[package]
authors = ["The Rust Project Developers"]
description = "Numeric traits for generic mathematics"
documentation = "https://docs.rs/num-traits"
homepage = "https://github.com/rust-num/num-traits"
keywords = ["mathematics", "numerics"]
categories = ["algorithms", "science", "no-std"]
license = "MIT/Apache-2.0"
repository = "https://github.com/rust-num/num-traits"
name = "num-traits"
version = "0.2.8"
readme = "README.md"
build = "build.rs"
exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
[package.metadata.docs.rs]
features = ["std"]
name = "num"
version = "0.1.31"
authors = ["The Rust Project Developers"]
license = "MIT/Apache-2.0"
homepage = "https://github.com/rust-num/num"
repository = "https://github.com/rust-num/num"
documentation = "http://rust-num.github.io/num"
keywords = ["mathematics", "numerics"]
description = """
A collection of numeric types and traits for Rust, including bigint,
complex, rational, range iterators, generic integers, and more!
"""
[dependencies]
libm = { version = "0.1.4", optional = true }
rustc-serialize = { version = "0.3.13", optional = true }
rand = { version = "0.3.8", optional = true }
[dev-dependencies]
# Some tests of non-rand functionality still use rand because the tests
# themselves are randomized.
rand = { version = "0.3.8" }
[features]
default = ["std"]
std = []
i128 = []
[build-dependencies]
autocfg = "0.1.3"
complex = []
rational = []
bigint = []
default = ["bigint", "complex", "rand", "rational", "rustc-serialize"]
[[bench]]
name = "bigint"
[[bench]]
name = "shootout-pidigits"
harness = false

View File

@ -1,11 +1,12 @@
# num-traits
# num
[![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)
[![Travis status](https://travis-ci.org/rust-num/num-traits.svg?branch=master)](https://travis-ci.org/rust-num/num-traits)
A collection of numeric types and traits for Rust.
Numeric traits for generic mathematics in Rust.
This includes new types for big integers, rationals, and complex numbers,
new traits for generic programming on numeric properties like `Integer,
and generic range iterators.
[Documentation](http://rust-num.github.io/num)
## Usage
@ -13,42 +14,11 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
num-traits = "0.2"
num = "0.1"
```
and this to your crate root:
```rust
extern crate num_traits;
extern crate num;
```
## Features
This crate can be used without the standard library (`#![no_std]`) by disabling
the default `std` feature. Use this in `Cargo.toml`:
```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 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.

View File

@ -1,154 +0,0 @@
# 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
strictly defined, but the current behavior is a pragmatic choice that has
precedent in Rust `core` for the primitives and in many other languages.
- [The new `WrappingShl` and `WrappingShr` traits][81] will wrap the shift count
if it exceeds the bit size of the type.
**Contributors**: @cuviper, @edmccard, @meltinglava
[79]: https://github.com/rust-num/num-traits/pull/79
[81]: https://github.com/rust-num/num-traits/pull/81
# Release 0.2.5 (2018-06-20)
- [Documentation for `mul_add` now clarifies that it's not always faster.][70]
- [The default methods in `FromPrimitive` and `ToPrimitive` are more robust.][73]
**Contributors**: @cuviper, @frewsxcv
[70]: https://github.com/rust-num/num-traits/pull/70
[73]: https://github.com/rust-num/num-traits/pull/73
# Release 0.2.4 (2018-05-11)
- [Support for 128-bit integers is now automatically detected and enabled.][69]
Setting the `i128` crate feature now causes the build script to panic if such
support is not detected.
**Contributors**: @cuviper
[69]: https://github.com/rust-num/num-traits/pull/69
# Release 0.2.3 (2018-05-10)
- [The new `CheckedNeg` and `CheckedRem` traits][63] perform checked `Neg` and
`Rem`, returning `Some(output)` or `None` on overflow.
- [The `no_std` implementation of `FloatCore::to_degrees` for `f32`][61] now
uses a constant for greater accuracy, mirroring [rust#47919]. (With `std` it
just calls the inherent `f32::to_degrees` in the standard library.)
- [The new `MulAdd` and `MulAddAssign` traits][59] perform a fused multiply-
add. For integer types this is just a convenience, but for floating point
types this produces a more accurate result than the separate operations.
- [All applicable traits are now implemented for 128-bit integers][60] starting
with Rust 1.26, enabled by the new `i128` crate feature. The `FromPrimitive`
and `ToPrimitive` traits now also have corresponding 128-bit methods, which
default to converting via 64-bit integers for compatibility.
**Contributors**: @cuviper, @LEXUGE, @regexident, @vks
[59]: https://github.com/rust-num/num-traits/pull/59
[60]: https://github.com/rust-num/num-traits/pull/60
[61]: https://github.com/rust-num/num-traits/pull/61
[63]: https://github.com/rust-num/num-traits/pull/63
[rust#47919]: https://github.com/rust-lang/rust/pull/47919
# Release 0.2.2 (2018-03-18)
- [Casting from floating point to integers now returns `None` on overflow][52],
avoiding [rustc's undefined behavior][rust-10184]. This applies to the `cast`
function and the traits `NumCast`, `FromPrimitive`, and `ToPrimitive`.
**Contributors**: @apopiak, @cuviper, @dbarella
[52]: https://github.com/rust-num/num-traits/pull/52
[rust-10184]: https://github.com/rust-lang/rust/issues/10184
# Release 0.2.1 (2018-03-01)
- [The new `FloatCore` trait][32] offers a subset of `Float` for `#![no_std]` use.
[This includes everything][41] except the transcendental functions and FMA.
- [The new `Inv` trait][37] returns the multiplicative inverse, or reciprocal.
- [The new `Pow` trait][37] performs exponentiation, much like the existing `pow`
function, but with generic exponent types.
- [The new `One::is_one` method][39] tests if a value equals 1. Implementers
should override this method if there's a more efficient way to check for 1,
rather than comparing with a temporary `one()`.
**Contributors**: @clarcharr, @cuviper, @vks
[32]: https://github.com/rust-num/num-traits/pull/32
[37]: https://github.com/rust-num/num-traits/pull/37
[39]: https://github.com/rust-num/num-traits/pull/39
[41]: https://github.com/rust-num/num-traits/pull/41
# Release 0.2.0 (2018-02-06)
- **breaking change**: [There is now a `std` feature][30], enabled by default, along
with the implication that building *without* this feature makes this a
`#![no_std]` crate.
- The `Float` and `Real` traits are only available when `std` is enabled.
- Otherwise, the API is unchanged, and num-traits 0.1.43 now re-exports its
items from num-traits 0.2 for compatibility (the [semver-trick]).
**Contributors**: @cuviper, @termoshtt, @vks
[semver-trick]: https://github.com/dtolnay/semver-trick
[30]: https://github.com/rust-num/num-traits/pull/30
# Release 0.1.43 (2018-02-06)
- All items are now [re-exported from num-traits 0.2][31] for compatibility.
[31]: https://github.com/rust-num/num-traits/pull/31
# Release 0.1.42 (2018-01-22)
- [num-traits now has its own source repository][num-356] at [rust-num/num-traits][home].
- [`ParseFloatError` now implements `Display`][22].
- [The new `AsPrimitive` trait][17] implements generic casting with the `as` operator.
- [The new `CheckedShl` and `CheckedShr` traits][21] implement generic
support for the `checked_shl` and `checked_shr` methods on primitive integers.
- [The new `Real` trait][23] offers a subset of `Float` functionality that may be applicable to more
types, with a blanket implementation for all existing `T: Float` types.
Thanks to @cuviper, @Enet4, @fabianschuiki, @svartalf, and @yoanlcq for their contributions!
[home]: https://github.com/rust-num/num-traits
[num-356]: https://github.com/rust-num/num/pull/356
[17]: https://github.com/rust-num/num-traits/pull/17
[21]: https://github.com/rust-num/num-traits/pull/21
[22]: https://github.com/rust-num/num-traits/pull/22
[23]: https://github.com/rust-num/num-traits/pull/23
# Prior releases
No prior release notes were kept. Thanks all the same to the many
contributors that have made this crate what it is!

214
benches/bigint.rs Normal file
View File

@ -0,0 +1,214 @@
#![feature(test)]
extern crate test;
extern crate num;
extern crate rand;
use std::mem::replace;
use test::Bencher;
use num::{BigInt, BigUint, Zero, One, FromPrimitive};
use num::bigint::RandBigInt;
use rand::{SeedableRng, StdRng};
fn get_rng() -> StdRng {
let seed: &[_] = &[1, 2, 3, 4];
SeedableRng::from_seed(seed)
}
fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
let mut rng = get_rng();
let x = rng.gen_bigint(xbits);
let y = rng.gen_bigint(ybits);
b.iter(|| &x * &y);
}
fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
let mut rng = get_rng();
let x = rng.gen_bigint(xbits);
let y = rng.gen_bigint(ybits);
b.iter(|| &x / &y);
}
fn factorial(n: usize) -> BigUint {
let mut f: BigUint = One::one();
for i in 1..(n+1) {
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
f = f * bu;
}
f
}
fn fib(n: usize) -> BigUint {
let mut f0: BigUint = Zero::zero();
let mut f1: BigUint = One::one();
for _ in 0..n {
let f2 = f0 + &f1;
f0 = replace(&mut f1, f2);
}
f0
}
#[bench]
fn multiply_0(b: &mut Bencher) {
multiply_bench(b, 1 << 8, 1 << 8);
}
#[bench]
fn multiply_1(b: &mut Bencher) {
multiply_bench(b, 1 << 8, 1 << 16);
}
#[bench]
fn multiply_2(b: &mut Bencher) {
multiply_bench(b, 1 << 16, 1 << 16);
}
#[bench]
fn divide_0(b: &mut Bencher) {
divide_bench(b, 1 << 8, 1 << 6);
}
#[bench]
fn divide_1(b: &mut Bencher) {
divide_bench(b, 1 << 12, 1 << 8);
}
#[bench]
fn divide_2(b: &mut Bencher) {
divide_bench(b, 1 << 16, 1 << 12);
}
#[bench]
fn factorial_100(b: &mut Bencher) {
b.iter(|| factorial(100));
}
#[bench]
fn fib_100(b: &mut Bencher) {
b.iter(|| fib(100));
}
#[bench]
fn fac_to_string(b: &mut Bencher) {
let fac = factorial(100);
b.iter(|| fac.to_string());
}
#[bench]
fn fib_to_string(b: &mut Bencher) {
let fib = fib(100);
b.iter(|| fib.to_string());
}
fn to_str_radix_bench(b: &mut Bencher, radix: u32) {
let mut rng = get_rng();
let x = rng.gen_bigint(1009);
b.iter(|| x.to_str_radix(radix));
}
#[bench]
fn to_str_radix_02(b: &mut Bencher) {
to_str_radix_bench(b, 2);
}
#[bench]
fn to_str_radix_08(b: &mut Bencher) {
to_str_radix_bench(b, 8);
}
#[bench]
fn to_str_radix_10(b: &mut Bencher) {
to_str_radix_bench(b, 10);
}
#[bench]
fn to_str_radix_16(b: &mut Bencher) {
to_str_radix_bench(b, 16);
}
#[bench]
fn to_str_radix_36(b: &mut Bencher) {
to_str_radix_bench(b, 36);
}
fn from_str_radix_bench(b: &mut Bencher, radix: u32) {
use num::Num;
let mut rng = get_rng();
let x = rng.gen_bigint(1009);
let s = x.to_str_radix(radix);
assert_eq!(x, BigInt::from_str_radix(&s, radix).unwrap());
b.iter(|| BigInt::from_str_radix(&s, radix));
}
#[bench]
fn from_str_radix_02(b: &mut Bencher) {
from_str_radix_bench(b, 2);
}
#[bench]
fn from_str_radix_08(b: &mut Bencher) {
from_str_radix_bench(b, 8);
}
#[bench]
fn from_str_radix_10(b: &mut Bencher) {
from_str_radix_bench(b, 10);
}
#[bench]
fn from_str_radix_16(b: &mut Bencher) {
from_str_radix_bench(b, 16);
}
#[bench]
fn from_str_radix_36(b: &mut Bencher) {
from_str_radix_bench(b, 36);
}
#[bench]
fn shl(b: &mut Bencher) {
let n = BigUint::one() << 1000;
b.iter(|| {
let mut m = n.clone();
for i in 0..50 {
m = m << i;
}
})
}
#[bench]
fn shr(b: &mut Bencher) {
let n = BigUint::one() << 2000;
b.iter(|| {
let mut m = n.clone();
for i in 0..50 {
m = m >> i;
}
})
}
#[bench]
fn hash(b: &mut Bencher) {
use std::collections::HashSet;
let mut rng = get_rng();
let v: Vec<BigInt> = (1000..2000).map(|bits| rng.gen_bigint(bits)).collect();
b.iter(|| {
let h: HashSet<&BigInt> = v.iter().collect();
assert_eq!(h.len(), v.len());
});
}
#[bench]
fn pow_bench(b: &mut Bencher) {
b.iter(|| {
let upper = 100_usize;
for i in 2..upper + 1 {
for j in 2..upper + 1 {
let i_big = BigUint::from_usize(i).unwrap();
num::pow(i_big, j);
}
}
});
}

View File

@ -0,0 +1,131 @@
// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// Copyright (c) 2013-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
// the name of "The Computer Language Shootout Benchmarks" nor the
// names of its contributors may be used to endorse or promote
// products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
extern crate num;
use std::str::FromStr;
use std::io;
use num::traits::{FromPrimitive, ToPrimitive};
use num::{BigInt, Integer, One, Zero};
struct Context {
numer: BigInt,
accum: BigInt,
denom: BigInt,
}
impl Context {
fn new() -> Context {
Context {
numer: One::one(),
accum: Zero::zero(),
denom: One::one(),
}
}
fn from_i32(i: i32) -> BigInt {
FromPrimitive::from_i32(i).unwrap()
}
fn extract_digit(&self) -> i32 {
if self.numer > self.accum {return -1;}
let (q, r) =
(&self.numer * Context::from_i32(3) + &self.accum)
.div_rem(&self.denom);
if r + &self.numer >= self.denom {return -1;}
q.to_i32().unwrap()
}
fn next_term(&mut self, k: i32) {
let y2 = Context::from_i32(k * 2 + 1);
self.accum = (&self.accum + (&self.numer << 1)) * &y2;
self.numer = &self.numer * Context::from_i32(k);
self.denom = &self.denom * y2;
}
fn eliminate_digit(&mut self, d: i32) {
let d = Context::from_i32(d);
let ten = Context::from_i32(10);
self.accum = (&self.accum - &self.denom * d) * &ten;
self.numer = &self.numer * ten;
}
}
fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
let mut k = 0;
let mut context = Context::new();
for i in 1..(n+1) {
let mut d;
loop {
k += 1;
context.next_term(k);
d = context.extract_digit();
if d != -1 {break;}
}
try!(write!(out, "{}", d));
if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }
context.eliminate_digit(d);
}
let m = n % 10;
if m != 0 {
for _ in m..10 { try!(write!(out, " ")); }
try!(write!(out, "\t:{}\n", n));
}
Ok(())
}
const DEFAULT_DIGITS: isize = 512;
fn main() {
let args = std::env::args().collect::<Vec<_>>();
let n = if args.len() < 2 {
DEFAULT_DIGITS
} else if args[1] == "--bench" {
return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
} else {
FromStr::from_str(&args[1]).unwrap()
};
pidigits(n, &mut std::io::stdout()).unwrap();
}

View File

@ -1,3 +0,0 @@
status = [
"continuous-integration/travis-ci/push",
]

View File

@ -1,14 +0,0 @@
extern crate autocfg;
use std::env;
fn main() {
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!");
}
autocfg::rerun_path(file!());
}

View File

@ -1,11 +0,0 @@
#!/bin/sh
# Use rustup to locally run the same suite of tests as .travis.yml.
# (You should first install/update 1.8.0, stable, beta, and nightly.)
set -ex
export TRAVIS_RUST_VERSION
for TRAVIS_RUST_VERSION in 1.8.0 1.15.0 1.20.0 stable beta nightly; do
run="rustup run $TRAVIS_RUST_VERSION"
$run $PWD/ci/test_full.sh
done

View File

@ -1,27 +0,0 @@
#!/bin/bash
set -ex
echo Testing num-traits on rustc ${TRAVIS_RUST_VERSION}
# num-traits should build and test everywhere.
cargo build --verbose
cargo test --verbose
# test `no_std`
cargo build --verbose --no-default-features
cargo test --verbose --no-default-features
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

BIN
doc/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

1
doc/index.html Normal file
View File

@ -0,0 +1 @@
<meta http-equiv=refresh content=0;url=num/index.html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

19
num-macros/Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "num-macros"
version = "0.1.31"
authors = ["The Rust Project Developers"]
license = "MIT/Apache-2.0"
homepage = "https://github.com/rust-num/num"
repository = "https://github.com/rust-num/num"
documentation = "http://rust-num.github.io/num"
keywords = ["mathematics", "numerics"]
description = """
Numeric syntax extensions.
"""
[lib]
name = "num_macros"
plugin = true
[dev-dependencies]
num = { path = "..", version = "0.1" }

198
num-macros/src/lib.rs Normal file
View File

@ -0,0 +1,198 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate syntax_ext;
extern crate rustc_plugin;
use syntax::ast::{MetaItem, Expr, BinOpKind};
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax_ext::deriving::generic::*;
use syntax_ext::deriving::generic::ty::*;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::ext::base::MultiDecorator;
use syntax::parse::token;
use rustc_plugin::Registry;
macro_rules! pathvec {
($($x:ident)::+) => (
vec![ $( stringify!($x) ),+ ]
)
}
macro_rules! path {
($($x:tt)*) => (
::syntax_ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
)
}
macro_rules! path_local {
($x:ident) => (
::syntax_ext::deriving::generic::ty::Path::new_local(stringify!($x))
)
}
macro_rules! pathvec_std {
($cx:expr, $first:ident :: $($rest:ident)::+) => ({
let mut v = pathvec!($($rest)::+);
if let Some(s) = $cx.crate_root {
v.insert(0, s);
}
v
})
}
pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));
let trait_def = TraitDef {
is_unsafe: false,
span: span,
attributes: Vec::new(),
path: path!(num::FromPrimitive),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec!(
MethodDef {
name: "from_i64",
is_unsafe: false,
generics: LifetimeBounds::empty(),
explicit_self: None,
args: vec!(Literal(path_local!(i64))),
ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
None,
vec!(Box::new(Self_)),
true)),
// #[inline] liable to cause code-bloat
attributes: attrs.clone(),
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
cs_from("i64", c, s, sub)
})),
},
MethodDef {
name: "from_u64",
is_unsafe: false,
generics: LifetimeBounds::empty(),
explicit_self: None,
args: vec!(Literal(path_local!(u64))),
ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
None,
vec!(Box::new(Self_)),
true)),
// #[inline] liable to cause code-bloat
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
cs_from("u64", c, s, sub)
})),
}
),
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, &item, push)
}
fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
if substr.nonself_args.len() != 1 {
cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
}
let n = &substr.nonself_args[0];
match *substr.fields {
StaticStruct(..) => {
cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
return cx.expr_fail(trait_span, InternedString::new(""));
}
StaticEnum(enum_def, _) => {
if enum_def.variants.is_empty() {
cx.span_err(trait_span,
"`FromPrimitive` cannot be derived for enums with no variants");
return cx.expr_fail(trait_span, InternedString::new(""));
}
let mut arms = Vec::new();
for variant in &enum_def.variants {
match variant.node.data {
ast::VariantData::Unit(..) => {
let span = variant.span;
// expr for `$n == $variant as $name`
let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
let variant = cx.expr_path(path);
let ty = cx.ty_ident(span, cx.ident_of(name));
let cast = cx.expr_cast(span, variant.clone(), ty);
let guard = cx.expr_binary(span, BinOpKind::Eq, n.clone(), cast);
// expr for `Some($variant)`
let body = cx.expr_some(span, variant);
// arm for `_ if $guard => $body`
let arm = ast::Arm {
attrs: vec!(),
pats: vec!(cx.pat_wild(span)),
guard: Some(guard),
body: body,
};
arms.push(arm);
}
ast::VariantData::Tuple(..) => {
cx.span_err(trait_span,
"`FromPrimitive` cannot be derived for \
enum variants with arguments");
return cx.expr_fail(trait_span,
InternedString::new(""));
}
ast::VariantData::Struct(..) => {
cx.span_err(trait_span,
"`FromPrimitive` cannot be derived for enums \
with struct variants");
return cx.expr_fail(trait_span,
InternedString::new(""));
}
}
}
// arm for `_ => None`
let arm = ast::Arm {
attrs: vec!(),
pats: vec!(cx.pat_wild(trait_span)),
guard: None,
body: cx.expr_none(trait_span),
};
arms.push(arm);
cx.expr_match(trait_span, n.clone(), arms)
}
_ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")
}
}
#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(
token::intern("derive_NumFromPrimitive"),
MultiDecorator(Box::new(expand_deriving_from_primitive)));
}

View File

@ -0,0 +1,36 @@
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(custom_derive, plugin)]
#![plugin(num_macros)]
extern crate num;
#[derive(Debug, PartialEq, NumFromPrimitive)]
enum Color {
Red,
Blue,
Green,
}
#[test]
fn test_from_primitive() {
let v: Vec<Option<Color>> = vec![
num::FromPrimitive::from_u64(0),
num::FromPrimitive::from_u64(1),
num::FromPrimitive::from_u64(2),
num::FromPrimitive::from_u64(3),
];
assert_eq!(
v,
vec![Some(Color::Red), Some(Color::Blue), Some(Color::Green), None]
);
}

4888
src/bigint.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,127 +0,0 @@
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};
/// Numbers which have upper and lower bounds
pub trait Bounded {
// FIXME (#5527): These should be associated constants
/// returns the smallest finite number this type can represent
fn min_value() -> Self;
/// returns the largest finite number this type can represent
fn max_value() -> Self;
}
macro_rules! bounded_impl {
($t:ty, $min:expr, $max:expr) => {
impl Bounded for $t {
#[inline]
fn min_value() -> $t {
$min
}
#[inline]
fn max_value() -> $t {
$max
}
}
};
}
bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8, u8::MIN, u8::MAX);
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);
bounded_impl!(i8, i8::MIN, i8::MAX);
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> {
fn min_value() -> Self {
Wrapping(T::min_value())
}
fn max_value() -> Self {
Wrapping(T::max_value())
}
}
bounded_impl!(f32, f32::MIN, f32::MAX);
macro_rules! for_each_tuple_ {
( $m:ident !! ) => (
$m! { }
);
( $m:ident !! $h:ident, $($t:ident,)* ) => (
$m! { $h $($t)* }
for_each_tuple_! { $m !! $($t,)* }
);
}
macro_rules! for_each_tuple {
($m:ident) => {
for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
};
}
macro_rules! bounded_tuple {
( $($name:ident)* ) => (
impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
#[inline]
fn min_value() -> Self {
($($name::min_value(),)*)
}
#[inline]
fn max_value() -> Self {
($($name::max_value(),)*)
}
}
);
}
for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
#[test]
fn wrapping_bounded() {
macro_rules! test_wrapping_bounded {
($($t:ty)+) => {
$(
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
)+
};
}
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 {
($($t:ty)+) => {
$(
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
)+
};
}
test_wrapping_bounded!(u128 i128);
}
#[test]
fn wrapping_is_bounded() {
fn require_bounded<T: Bounded>(_: &T) {}
require_bounded(&Wrapping(42_u32));
require_bounded(&Wrapping(-42));
}

View File

@ -1,762 +0,0 @@
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 float::FloatCore;
/// A generic trait for converting a value to a number.
pub trait ToPrimitive {
/// Converts the value of `self` to an `isize`.
#[inline]
fn to_isize(&self) -> Option<isize> {
self.to_i64().as_ref().and_then(ToPrimitive::to_isize)
}
/// Converts the value of `self` to an `i8`.
#[inline]
fn to_i8(&self) -> Option<i8> {
self.to_i64().as_ref().and_then(ToPrimitive::to_i8)
}
/// Converts the value of `self` to an `i16`.
#[inline]
fn to_i16(&self) -> Option<i16> {
self.to_i64().as_ref().and_then(ToPrimitive::to_i16)
}
/// Converts the value of `self` to an `i32`.
#[inline]
fn to_i32(&self) -> Option<i32> {
self.to_i64().as_ref().and_then(ToPrimitive::to_i32)
}
/// Converts the value of `self` to an `i64`.
fn to_i64(&self) -> Option<i64>;
/// Converts the value of `self` to an `i128`.
///
/// 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)
}
/// Converts the value of `self` to a `usize`.
#[inline]
fn to_usize(&self) -> Option<usize> {
self.to_u64().as_ref().and_then(ToPrimitive::to_usize)
}
/// Converts the value of `self` to an `u8`.
#[inline]
fn to_u8(&self) -> Option<u8> {
self.to_u64().as_ref().and_then(ToPrimitive::to_u8)
}
/// Converts the value of `self` to an `u16`.
#[inline]
fn to_u16(&self) -> Option<u16> {
self.to_u64().as_ref().and_then(ToPrimitive::to_u16)
}
/// Converts the value of `self` to an `u32`.
#[inline]
fn to_u32(&self) -> Option<u32> {
self.to_u64().as_ref().and_then(ToPrimitive::to_u32)
}
/// Converts the value of `self` to an `u64`.
#[inline]
fn to_u64(&self) -> Option<u64>;
/// Converts the value of `self` to an `u128`.
///
/// 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)
}
/// Converts the value of `self` to an `f32`.
#[inline]
fn to_f32(&self) -> Option<f32> {
self.to_f64().as_ref().and_then(ToPrimitive::to_f32)
}
/// Converts the value of `self` to an `f64`.
#[inline]
fn to_f64(&self) -> Option<f64> {
match self.to_i64() {
Some(i) => i.to_f64(),
None => self.to_u64().as_ref().and_then(ToPrimitive::to_f64),
}
}
}
macro_rules! impl_to_primitive_int_to_int {
($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$DstT> {
let min = $DstT::MIN as $SrcT;
let max = $DstT::MAX as $SrcT;
if size_of::<$SrcT>() <= size_of::<$DstT>() || (min <= *self && *self <= max) {
Some(*self as $DstT)
} else {
None
}
}
)*}
}
macro_rules! impl_to_primitive_int_to_uint {
($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$DstT> {
let max = $DstT::MAX as $SrcT;
if 0 <= *self && (size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max) {
Some(*self as $DstT)
} else {
None
}
}
)*}
}
macro_rules! impl_to_primitive_int {
($T:ident) => {
impl ToPrimitive for $T {
impl_to_primitive_int_to_int! { $T:
fn to_isize -> isize;
fn to_i8 -> i8;
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
}
impl_to_primitive_int_to_uint! { $T:
fn to_usize -> usize;
fn to_u8 -> u8;
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
}
#[inline]
fn to_f32(&self) -> Option<f32> {
Some(*self as f32)
}
#[inline]
fn to_f64(&self) -> Option<f64> {
Some(*self as f64)
}
}
};
}
impl_to_primitive_int!(isize);
impl_to_primitive_int!(i8);
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 {
($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$DstT> {
let max = $DstT::MAX as $SrcT;
if size_of::<$SrcT>() < size_of::<$DstT>() || *self <= max {
Some(*self as $DstT)
} else {
None
}
}
)*}
}
macro_rules! impl_to_primitive_uint_to_uint {
($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$DstT> {
let max = $DstT::MAX as $SrcT;
if size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max {
Some(*self as $DstT)
} else {
None
}
}
)*}
}
macro_rules! impl_to_primitive_uint {
($T:ident) => {
impl ToPrimitive for $T {
impl_to_primitive_uint_to_int! { $T:
fn to_isize -> isize;
fn to_i8 -> i8;
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
}
impl_to_primitive_uint_to_uint! { $T:
fn to_usize -> usize;
fn to_u8 -> u8;
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
}
#[inline]
fn to_f32(&self) -> Option<f32> {
Some(*self as f32)
}
#[inline]
fn to_f64(&self) -> Option<f64> {
Some(*self as f64)
}
}
};
}
impl_to_primitive_uint!(usize);
impl_to_primitive_uint!(u8);
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 {
($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
#[inline]
fn $method(&self) -> Option<$DstT> {
// Only finite values that are reducing size need to worry about overflow.
if size_of::<$SrcT>() > size_of::<$DstT>() && FloatCore::is_finite(*self) {
let n = *self as f64;
if n < $DstT::MIN as f64 || n > $DstT::MAX as f64 {
return None;
}
}
// We can safely cast NaN, +-inf, and finite values in range.
Some(*self as $DstT)
}
)*}
}
macro_rules! impl_to_primitive_float_to_signed_int {
($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$i> {
// Float as int truncates toward zero, so we want to allow values
// in the exclusive range `(MIN-1, MAX+1)`.
if size_of::<$f>() > size_of::<$i>() {
// With a larger size, we can represent the range exactly.
const MIN_M1: $f = $i::MIN as $f - 1.0;
const MAX_P1: $f = $i::MAX as $f + 1.0;
if *self > MIN_M1 && *self < MAX_P1 {
return Some(*self as $i);
}
} else {
// We can't represent `MIN-1` exactly, but there's no fractional part
// at this magnitude, so we can just use a `MIN` inclusive boundary.
const MIN: $f = $i::MIN as $f;
// We can't represent `MAX` exactly, but it will round up to exactly
// `MAX+1` (a power of two) when we cast it.
const MAX_P1: $f = $i::MAX as $f;
if *self >= MIN && *self < MAX_P1 {
return Some(*self as $i);
}
}
None
}
)*}
}
macro_rules! impl_to_primitive_float_to_unsigned_int {
($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $u:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$u> {
// Float as int truncates toward zero, so we want to allow values
// in the exclusive range `(-1, MAX+1)`.
if size_of::<$f>() > size_of::<$u>() {
// With a larger size, we can represent the range exactly.
const MAX_P1: $f = $u::MAX as $f + 1.0;
if *self > -1.0 && *self < MAX_P1 {
return Some(*self as $u);
}
} else {
// We can't represent `MAX` exactly, but it will round up to exactly
// `MAX+1` (a power of two) when we cast it.
// (`u128::MAX as f32` is infinity, but this is still ok.)
const MAX_P1: $f = $u::MAX as $f;
if *self > -1.0 && *self < MAX_P1 {
return Some(*self as $u);
}
}
None
}
)*}
}
macro_rules! impl_to_primitive_float {
($T:ident) => {
impl ToPrimitive for $T {
impl_to_primitive_float_to_signed_int! { $T:
fn to_isize -> isize;
fn to_i8 -> i8;
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
}
impl_to_primitive_float_to_unsigned_int! { $T:
fn to_usize -> usize;
fn to_u8 -> u8;
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
}
impl_to_primitive_float_to_float! { $T:
fn to_f32 -> f32;
fn to_f64 -> f64;
}
}
};
}
impl_to_primitive_float!(f32);
impl_to_primitive_float!(f64);
/// A generic trait for converting a number to a value.
pub trait FromPrimitive: Sized {
/// Convert an `isize` to return an optional value of this type. If the
/// value cannot be represented by this value, then `None` is returned.
#[inline]
fn from_isize(n: isize) -> Option<Self> {
n.to_i64().and_then(FromPrimitive::from_i64)
}
/// Convert an `i8` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_i8(n: i8) -> Option<Self> {
FromPrimitive::from_i64(From::from(n))
}
/// Convert an `i16` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_i16(n: i16) -> Option<Self> {
FromPrimitive::from_i64(From::from(n))
}
/// Convert an `i32` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_i32(n: i32) -> Option<Self> {
FromPrimitive::from_i64(From::from(n))
}
/// Convert an `i64` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
fn from_i64(n: i64) -> Option<Self>;
/// Convert an `i128` to return an optional value of this type. If the
/// type cannot be represented by this value, 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)
}
/// Convert a `usize` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_usize(n: usize) -> Option<Self> {
n.to_u64().and_then(FromPrimitive::from_u64)
}
/// Convert an `u8` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_u8(n: u8) -> Option<Self> {
FromPrimitive::from_u64(From::from(n))
}
/// Convert an `u16` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_u16(n: u16) -> Option<Self> {
FromPrimitive::from_u64(From::from(n))
}
/// Convert an `u32` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_u32(n: u32) -> Option<Self> {
FromPrimitive::from_u64(From::from(n))
}
/// Convert an `u64` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
fn from_u64(n: u64) -> Option<Self>;
/// Convert an `u128` to return an optional value of this type. If the
/// type cannot be represented by this value, 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)
}
/// Convert a `f32` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_f32(n: f32) -> Option<Self> {
FromPrimitive::from_f64(From::from(n))
}
/// Convert a `f64` to return an optional value of this type. If the
/// type cannot be represented by this value, then `None` is returned.
#[inline]
fn from_f64(n: f64) -> Option<Self> {
match n.to_i64() {
Some(i) => FromPrimitive::from_i64(i),
None => n.to_u64().and_then(FromPrimitive::from_u64),
}
}
}
macro_rules! impl_from_primitive {
($T:ty, $to_ty:ident) => {
#[allow(deprecated)]
impl FromPrimitive for $T {
#[inline]
fn from_isize(n: isize) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_i8(n: i8) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_i16(n: i16) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_i32(n: i32) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_i64(n: i64) -> Option<$T> {
n.$to_ty()
}
#[cfg(has_i128)]
#[inline]
fn from_i128(n: i128) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_usize(n: usize) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_u8(n: u8) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_u16(n: u16) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_u32(n: u32) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_u64(n: u64) -> Option<$T> {
n.$to_ty()
}
#[cfg(has_i128)]
#[inline]
fn from_u128(n: u128) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_f32(n: f32) -> Option<$T> {
n.$to_ty()
}
#[inline]
fn from_f64(n: f64) -> Option<$T> {
n.$to_ty()
}
}
};
}
impl_from_primitive!(isize, to_isize);
impl_from_primitive!(i8, to_i8);
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);
macro_rules! impl_to_primitive_wrapping {
($( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(&self) -> Option<$i> {
(self.0).$method()
}
)*}
}
impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
impl_to_primitive_wrapping! {
fn to_isize -> isize;
fn to_i8 -> i8;
fn to_i16 -> i16;
fn to_i32 -> i32;
fn to_i64 -> i64;
#[cfg(has_i128)]
fn to_i128 -> i128;
fn to_usize -> usize;
fn to_u8 -> u8;
fn to_u16 -> u16;
fn to_u32 -> u32;
fn to_u64 -> u64;
#[cfg(has_i128)]
fn to_u128 -> u128;
fn to_f32 -> f32;
fn to_f64 -> f64;
}
}
macro_rules! impl_from_primitive_wrapping {
($( $(#[$cfg:meta])* fn $method:ident ( $i:ident ); )*) => {$(
#[inline]
$(#[$cfg])*
fn $method(n: $i) -> Option<Self> {
T::$method(n).map(Wrapping)
}
)*}
}
impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
impl_from_primitive_wrapping! {
fn from_isize(isize);
fn from_i8(i8);
fn from_i16(i16);
fn from_i32(i32);
fn from_i64(i64);
#[cfg(has_i128)]
fn from_i128(i128);
fn from_usize(usize);
fn from_u8(u8);
fn from_u16(u16);
fn from_u32(u32);
fn from_u64(u64);
#[cfg(has_i128)]
fn from_u128(u128);
fn from_f32(f32);
fn from_f64(f64);
}
}
/// Cast from one machine scalar to another.
///
/// # Examples
///
/// ```
/// # use num_traits as num;
/// let twenty: f32 = num::cast(0x14).unwrap();
/// assert_eq!(twenty, 20f32);
/// ```
///
#[inline]
pub fn cast<T: NumCast, U: NumCast>(n: T) -> Option<U> {
NumCast::from(n)
}
/// An interface for casting between machine scalars.
pub trait NumCast: Sized + ToPrimitive {
/// Creates a number from another value that can be converted into
/// a primitive via the `ToPrimitive` trait.
fn from<T: ToPrimitive>(n: T) -> Option<Self>;
}
macro_rules! impl_num_cast {
($T:ty, $conv:ident) => {
impl NumCast for $T {
#[inline]
#[allow(deprecated)]
fn from<N: ToPrimitive>(n: N) -> Option<$T> {
// `$conv` could be generated using `concat_idents!`, but that
// macro seems to be broken at the moment
n.$conv()
}
}
};
}
impl_num_cast!(u8, to_u8);
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);
impl_num_cast!(f64, to_f64);
impl<T: NumCast> NumCast for Wrapping<T> {
fn from<U: ToPrimitive>(n: U) -> Option<Self> {
T::from(n).map(Wrapping)
}
}
/// 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
/// numeric type (e.g. a newtype around another primitive), and the
/// intended conversion must never fail.
///
/// # Examples
///
/// ```
/// # use num_traits::AsPrimitive;
/// let three: i32 = (3.14159265f32).as_();
/// assert_eq!(three, 3);
/// ```
///
/// # Safety
///
/// Currently, some uses of the `as` operator are not entirely safe.
/// In particular, it is undefined behavior if:
///
/// - A truncated floating point value cannot fit in the target integer
/// type ([#10184](https://github.com/rust-lang/rust/issues/10184));
///
/// ```ignore
/// # use num_traits::AsPrimitive;
/// let x: u8 = (1.04E+17).as_(); // UB
/// ```
///
/// - Or a floating point value does not fit in another floating
/// point type ([#15536](https://github.com/rust-lang/rust/issues/15536)).
///
/// ```ignore
/// # use num_traits::AsPrimitive;
/// let x: f32 = (1e300f64).as_(); // UB
/// ```
///
pub trait AsPrimitive<T>: 'static + Copy
where
T: 'static + Copy,
{
/// Convert a value to another, using the `as` operator.
fn as_(self) -> T;
}
macro_rules! impl_as_primitive {
(@ $T: ty => $(#[$cfg:meta])* impl $U: ty ) => {
$(#[$cfg])*
impl AsPrimitive<$U> for $T {
#[inline] fn as_(self) -> $U { self as $U }
}
};
(@ $T: ty => { $( $U: ty ),* } ) => {$(
impl_as_primitive!(@ $T => impl $U);
)*};
($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!(u8 => { char, f32, f64 });
impl_as_primitive!(i8 => { f32, f64 });
impl_as_primitive!(u16 => { f32, f64 });
impl_as_primitive!(i16 => { f32, f64 });
impl_as_primitive!(u32 => { f32, f64 });
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 });
impl_as_primitive!(f32 => { f32, f64 });
impl_as_primitive!(f64 => { f32, f64 });
impl_as_primitive!(char => { char });
impl_as_primitive!(bool => {});

1117
src/complex.rs Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,207 +0,0 @@
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`.
/// # Purity
///
/// This function should return the same result at all times regardless of
/// external mutable state, for example values stored in TLS or in
/// `static mut`s.
// 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;
}
macro_rules! zero_impl {
($t:ty, $v:expr) => {
impl Zero for $t {
#[inline]
fn zero() -> $t {
$v
}
#[inline]
fn is_zero(&self) -> bool {
*self == $v
}
}
};
}
zero_impl!(usize, 0);
zero_impl!(u8, 0);
zero_impl!(u16, 0);
zero_impl!(u32, 0);
zero_impl!(u64, 0);
#[cfg(has_i128)]
zero_impl!(u128, 0);
zero_impl!(isize, 0);
zero_impl!(i8, 0);
zero_impl!(i16, 0);
zero_impl!(i32, 0);
zero_impl!(i64, 0);
#[cfg(has_i128)]
zero_impl!(i128, 0);
zero_impl!(f32, 0.0);
zero_impl!(f64, 0.0);
impl<T: Zero> Zero for Wrapping<T>
where
Wrapping<T>: Add<Output = Wrapping<T>>,
{
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`.
///
/// # Purity
///
/// This function should return the same result at all times regardless of
/// external mutable state, for example values stored in TLS or in
/// `static mut`s.
// 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.
/// After a semver bump, this method will be required, and the
/// `where Self: PartialEq` bound will be removed.
#[inline]
fn is_one(&self) -> bool
where
Self: PartialEq,
{
*self == Self::one()
}
}
macro_rules! one_impl {
($t:ty, $v:expr) => {
impl One for $t {
#[inline]
fn one() -> $t {
$v
}
#[inline]
fn is_one(&self) -> bool {
*self == $v
}
}
};
}
one_impl!(usize, 1);
one_impl!(u8, 1);
one_impl!(u16, 1);
one_impl!(u32, 1);
one_impl!(u64, 1);
#[cfg(has_i128)]
one_impl!(u128, 1);
one_impl!(isize, 1);
one_impl!(i8, 1);
one_impl!(i16, 1);
one_impl!(i32, 1);
one_impl!(i64, 1);
#[cfg(has_i128)]
one_impl!(i128, 1);
one_impl!(f32, 1.0);
one_impl!(f64, 1.0);
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())
}
}
// Some helper functions provided for backwards compatibility.
/// Returns the additive identity, `0`.
#[inline(always)]
pub fn zero<T: Zero>() -> T {
Zero::zero()
}
/// Returns the multiplicative identity, `1`.
#[inline(always)]
pub fn one<T: One>() -> T {
One::one()
}
#[test]
fn wrapping_identities() {
macro_rules! test_wrapping_identities {
($($t:ty)+) => {
$(
assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
)+
};
}
test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
}
#[test]
fn wrapping_is_zero() {
fn require_zero<T: Zero>(_: &T) {}
require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
fn require_one<T: One>(_: &T) {}
require_one(&Wrapping(42));
}

View File

@ -1,409 +0,0 @@
use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
use bounds::Bounded;
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
+ Num
+ NumCast
+ Bounded
+ PartialOrd
+ Ord
+ Eq
+ Not<Output = Self>
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
+ CheckedAdd<Output = Self>
+ CheckedSub<Output = Self>
+ CheckedMul<Output = Self>
+ CheckedDiv<Output = Self>
+ Saturating
{
/// Returns the number of ones in the binary representation of `self`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0b01001100u8;
///
/// assert_eq!(n.count_ones(), 3);
/// ```
fn count_ones(self) -> u32;
/// Returns the number of zeros in the binary representation of `self`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0b01001100u8;
///
/// assert_eq!(n.count_zeros(), 5);
/// ```
fn count_zeros(self) -> u32;
/// Returns the number of leading zeros in the binary representation
/// of `self`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0b0101000u16;
///
/// assert_eq!(n.leading_zeros(), 10);
/// ```
fn leading_zeros(self) -> u32;
/// Returns the number of trailing zeros in the binary representation
/// of `self`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0b0101000u16;
///
/// assert_eq!(n.trailing_zeros(), 3);
/// ```
fn trailing_zeros(self) -> u32;
/// Shifts the bits to the left by a specified amount amount, `n`, wrapping
/// the truncated bits to the end of the resulting integer.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
/// let m = 0x3456789ABCDEF012u64;
///
/// assert_eq!(n.rotate_left(12), m);
/// ```
fn rotate_left(self, n: u32) -> Self;
/// Shifts the bits to the right by a specified amount amount, `n`, wrapping
/// the truncated bits to the beginning of the resulting integer.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
/// let m = 0xDEF0123456789ABCu64;
///
/// assert_eq!(n.rotate_right(12), m);
/// ```
fn rotate_right(self, n: u32) -> Self;
/// Shifts the bits to the left by a specified amount amount, `n`, filling
/// zeros in the least significant bits.
///
/// This is bitwise equivalent to signed `Shl`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
/// let m = 0x3456789ABCDEF000u64;
///
/// assert_eq!(n.signed_shl(12), m);
/// ```
fn signed_shl(self, n: u32) -> Self;
/// Shifts the bits to the right by a specified amount amount, `n`, copying
/// the "sign bit" in the most significant bits even for unsigned types.
///
/// This is bitwise equivalent to signed `Shr`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0xFEDCBA9876543210u64;
/// let m = 0xFFFFEDCBA9876543u64;
///
/// assert_eq!(n.signed_shr(12), m);
/// ```
fn signed_shr(self, n: u32) -> Self;
/// Shifts the bits to the left by a specified amount amount, `n`, filling
/// zeros in the least significant bits.
///
/// This is bitwise equivalent to unsigned `Shl`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFi64;
/// let m = 0x3456789ABCDEF000i64;
///
/// assert_eq!(n.unsigned_shl(12), m);
/// ```
fn unsigned_shl(self, n: u32) -> Self;
/// Shifts the bits to the right by a specified amount amount, `n`, filling
/// zeros in the most significant bits.
///
/// This is bitwise equivalent to unsigned `Shr`.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = -8i8; // 0b11111000
/// let m = 62i8; // 0b00111110
///
/// assert_eq!(n.unsigned_shr(2), m);
/// ```
fn unsigned_shr(self, n: u32) -> Self;
/// Reverses the byte order of the integer.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
/// let m = 0xEFCDAB8967452301u64;
///
/// assert_eq!(n.swap_bytes(), m);
/// ```
fn swap_bytes(self) -> Self;
/// Convert an integer from big endian to the target's endianness.
///
/// On big endian this is a no-op. On little endian the bytes are swapped.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
///
/// if cfg!(target_endian = "big") {
/// assert_eq!(u64::from_be(n), n)
/// } else {
/// assert_eq!(u64::from_be(n), n.swap_bytes())
/// }
/// ```
fn from_be(x: Self) -> Self;
/// Convert an integer from little endian to the target's endianness.
///
/// On little endian this is a no-op. On big endian the bytes are swapped.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
///
/// if cfg!(target_endian = "little") {
/// assert_eq!(u64::from_le(n), n)
/// } else {
/// assert_eq!(u64::from_le(n), n.swap_bytes())
/// }
/// ```
fn from_le(x: Self) -> Self;
/// Convert `self` to big endian from the target's endianness.
///
/// On big endian this is a no-op. On little endian the bytes are swapped.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
///
/// if cfg!(target_endian = "big") {
/// assert_eq!(n.to_be(), n)
/// } else {
/// assert_eq!(n.to_be(), n.swap_bytes())
/// }
/// ```
fn to_be(self) -> Self;
/// Convert `self` to little endian from the target's endianness.
///
/// On little endian this is a no-op. On big endian the bytes are swapped.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// let n = 0x0123456789ABCDEFu64;
///
/// if cfg!(target_endian = "little") {
/// assert_eq!(n.to_le(), n)
/// } else {
/// assert_eq!(n.to_le(), n.swap_bytes())
/// }
/// ```
fn to_le(self) -> Self;
/// Raises self to the power of `exp`, using exponentiation by squaring.
///
/// # Examples
///
/// ```
/// use num_traits::PrimInt;
///
/// assert_eq!(2i32.pow(4), 16);
/// ```
fn pow(self, exp: u32) -> Self;
}
macro_rules! prim_int_impl {
($T:ty, $S:ty, $U:ty) => {
impl PrimInt for $T {
#[inline]
fn count_ones(self) -> u32 {
<$T>::count_ones(self)
}
#[inline]
fn count_zeros(self) -> u32 {
<$T>::count_zeros(self)
}
#[inline]
fn leading_zeros(self) -> u32 {
<$T>::leading_zeros(self)
}
#[inline]
fn trailing_zeros(self) -> u32 {
<$T>::trailing_zeros(self)
}
#[inline]
fn rotate_left(self, n: u32) -> Self {
<$T>::rotate_left(self, n)
}
#[inline]
fn rotate_right(self, n: u32) -> Self {
<$T>::rotate_right(self, n)
}
#[inline]
fn signed_shl(self, n: u32) -> Self {
((self as $S) << n) as $T
}
#[inline]
fn signed_shr(self, n: u32) -> Self {
((self as $S) >> n) as $T
}
#[inline]
fn unsigned_shl(self, n: u32) -> Self {
((self as $U) << n) as $T
}
#[inline]
fn unsigned_shr(self, n: u32) -> Self {
((self as $U) >> n) as $T
}
#[inline]
fn swap_bytes(self) -> Self {
<$T>::swap_bytes(self)
}
#[inline]
fn from_be(x: Self) -> Self {
<$T>::from_be(x)
}
#[inline]
fn from_le(x: Self) -> Self {
<$T>::from_le(x)
}
#[inline]
fn to_be(self) -> Self {
<$T>::to_be(self)
}
#[inline]
fn to_le(self) -> Self {
<$T>::to_le(self)
}
#[inline]
fn pow(self, exp: u32) -> Self {
<$T>::pow(self, exp)
}
}
};
}
// prim_int_impl!(type, signed, unsigned);
prim_int_impl!(u8, i8, u8);
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);

630
src/integer.rs Normal file
View File

@ -0,0 +1,630 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Integer trait and functions.
use {Num, Signed};
pub trait Integer
: Sized
+ Num
+ PartialOrd + Ord + Eq
{
/// Floored integer division.
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert!(( 8).div_floor(& 3) == 2);
/// assert!(( 8).div_floor(&-3) == -3);
/// assert!((-8).div_floor(& 3) == -3);
/// assert!((-8).div_floor(&-3) == 2);
///
/// assert!(( 1).div_floor(& 2) == 0);
/// assert!(( 1).div_floor(&-2) == -1);
/// assert!((-1).div_floor(& 2) == -1);
/// assert!((-1).div_floor(&-2) == 0);
/// ~~~
fn div_floor(&self, other: &Self) -> Self;
/// Floored integer modulo, satisfying:
///
/// ~~~
/// # use num::Integer;
/// # let n = 1; let d = 1;
/// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n)
/// ~~~
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert!(( 8).mod_floor(& 3) == 2);
/// assert!(( 8).mod_floor(&-3) == -1);
/// assert!((-8).mod_floor(& 3) == 1);
/// assert!((-8).mod_floor(&-3) == -2);
///
/// assert!(( 1).mod_floor(& 2) == 1);
/// assert!(( 1).mod_floor(&-2) == -1);
/// assert!((-1).mod_floor(& 2) == 1);
/// assert!((-1).mod_floor(&-2) == -1);
/// ~~~
fn mod_floor(&self, other: &Self) -> Self;
/// Greatest Common Divisor (GCD).
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(6.gcd(&8), 2);
/// assert_eq!(7.gcd(&3), 1);
/// ~~~
fn gcd(&self, other: &Self) -> Self;
/// Lowest Common Multiple (LCM).
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(7.lcm(&3), 21);
/// assert_eq!(2.lcm(&4), 4);
/// ~~~
fn lcm(&self, other: &Self) -> Self;
/// Deprecated, use `is_multiple_of` instead.
fn divides(&self, other: &Self) -> bool;
/// Returns `true` if `other` is a multiple of `self`.
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(9.is_multiple_of(&3), true);
/// assert_eq!(3.is_multiple_of(&9), false);
/// ~~~
fn is_multiple_of(&self, other: &Self) -> bool;
/// Returns `true` if the number is even.
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(3.is_even(), false);
/// assert_eq!(4.is_even(), true);
/// ~~~
fn is_even(&self) -> bool;
/// Returns `true` if the number is odd.
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(3.is_odd(), true);
/// assert_eq!(4.is_odd(), false);
/// ~~~
fn is_odd(&self) -> bool;
/// Simultaneous truncated integer division and modulus.
/// Returns `(quotient, remainder)`.
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(( 8).div_rem( &3), ( 2, 2));
/// assert_eq!(( 8).div_rem(&-3), (-2, 2));
/// assert_eq!((-8).div_rem( &3), (-2, -2));
/// assert_eq!((-8).div_rem(&-3), ( 2, -2));
///
/// assert_eq!(( 1).div_rem( &2), ( 0, 1));
/// assert_eq!(( 1).div_rem(&-2), ( 0, 1));
/// assert_eq!((-1).div_rem( &2), ( 0, -1));
/// assert_eq!((-1).div_rem(&-2), ( 0, -1));
/// ~~~
#[inline]
fn div_rem(&self, other: &Self) -> (Self, Self);
/// Simultaneous floored integer division and modulus.
/// Returns `(quotient, remainder)`.
///
/// # Examples
///
/// ~~~
/// # use num::Integer;
/// assert_eq!(( 8).div_mod_floor( &3), ( 2, 2));
/// assert_eq!(( 8).div_mod_floor(&-3), (-3, -1));
/// assert_eq!((-8).div_mod_floor( &3), (-3, 1));
/// assert_eq!((-8).div_mod_floor(&-3), ( 2, -2));
///
/// assert_eq!(( 1).div_mod_floor( &2), ( 0, 1));
/// assert_eq!(( 1).div_mod_floor(&-2), (-1, -1));
/// assert_eq!((-1).div_mod_floor( &2), (-1, 1));
/// assert_eq!((-1).div_mod_floor(&-2), ( 0, -1));
/// ~~~
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
(self.div_floor(other), self.mod_floor(other))
}
}
/// Simultaneous integer division and modulus
#[inline] pub fn div_rem<T: Integer>(x: T, y: T) -> (T, T) { x.div_rem(&y) }
/// Floored integer division
#[inline] pub fn div_floor<T: Integer>(x: T, y: T) -> T { x.div_floor(&y) }
/// Floored integer modulus
#[inline] pub fn mod_floor<T: Integer>(x: T, y: T) -> T { x.mod_floor(&y) }
/// Simultaneous floored integer division and modulus
#[inline] pub fn div_mod_floor<T: Integer>(x: T, y: T) -> (T, T) { x.div_mod_floor(&y) }
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The
/// result is always positive.
#[inline(always)] pub fn gcd<T: Integer>(x: T, y: T) -> T { x.gcd(&y) }
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
#[inline(always)] pub fn lcm<T: Integer>(x: T, y: T) -> T { x.lcm(&y) }
macro_rules! impl_integer_for_isize {
($T:ty, $test_mod:ident) => (
impl Integer for $T {
/// Floored integer division
#[inline]
fn div_floor(&self, other: &$T) -> $T {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match self.div_rem(other) {
(d, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => d - 1,
(d, _) => d,
}
}
/// Floored integer modulo
#[inline]
fn mod_floor(&self, other: &$T) -> $T {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match *self % *other {
r if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => r + *other,
r => r,
}
}
/// Calculates `div_floor` and `mod_floor` simultaneously
#[inline]
fn div_mod_floor(&self, other: &$T) -> ($T,$T) {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match self.div_rem(other) {
(d, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => (d - 1, r + *other),
(d, r) => (d, r),
}
}
/// Calculates the Greatest Common Divisor (GCD) of the number and
/// `other`. The result is always positive.
#[inline]
fn gcd(&self, other: &$T) -> $T {
// Use Stein's algorithm
let mut m = *self;
let mut n = *other;
if m == 0 || n == 0 { return (m | n).abs() }
// find common factors of 2
let shift = (m | n).trailing_zeros();
// The algorithm needs positive numbers, but the minimum value
// can't be represented as a positive one.
// It's also a power of two, so the gcd can be
// calculated by bitshifting in that case
// Assuming two's complement, the number created by the shift
// is positive for all numbers except gcd = abs(min value)
// The call to .abs() causes a panic in debug mode
if m == <$T>::min_value() || n == <$T>::min_value() {
return (1 << shift).abs()
}
// guaranteed to be positive now, rest like unsigned algorithm
m = m.abs();
n = n.abs();
// divide n and m by 2 until odd
// m inside loop
n >>= n.trailing_zeros();
while m != 0 {
m >>= m.trailing_zeros();
if n > m { ::std::mem::swap(&mut n, &mut m) }
m -= n;
}
n << shift
}
/// Calculates the Lowest Common Multiple (LCM) of the number and
/// `other`.
#[inline]
fn lcm(&self, other: &$T) -> $T {
// should not have to recalculate abs
((*self * *other) / self.gcd(other)).abs()
}
/// Deprecated, use `is_multiple_of` instead.
#[inline]
fn divides(&self, other: &$T) -> bool { return self.is_multiple_of(other); }
/// Returns `true` if the number is a multiple of `other`.
#[inline]
fn is_multiple_of(&self, other: &$T) -> bool { *self % *other == 0 }
/// Returns `true` if the number is divisible by `2`
#[inline]
fn is_even(&self) -> bool { (*self) & 1 == 0 }
/// Returns `true` if the number is not divisible by `2`
#[inline]
fn is_odd(&self) -> bool { !self.is_even() }
/// Simultaneous truncated integer division and modulus.
#[inline]
fn div_rem(&self, other: &$T) -> ($T, $T) {
(*self / *other, *self % *other)
}
}
#[cfg(test)]
mod $test_mod {
use Integer;
/// Checks that the division rule holds for:
///
/// - `n`: numerator (dividend)
/// - `d`: denominator (divisor)
/// - `qr`: quotient and remainder
#[cfg(test)]
fn test_division_rule((n,d): ($T,$T), (q,r): ($T,$T)) {
assert_eq!(d * q + r, n);
}
#[test]
fn test_div_rem() {
fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) {
let (n,d) = nd;
let separate_div_rem = (n / d, n % d);
let combined_div_rem = n.div_rem(&d);
assert_eq!(separate_div_rem, qr);
assert_eq!(combined_div_rem, qr);
test_division_rule(nd, separate_div_rem);
test_division_rule(nd, combined_div_rem);
}
test_nd_dr(( 8, 3), ( 2, 2));
test_nd_dr(( 8, -3), (-2, 2));
test_nd_dr((-8, 3), (-2, -2));
test_nd_dr((-8, -3), ( 2, -2));
test_nd_dr(( 1, 2), ( 0, 1));
test_nd_dr(( 1, -2), ( 0, 1));
test_nd_dr((-1, 2), ( 0, -1));
test_nd_dr((-1, -2), ( 0, -1));
}
#[test]
fn test_div_mod_floor() {
fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) {
let (n,d) = nd;
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
let combined_div_mod_floor = n.div_mod_floor(&d);
assert_eq!(separate_div_mod_floor, dm);
assert_eq!(combined_div_mod_floor, dm);
test_division_rule(nd, separate_div_mod_floor);
test_division_rule(nd, combined_div_mod_floor);
}
test_nd_dm(( 8, 3), ( 2, 2));
test_nd_dm(( 8, -3), (-3, -1));
test_nd_dm((-8, 3), (-3, 1));
test_nd_dm((-8, -3), ( 2, -2));
test_nd_dm(( 1, 2), ( 0, 1));
test_nd_dm(( 1, -2), (-1, -1));
test_nd_dm((-1, 2), (-1, 1));
test_nd_dm((-1, -2), ( 0, -1));
}
#[test]
fn test_gcd() {
assert_eq!((10 as $T).gcd(&2), 2 as $T);
assert_eq!((10 as $T).gcd(&3), 1 as $T);
assert_eq!((0 as $T).gcd(&3), 3 as $T);
assert_eq!((3 as $T).gcd(&3), 3 as $T);
assert_eq!((56 as $T).gcd(&42), 14 as $T);
assert_eq!((3 as $T).gcd(&-3), 3 as $T);
assert_eq!((-6 as $T).gcd(&3), 3 as $T);
assert_eq!((-4 as $T).gcd(&-2), 2 as $T);
}
#[test]
fn test_gcd_cmp_with_euclidean() {
fn euclidean_gcd(mut m: $T, mut n: $T) -> $T {
while m != 0 {
::std::mem::swap(&mut m, &mut n);
m %= n;
}
n.abs()
}
// gcd(-128, b) = 128 is not representable as positive value
// for i8
for i in -127..127 {
for j in -127..127 {
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
}
}
// last value
// FIXME: Use inclusive ranges for above loop when implemented
let i = 127;
for j in -127..127 {
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
}
assert_eq!(127.gcd(&127), 127);
}
#[test]
fn test_gcd_min_val() {
let min = <$T>::min_value();
let max = <$T>::max_value();
let max_pow2 = max / 2 + 1;
assert_eq!(min.gcd(&max), 1 as $T);
assert_eq!(max.gcd(&min), 1 as $T);
assert_eq!(min.gcd(&max_pow2), max_pow2);
assert_eq!(max_pow2.gcd(&min), max_pow2);
assert_eq!(min.gcd(&42), 2 as $T);
assert_eq!((42 as $T).gcd(&min), 2 as $T);
}
#[test]
#[should_panic]
fn test_gcd_min_val_min_val() {
let min = <$T>::min_value();
assert!(min.gcd(&min) >= 0);
}
#[test]
#[should_panic]
fn test_gcd_min_val_0() {
let min = <$T>::min_value();
assert!(min.gcd(&0) >= 0);
}
#[test]
#[should_panic]
fn test_gcd_0_min_val() {
let min = <$T>::min_value();
assert!((0 as $T).gcd(&min) >= 0);
}
#[test]
fn test_lcm() {
assert_eq!((1 as $T).lcm(&0), 0 as $T);
assert_eq!((0 as $T).lcm(&1), 0 as $T);
assert_eq!((1 as $T).lcm(&1), 1 as $T);
assert_eq!((-1 as $T).lcm(&1), 1 as $T);
assert_eq!((1 as $T).lcm(&-1), 1 as $T);
assert_eq!((-1 as $T).lcm(&-1), 1 as $T);
assert_eq!((8 as $T).lcm(&9), 72 as $T);
assert_eq!((11 as $T).lcm(&5), 55 as $T);
}
#[test]
fn test_even() {
assert_eq!((-4 as $T).is_even(), true);
assert_eq!((-3 as $T).is_even(), false);
assert_eq!((-2 as $T).is_even(), true);
assert_eq!((-1 as $T).is_even(), false);
assert_eq!((0 as $T).is_even(), true);
assert_eq!((1 as $T).is_even(), false);
assert_eq!((2 as $T).is_even(), true);
assert_eq!((3 as $T).is_even(), false);
assert_eq!((4 as $T).is_even(), true);
}
#[test]
fn test_odd() {
assert_eq!((-4 as $T).is_odd(), false);
assert_eq!((-3 as $T).is_odd(), true);
assert_eq!((-2 as $T).is_odd(), false);
assert_eq!((-1 as $T).is_odd(), true);
assert_eq!((0 as $T).is_odd(), false);
assert_eq!((1 as $T).is_odd(), true);
assert_eq!((2 as $T).is_odd(), false);
assert_eq!((3 as $T).is_odd(), true);
assert_eq!((4 as $T).is_odd(), false);
}
}
)
}
impl_integer_for_isize!(i8, test_integer_i8);
impl_integer_for_isize!(i16, test_integer_i16);
impl_integer_for_isize!(i32, test_integer_i32);
impl_integer_for_isize!(i64, test_integer_i64);
impl_integer_for_isize!(isize, test_integer_isize);
macro_rules! impl_integer_for_usize {
($T:ty, $test_mod:ident) => (
impl Integer for $T {
/// Unsigned integer division. Returns the same result as `div` (`/`).
#[inline]
fn div_floor(&self, other: &$T) -> $T { *self / *other }
/// Unsigned integer modulo operation. Returns the same result as `rem` (`%`).
#[inline]
fn mod_floor(&self, other: &$T) -> $T { *self % *other }
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`
#[inline]
fn gcd(&self, other: &$T) -> $T {
// Use Stein's algorithm
let mut m = *self;
let mut n = *other;
if m == 0 || n == 0 { return m | n }
// find common factors of 2
let shift = (m | n).trailing_zeros();
// divide n and m by 2 until odd
// m inside loop
n >>= n.trailing_zeros();
while m != 0 {
m >>= m.trailing_zeros();
if n > m { ::std::mem::swap(&mut n, &mut m) }
m -= n;
}
n << shift
}
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
#[inline]
fn lcm(&self, other: &$T) -> $T {
(*self * *other) / self.gcd(other)
}
/// Deprecated, use `is_multiple_of` instead.
#[inline]
fn divides(&self, other: &$T) -> bool { return self.is_multiple_of(other); }
/// Returns `true` if the number is a multiple of `other`.
#[inline]
fn is_multiple_of(&self, other: &$T) -> bool { *self % *other == 0 }
/// Returns `true` if the number is divisible by `2`.
#[inline]
fn is_even(&self) -> bool { (*self) & 1 == 0 }
/// Returns `true` if the number is not divisible by `2`.
#[inline]
fn is_odd(&self) -> bool { !(*self).is_even() }
/// Simultaneous truncated integer division and modulus.
#[inline]
fn div_rem(&self, other: &$T) -> ($T, $T) {
(*self / *other, *self % *other)
}
}
#[cfg(test)]
mod $test_mod {
use Integer;
#[test]
fn test_div_mod_floor() {
assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T);
assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T);
assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T));
assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T);
assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T);
assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T));
assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T);
assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T);
assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T));
}
#[test]
fn test_gcd() {
assert_eq!((10 as $T).gcd(&2), 2 as $T);
assert_eq!((10 as $T).gcd(&3), 1 as $T);
assert_eq!((0 as $T).gcd(&3), 3 as $T);
assert_eq!((3 as $T).gcd(&3), 3 as $T);
assert_eq!((56 as $T).gcd(&42), 14 as $T);
}
#[test]
fn test_gcd_cmp_with_euclidean() {
fn euclidean_gcd(mut m: $T, mut n: $T) -> $T {
while m != 0 {
::std::mem::swap(&mut m, &mut n);
m %= n;
}
n
}
for i in 0..255 {
for j in 0..255 {
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
}
}
// last value
// FIXME: Use inclusive ranges for above loop when implemented
let i = 255;
for j in 0..255 {
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
}
assert_eq!(255.gcd(&255), 255);
}
#[test]
fn test_lcm() {
assert_eq!((1 as $T).lcm(&0), 0 as $T);
assert_eq!((0 as $T).lcm(&1), 0 as $T);
assert_eq!((1 as $T).lcm(&1), 1 as $T);
assert_eq!((8 as $T).lcm(&9), 72 as $T);
assert_eq!((11 as $T).lcm(&5), 55 as $T);
assert_eq!((15 as $T).lcm(&17), 255 as $T);
}
#[test]
fn test_is_multiple_of() {
assert!((6 as $T).is_multiple_of(&(6 as $T)));
assert!((6 as $T).is_multiple_of(&(3 as $T)));
assert!((6 as $T).is_multiple_of(&(1 as $T)));
}
#[test]
fn test_even() {
assert_eq!((0 as $T).is_even(), true);
assert_eq!((1 as $T).is_even(), false);
assert_eq!((2 as $T).is_even(), true);
assert_eq!((3 as $T).is_even(), false);
assert_eq!((4 as $T).is_even(), true);
}
#[test]
fn test_odd() {
assert_eq!((0 as $T).is_odd(), false);
assert_eq!((1 as $T).is_odd(), true);
assert_eq!((2 as $T).is_odd(), false);
assert_eq!((3 as $T).is_odd(), true);
assert_eq!((4 as $T).is_odd(), false);
}
}
)
}
impl_integer_for_usize!(u8, test_integer_u8);
impl_integer_for_usize!(u16, test_integer_u16);
impl_integer_for_usize!(u32, test_integer_u32);
impl_integer_for_usize!(u64, test_integer_u64);
impl_integer_for_usize!(usize, test_integer_usize);

372
src/iter.rs Normal file
View File

@ -0,0 +1,372 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! External iterators for generic mathematics
use {Integer, Zero, One, CheckedAdd, ToPrimitive};
use std::ops::{Add, Sub};
/// An iterator over the range [start, stop)
#[derive(Clone)]
pub struct Range<A> {
state: A,
stop: A,
one: A
}
/// Returns an iterator over the given range [start, stop) (that is, starting
/// at start (inclusive), and ending at stop (exclusive)).
///
/// # Example
///
/// ```rust
/// use num::iter;
///
/// let array = [0, 1, 2, 3, 4];
///
/// for i in iter::range(0, 5) {
/// println!("{}", i);
/// assert_eq!(i, array[i]);
/// }
/// ```
#[inline]
pub fn range<A>(start: A, stop: A) -> Range<A>
where A: Add<A, Output = A> + PartialOrd + Clone + One
{
Range{state: start, stop: stop, one: One::one()}
}
// FIXME: rust-lang/rust#10414: Unfortunate type bound
impl<A> Iterator for Range<A>
where A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
if self.state < self.stop {
let result = self.state.clone();
self.state = self.state.clone() + self.one.clone();
Some(result)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
// This first checks if the elements are representable as i64. If they aren't, try u64 (to
// handle cases like range(huge, huger)). We don't use usize/int because the difference of
// the i64/u64 might lie within their range.
let bound = match self.state.to_i64() {
Some(a) => {
let sz = self.stop.to_i64().map(|b| b.checked_sub(a));
match sz {
Some(Some(bound)) => bound.to_usize(),
_ => None,
}
},
None => match self.state.to_u64() {
Some(a) => {
let sz = self.stop.to_u64().map(|b| b.checked_sub(a));
match sz {
Some(Some(bound)) => bound.to_usize(),
_ => None
}
},
None => None
}
};
match bound {
Some(b) => (b, Some(b)),
// Standard fallback for unbounded/unrepresentable bounds
None => (0, None)
}
}
}
/// `Integer` is required to ensure the range will be the same regardless of
/// the direction it is consumed.
impl<A> DoubleEndedIterator for Range<A>
where A: Integer + PartialOrd + Clone + ToPrimitive
{
#[inline]
fn next_back(&mut self) -> Option<A> {
if self.stop > self.state {
self.stop = self.stop.clone() - self.one.clone();
Some(self.stop.clone())
} else {
None
}
}
}
/// An iterator over the range [start, stop]
#[derive(Clone)]
pub struct RangeInclusive<A> {
range: Range<A>,
done: bool,
}
/// Return an iterator over the range [start, stop]
#[inline]
pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
where A: Add<A, Output = A> + PartialOrd + Clone + One
{
RangeInclusive{range: range(start, stop), done: false}
}
impl<A> Iterator for RangeInclusive<A>
where A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
match self.range.next() {
Some(x) => Some(x),
None => {
if !self.done && self.range.state == self.range.stop {
self.done = true;
Some(self.range.stop.clone())
} else {
None
}
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lo, hi) = self.range.size_hint();
if self.done {
(lo, hi)
} else {
let lo = lo.saturating_add(1);
let hi = match hi {
Some(x) => x.checked_add(1),
None => None
};
(lo, hi)
}
}
}
impl<A> DoubleEndedIterator for RangeInclusive<A>
where A: Sub<A, Output = A> + Integer + PartialOrd + Clone + ToPrimitive
{
#[inline]
fn next_back(&mut self) -> Option<A> {
if self.range.stop > self.range.state {
let result = self.range.stop.clone();
self.range.stop = self.range.stop.clone() - self.range.one.clone();
Some(result)
} else if !self.done && self.range.state == self.range.stop {
self.done = true;
Some(self.range.stop.clone())
} else {
None
}
}
}
/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
#[derive(Clone)]
pub struct RangeStep<A> {
state: A,
stop: A,
step: A,
rev: bool,
}
/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
#[inline]
pub fn range_step<A>(start: A, stop: A, step: A) -> RangeStep<A>
where A: CheckedAdd + PartialOrd + Clone + Zero
{
let rev = step < Zero::zero();
RangeStep{state: start, stop: stop, step: step, rev: rev}
}
impl<A> Iterator for RangeStep<A>
where A: CheckedAdd + PartialOrd + Clone
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
let result = self.state.clone();
match self.state.checked_add(&self.step) {
Some(x) => self.state = x,
None => self.state = self.stop.clone()
}
Some(result)
} else {
None
}
}
}
/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
#[derive(Clone)]
pub struct RangeStepInclusive<A> {
state: A,
stop: A,
step: A,
rev: bool,
done: bool,
}
/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
#[inline]
pub fn range_step_inclusive<A>(start: A, stop: A, step: A) -> RangeStepInclusive<A>
where A: CheckedAdd + PartialOrd + Clone + Zero
{
let rev = step < Zero::zero();
RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
}
impl<A> Iterator for RangeStepInclusive<A>
where A: CheckedAdd + PartialOrd + Clone + PartialEq
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
if !self.done && ((self.rev && self.state >= self.stop) ||
(!self.rev && self.state <= self.stop)) {
let result = self.state.clone();
match self.state.checked_add(&self.step) {
Some(x) => self.state = x,
None => self.done = true
}
Some(result)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use std::usize;
use std::ops::{Add, Mul};
use std::cmp::Ordering;
use {One, ToPrimitive};
#[test]
fn test_range() {
/// A mock type to check Range when ToPrimitive returns None
struct Foo;
impl ToPrimitive for Foo {
fn to_i64(&self) -> Option<i64> { None }
fn to_u64(&self) -> Option<u64> { None }
}
impl Add<Foo> for Foo {
type Output = Foo;
fn add(self, _: Foo) -> Foo {
Foo
}
}
impl PartialEq for Foo {
fn eq(&self, _: &Foo) -> bool {
true
}
}
impl PartialOrd for Foo {
fn partial_cmp(&self, _: &Foo) -> Option<Ordering> {
None
}
}
impl Clone for Foo {
fn clone(&self) -> Foo {
Foo
}
}
impl Mul<Foo> for Foo {
type Output = Foo;
fn mul(self, _: Foo) -> Foo {
Foo
}
}
impl One for Foo {
fn one() -> Foo {
Foo
}
}
assert!(super::range(0, 5).collect::<Vec<isize>>() == vec![0, 1, 2, 3, 4]);
assert!(super::range(-10, -1).collect::<Vec<isize>>() ==
vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
assert!(super::range(0, 5).rev().collect::<Vec<isize>>() == vec![4, 3, 2, 1, 0]);
assert_eq!(super::range(200, -5).count(), 0);
assert_eq!(super::range(200, -5).rev().count(), 0);
assert_eq!(super::range(200, 200).count(), 0);
assert_eq!(super::range(200, 200).rev().count(), 0);
assert_eq!(super::range(0, 100).size_hint(), (100, Some(100)));
// this test is only meaningful when sizeof usize < sizeof u64
assert_eq!(super::range(usize::MAX - 1, usize::MAX).size_hint(), (1, Some(1)));
assert_eq!(super::range(-10, -1).size_hint(), (9, Some(9)));
}
#[test]
fn test_range_inclusive() {
assert!(super::range_inclusive(0, 5).collect::<Vec<isize>>() ==
vec![0, 1, 2, 3, 4, 5]);
assert!(super::range_inclusive(0, 5).rev().collect::<Vec<isize>>() ==
vec![5, 4, 3, 2, 1, 0]);
assert_eq!(super::range_inclusive(200, -5).count(), 0);
assert_eq!(super::range_inclusive(200, -5).rev().count(), 0);
assert!(super::range_inclusive(200, 200).collect::<Vec<isize>>() == vec![200]);
assert!(super::range_inclusive(200, 200).rev().collect::<Vec<isize>>() == vec![200]);
}
#[test]
fn test_range_step() {
assert!(super::range_step(0, 20, 5).collect::<Vec<isize>>() ==
vec![0, 5, 10, 15]);
assert!(super::range_step(20, 0, -5).collect::<Vec<isize>>() ==
vec![20, 15, 10, 5]);
assert!(super::range_step(20, 0, -6).collect::<Vec<isize>>() ==
vec![20, 14, 8, 2]);
assert!(super::range_step(200u8, 255, 50).collect::<Vec<u8>>() ==
vec![200u8, 250]);
assert!(super::range_step(200, -5, 1).collect::<Vec<isize>>() == vec![]);
assert!(super::range_step(200, 200, 1).collect::<Vec<isize>>() == vec![]);
}
#[test]
fn test_range_step_inclusive() {
assert!(super::range_step_inclusive(0, 20, 5).collect::<Vec<isize>>() ==
vec![0, 5, 10, 15, 20]);
assert!(super::range_step_inclusive(20, 0, -5).collect::<Vec<isize>>() ==
vec![20, 15, 10, 5, 0]);
assert!(super::range_step_inclusive(20, 0, -6).collect::<Vec<isize>>() ==
vec![20, 14, 8, 2]);
assert!(super::range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>() ==
vec![200u8, 250]);
assert!(super::range_step_inclusive(200, -5, 1).collect::<Vec<isize>>() ==
vec![]);
assert!(super::range_step_inclusive(200, 200, 1).collect::<Vec<isize>>() ==
vec![200]);
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,565 +8,206 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Numeric traits for generic mathematics
//! A collection of numeric types and traits for Rust.
//!
//! ## Compatibility
//! This includes new types for big integers, rationals, and complex numbers,
//! new traits for generic programming on numeric properties like `Integer`,
//! and generic range iterators.
//!
//! The `num-traits` crate is tested for rustc 1.8 and greater.
//! ## Example
//!
//! This example uses the BigRational type and [Newton's method][newt] to
//! approximate a square root to arbitrary precision:
//!
//! ```
//! extern crate num;
//! # #[cfg(all(feature = "bigint", feature="rational"))]
//! # mod test {
//!
//! use num::FromPrimitive;
//! use num::bigint::BigInt;
//! use num::rational::{Ratio, BigRational};
//!
//! # pub
//! fn approx_sqrt(number: u64, iterations: usize) -> BigRational {
//! let start: Ratio<BigInt> = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap());
//! let mut approx = start.clone();
//!
//! for _ in 0..iterations {
//! approx = (&approx + (&start / &approx)) /
//! Ratio::from_integer(FromPrimitive::from_u64(2).unwrap());
//! }
//!
//! approx
//! }
//! # }
//! # #[cfg(not(all(feature = "bigint", feature="rational")))]
//! # mod test { pub fn approx_sqrt(n: u64, _: usize) -> u64 { n } }
//! # use test::approx_sqrt;
//!
//! fn main() {
//! println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416
//! }
//!
//! ```
//!
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
#![doc(html_logo_url = "http://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://rust-num.github.io/num/favicon.ico",
html_root_url = "http://rust-num.github.io/num/",
html_playground_url = "http://play.rust-lang.org/")]
#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
#![deny(unconditional_recursion)]
#![no_std]
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "rustc-serialize")]
extern crate rustc_serialize;
// Only `no_std` builds actually use `libm`.
#[cfg(all(not(feature = "std"), feature = "libm"))]
extern crate libm;
// Some of the tests of non-RNG-based functionality are randomized using the
// RNG-based functionality, so the RNG-based functionality needs to be enabled
// for tests.
#[cfg(any(feature = "rand", all(feature = "bigint", test)))]
extern crate rand;
use core::fmt;
use core::num::Wrapping;
use core::ops::{Add, Div, Mul, Rem, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
#[cfg(feature = "bigint")]
pub use bigint::{BigInt, BigUint};
#[cfg(feature = "rational")]
pub use rational::Rational;
#[cfg(all(feature = "rational", feature="bigint"))]
pub use rational::BigRational;
#[cfg(feature = "complex")]
pub use complex::Complex;
pub use integer::Integer;
pub use iter::{range, range_inclusive, range_step, range_step_inclusive};
pub use traits::{Num, Zero, One, Signed, Unsigned, Bounded,
Saturating, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
PrimInt, Float, ToPrimitive, FromPrimitive, NumCast, cast};
pub use bounds::Bounded;
#[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::*;`.
pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
pub use identities::{one, zero, One, Zero};
pub use int::PrimInt;
pub use ops::checked::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
};
pub use ops::inv::Inv;
pub use ops::mul_add::{MulAdd, MulAddAssign};
pub use ops::saturating::Saturating;
pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingShl, WrappingShr, WrappingSub};
pub use pow::{checked_pow, pow, Pow};
pub use sign::{abs, abs_sub, signum, Signed, Unsigned};
#[cfg(test)] use std::hash;
#[macro_use]
mod macros;
use std::ops::{Mul};
pub mod bounds;
pub mod cast;
pub mod float;
pub mod identities;
pub mod int;
pub mod ops;
pub mod pow;
pub mod real;
pub mod sign;
#[cfg(feature = "bigint")]
pub mod bigint;
pub mod complex;
pub mod integer;
pub mod iter;
pub mod traits;
#[cfg(feature = "rational")]
pub mod rational;
/// The base trait for numeric types, covering `0` and `1` values,
/// comparisons, basic numeric operations, and string conversion.
pub trait Num: PartialEq + Zero + One + NumOps {
type FromStrRadixErr;
/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }
/// Convert from a string and radix <= 36.
///
/// # Examples
///
/// ```rust
/// use num_traits::Num;
///
/// let result = <i32 as Num>::from_str_radix("27", 10);
/// assert_eq!(result, Ok(27));
///
/// let result = <i32 as Num>::from_str_radix("foo", 10);
/// assert!(result.is_err());
/// ```
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }
/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
value.abs()
}
/// The trait for types implementing basic numeric operations
/// The positive difference of two numbers.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumOps<Rhs = Self, Output = Self>:
Add<Rhs, Output = Output>
+ Sub<Rhs, Output = Output>
+ Mul<Rhs, Output = Output>
+ Div<Rhs, Output = Output>
+ Rem<Rhs, Output = Output>
{
/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
/// between `x` and `y` is returned.
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
x.abs_sub(&y)
}
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>
{
}
/// The trait for `Num` types which also implement numeric operations taking
/// the second operand by reference.
/// Returns the sign of the number.
///
/// 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> {}
/// The trait for references which implement numeric operations, taking the
/// second operand either by value or by reference.
/// For `f32` and `f64`:
///
/// 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> {}
/// The trait for types implementing numeric assignment operators (like `+=`).
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssignOps<Rhs = Self>:
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>
{
}
/// The trait for `Num` types which also implement assignment operators.
/// For signed integers:
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssign: Num + NumAssignOps {}
impl<T> NumAssign for T where T: Num + NumAssignOps {}
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }
/// The trait for `NumAssign` types which also implement assignment operations
/// taking the second operand by reference.
/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// 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> {}
/// # Example
///
/// ```rust
/// use num;
///
/// assert_eq!(num::pow(2i8, 4), 16);
/// assert_eq!(num::pow(6u8, 3), 216);
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
if exp == 0 { return T::one() }
macro_rules! int_trait_impl {
($name:ident for $($t:ty)*) => ($(
impl $name for $t {
type FromStrRadixErr = ::core::num::ParseIntError;
#[inline]
fn from_str_radix(s: &str, radix: u32)
-> Result<Self, ::core::num::ParseIntError>
{
<$t>::from_str_radix(s, radix)
}
while exp & 1 == 0 {
base = base.clone() * base;
exp >>= 1;
}
if exp == 1 { return base }
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = base.clone() * base;
if exp & 1 == 1 {
acc = acc * base.clone();
}
)*)
}
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);
impl<T: Num> Num for Wrapping<T>
where
Wrapping<T>: Add<Output = Wrapping<T>>
+ Sub<Output = Wrapping<T>>
+ Mul<Output = Wrapping<T>>
+ Div<Output = Wrapping<T>>
+ Rem<Output = Wrapping<T>>,
{
type FromStrRadixErr = T::FromStrRadixErr;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
T::from_str_radix(str, radix).map(Wrapping)
}
acc
}
#[derive(Debug)]
pub enum FloatErrorKind {
Empty,
Invalid,
}
// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
// so there's not really any way for us to reuse it.
#[derive(Debug)]
pub struct ParseFloatError {
pub kind: FloatErrorKind,
}
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num;
///
/// assert_eq!(num::checked_pow(2i8, 4), Some(16));
/// assert_eq!(num::checked_pow(7i8, 8), None);
/// assert_eq!(num::checked_pow(7u32, 8), Some(5_764_801));
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
if exp == 0 { return Some(T::one()) }
impl fmt::Display for ParseFloatError {
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",
};
description.fmt(f)
}
}
// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
// with this implementation ourselves until we want to make a breaking change.
// (would have to drop it from `Num` though)
macro_rules! float_trait_impl {
($name:ident for $($t:ident)*) => ($(
impl $name for $t {
type FromStrRadixErr = ParseFloatError;
fn from_str_radix(src: &str, radix: u32)
-> Result<Self, Self::FromStrRadixErr>
{
use self::FloatErrorKind::*;
use self::ParseFloatError as PFE;
// Special values
match src {
"inf" => return Ok(core::$t::INFINITY),
"-inf" => return Ok(core::$t::NEG_INFINITY),
"NaN" => return Ok(core::$t::NAN),
_ => {},
}
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
}
}
let (is_positive, src) = match slice_shift_char(src) {
None => return Err(PFE { kind: Empty }),
Some(('-', "")) => return Err(PFE { kind: Empty }),
Some(('-', src)) => (false, src),
Some((_, _)) => (true, src),
};
// The significand to accumulate
let mut sig = if is_positive { 0.0 } else { -0.0 };
// Necessary to detect overflow
let mut prev_sig = sig;
let mut cs = src.chars().enumerate();
// Exponent prefix and exponent index offset
let mut exp_info = None::<(char, usize)>;
// Parse the integer part of the significand
for (i, c) in cs.by_ref() {
match c.to_digit(radix) {
Some(digit) => {
// shift significand one digit left
sig = sig * (radix as $t);
// add/subtract current digit depending on sign
if is_positive {
sig = sig + ((digit as isize) as $t);
} else {
sig = sig - ((digit as isize) as $t);
}
// Detect overflow by comparing to last value, except
// if we've not seen any non-zero digits.
if prev_sig != 0.0 {
if is_positive && sig <= prev_sig
{ return Ok(core::$t::INFINITY); }
if !is_positive && sig >= prev_sig
{ return Ok(core::$t::NEG_INFINITY); }
// Detect overflow by reversing the shift-and-add process
if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
{ return Ok(core::$t::INFINITY); }
if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
{ return Ok(core::$t::NEG_INFINITY); }
}
prev_sig = sig;
},
None => match c {
'e' | 'E' | 'p' | 'P' => {
exp_info = Some((c, i + 1));
break; // start of exponent
},
'.' => {
break; // start of fractional part
},
_ => {
return Err(PFE { kind: Invalid });
},
},
}
}
// If we are not yet at the exponent parse the fractional
// part of the significand
if exp_info.is_none() {
let mut power = 1.0;
for (i, c) in cs.by_ref() {
match c.to_digit(radix) {
Some(digit) => {
// Decrease power one order of magnitude
power = power / (radix as $t);
// add/subtract current digit depending on sign
sig = if is_positive {
sig + (digit as $t) * power
} else {
sig - (digit as $t) * power
};
// Detect overflow by comparing to last value
if is_positive && sig < prev_sig
{ return Ok(core::$t::INFINITY); }
if !is_positive && sig > prev_sig
{ return Ok(core::$t::NEG_INFINITY); }
prev_sig = sig;
},
None => match c {
'e' | 'E' | 'p' | 'P' => {
exp_info = Some((c, i + 1));
break; // start of exponent
},
_ => {
return Err(PFE { kind: Invalid });
},
},
}
}
}
// Parse and calculate the exponent
let exp = match exp_info {
Some((c, offset)) => {
let base = match c {
'E' | 'e' if radix == 10 => 10.0,
'P' | 'p' if radix == 16 => 2.0,
_ => return Err(PFE { kind: Invalid }),
};
// Parse the exponent as decimal integer
let src = &src[offset..];
let (is_positive, exp) = match slice_shift_char(src) {
Some(('-', src)) => (false, src.parse::<usize>()),
Some(('+', src)) => (true, src.parse::<usize>()),
Some((_, _)) => (true, src.parse::<usize>()),
None => return Err(PFE { kind: Invalid }),
};
#[cfg(feature = "std")]
fn pow(base: $t, exp: usize) -> $t {
Float::powi(base, exp as i32)
}
// otherwise uses the generic `pow` from the root
match (is_positive, exp) {
(true, Ok(exp)) => pow(base, exp),
(false, Ok(exp)) => 1.0 / pow(base, exp),
(_, Err(_)) => return Err(PFE { kind: Invalid }),
}
},
None => 1.0, // no exponent
};
Ok(sig * exp)
}
macro_rules! optry {
( $ expr : expr ) => {
if let Some(val) = $expr { val } else { return None }
}
)*)
}
float_trait_impl!(Num for f32 f64);
/// A value bounded by a minimum and a maximum
///
/// 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");
if input < min {
min
} else if input > max {
max
} else {
input
}
}
/// 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]
fn from_str_radix_unwrap() {
// The Result error must impl Debug to allow unwrap()
let i: i32 = Num::from_str_radix("0", 10).unwrap();
assert_eq!(i, 0);
let f: f32 = Num::from_str_radix("0.0", 10).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) {}
require_num(&Wrapping(42_u32));
require_num(&Wrapping(-42));
}
#[test]
fn wrapping_from_str_radix() {
macro_rules! test_wrapping_from_str_radix {
($($t:ty)+) => {
$(
for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0);
assert_eq!(w, <$t as Num>::from_str_radix(s, r));
}
)+
};
}
test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
}
#[test]
fn check_num_ops() {
fn compute<T: Num + Copy>(x: T, y: T) -> T {
x * y / y % y + y - y
while exp & 1 == 0 {
base = optry!(base.checked_mul(&base));
exp >>= 1;
}
assert_eq!(compute(1, 2), 1)
}
if exp == 1 { return Some(base) }
#[test]
fn check_numref_ops() {
fn compute<T: NumRef>(x: T, y: &T) -> T {
x * y / y % y + y - y
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = optry!(base.checked_mul(&base));
if exp & 1 == 1 {
acc = optry!(acc.checked_mul(&base));
}
}
assert_eq!(compute(1, &2), 1)
Some(acc)
}
#[test]
fn check_refnum_ops() {
fn compute<T: Copy>(x: &T, y: T) -> T
where
for<'a> &'a T: RefNum<T>,
{
&(&(&(&(x * y) / y) % y) + y) - y
}
assert_eq!(compute(&1, 2), 1)
#[cfg(test)]
fn hash<T: hash::Hash>(x: &T) -> u64 {
use std::hash::Hasher;
let mut hasher = hash::SipHasher::new();
x.hash(&mut hasher);
hasher.finish()
}
#[test]
fn check_refref_ops() {
fn compute<T>(x: &T, y: &T) -> T
where
for<'a> &'a T: RefNum<T>,
{
&(&(&(&(x * y) / y) % y) + y) - y
}
assert_eq!(compute(&1, &2), 1)
}
#[test]
fn check_numassign_ops() {
fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
x *= y;
x /= y;
x %= y;
x += y;
x -= y;
x
}
assert_eq!(compute(1, 2), 1)
}
// TODO test `NumAssignRef`, but even the standard numeric types don't
// implement this yet. (see rust pr41336)

View File

@ -1,37 +0,0 @@
// not all are used in all features configurations
#![allow(unused)]
/// Forward a method to an inherent method or a base trait method.
macro_rules! forward {
($( Self :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method(self $( , $arg : $ty )* ) -> $ret {
Self::$method(self $( , $arg )* )
}
)*};
($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method(self $( , $arg : $ty )* ) -> $ret {
<Self as $base>::$method(self $( , $arg )* )
}
)*};
($( $base:ident :: $method:ident ( $( $arg:ident : $ty:ty ),* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method( $( $arg : $ty ),* ) -> $ret {
<Self as $base>::$method( $( $arg ),* )
}
)*}
}
macro_rules! constant {
($( $method:ident () -> $ret:expr ; )*)
=> {$(
#[inline]
fn $method() -> Self {
$ret
}
)*};
}

View File

@ -1,277 +0,0 @@
use core::ops::{Add, Div, Mul, Rem, Shl, Shr, Sub};
/// Performs addition that returns `None` instead of wrapping around on
/// overflow.
pub trait CheckedAdd: Sized + Add<Self, Output = Self> {
/// Adds two numbers, checking for overflow. If overflow happens, `None` is
/// returned.
fn checked_add(&self, v: &Self) -> Option<Self>;
}
macro_rules! checked_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, v: &$t) -> Option<$t> {
<$t>::$method(*self, *v)
}
}
};
}
checked_impl!(CheckedAdd, checked_add, u8);
checked_impl!(CheckedAdd, checked_add, u16);
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);
checked_impl!(CheckedAdd, checked_add, i16);
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.
pub trait CheckedSub: Sized + Sub<Self, Output = Self> {
/// Subtracts two numbers, checking for underflow. If underflow happens,
/// `None` is returned.
fn checked_sub(&self, v: &Self) -> Option<Self>;
}
checked_impl!(CheckedSub, checked_sub, u8);
checked_impl!(CheckedSub, checked_sub, u16);
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);
checked_impl!(CheckedSub, checked_sub, i16);
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
/// overflow.
pub trait CheckedMul: Sized + Mul<Self, Output = Self> {
/// Multiplies two numbers, checking for underflow or overflow. If underflow
/// or overflow happens, `None` is returned.
fn checked_mul(&self, v: &Self) -> Option<Self>;
}
checked_impl!(CheckedMul, checked_mul, u8);
checked_impl!(CheckedMul, checked_mul, u16);
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);
checked_impl!(CheckedMul, checked_mul, i16);
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
/// wrapping around on underflow and overflow.
pub trait CheckedDiv: Sized + Div<Self, Output = Self> {
/// Divides two numbers, checking for underflow, overflow and division by
/// zero. If any of that happens, `None` is returned.
fn checked_div(&self, v: &Self) -> Option<Self>;
}
checked_impl!(CheckedDiv, checked_div, u8);
checked_impl!(CheckedDiv, checked_div, u16);
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);
checked_impl!(CheckedDiv, checked_div, i16);
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
/// instead of wrapping around on underflow and overflow.
pub trait CheckedRem: Sized + Rem<Self, Output = Self> {
/// Finds the remainder of dividing two numbers, checking for underflow, overflow and division
/// by zero. If any of that happens, `None` is returned.
///
/// # Examples
///
/// ```
/// use num_traits::CheckedRem;
/// use std::i32::MIN;
///
/// assert_eq!(CheckedRem::checked_rem(&10, &7), Some(3));
/// assert_eq!(CheckedRem::checked_rem(&10, &-7), Some(3));
/// assert_eq!(CheckedRem::checked_rem(&-10, &7), Some(-3));
/// assert_eq!(CheckedRem::checked_rem(&-10, &-7), Some(-3));
///
/// assert_eq!(CheckedRem::checked_rem(&10, &0), None);
///
/// assert_eq!(CheckedRem::checked_rem(&MIN, &1), Some(0));
/// assert_eq!(CheckedRem::checked_rem(&MIN, &-1), None);
/// ```
fn checked_rem(&self, v: &Self) -> Option<Self>;
}
checked_impl!(CheckedRem, checked_rem, u8);
checked_impl!(CheckedRem, checked_rem, u16);
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);
checked_impl!(CheckedRem, checked_rem, i16);
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 {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
#[inline]
fn $method(&self) -> Option<$t> {
<$t>::$method(*self)
}
}
};
}
/// Performs negation that returns `None` if the result can't be represented.
pub trait CheckedNeg: Sized {
/// Negates a number, returning `None` for results that can't be represented, like signed `MIN`
/// values that can't be positive, or non-zero unsigned values that can't be negative.
///
/// # Examples
///
/// ```
/// use num_traits::CheckedNeg;
/// use std::i32::MIN;
///
/// assert_eq!(CheckedNeg::checked_neg(&1_i32), Some(-1));
/// assert_eq!(CheckedNeg::checked_neg(&-1_i32), Some(1));
/// assert_eq!(CheckedNeg::checked_neg(&MIN), None);
///
/// assert_eq!(CheckedNeg::checked_neg(&0_u32), Some(0));
/// assert_eq!(CheckedNeg::checked_neg(&1_u32), None);
/// ```
fn checked_neg(&self) -> Option<Self>;
}
checked_impl_unary!(CheckedNeg, checked_neg, u8);
checked_impl_unary!(CheckedNeg, checked_neg, u16);
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);
checked_impl_unary!(CheckedNeg, checked_neg, i16);
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.
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`.
///
/// ```
/// use num_traits::CheckedShl;
///
/// let x: u16 = 0x0001;
///
/// assert_eq!(CheckedShl::checked_shl(&x, 0), Some(0x0001));
/// assert_eq!(CheckedShl::checked_shl(&x, 1), Some(0x0002));
/// assert_eq!(CheckedShl::checked_shl(&x, 15), Some(0x8000));
/// assert_eq!(CheckedShl::checked_shl(&x, 16), None);
/// ```
fn checked_shl(&self, rhs: u32) -> Option<Self>;
}
macro_rules! checked_shift_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, rhs: u32) -> Option<$t> {
<$t>::$method(*self, rhs)
}
}
};
}
checked_shift_impl!(CheckedShl, checked_shl, u8);
checked_shift_impl!(CheckedShl, checked_shl, u16);
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);
checked_shift_impl!(CheckedShl, checked_shl, i16);
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.
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`.
///
/// ```
/// use num_traits::CheckedShr;
///
/// let x: u16 = 0x8000;
///
/// assert_eq!(CheckedShr::checked_shr(&x, 0), Some(0x8000));
/// assert_eq!(CheckedShr::checked_shr(&x, 1), Some(0x4000));
/// assert_eq!(CheckedShr::checked_shr(&x, 15), Some(0x0001));
/// assert_eq!(CheckedShr::checked_shr(&x, 16), None);
/// ```
fn checked_shr(&self, rhs: u32) -> Option<Self>;
}
checked_shift_impl!(CheckedShr, checked_shr, u8);
checked_shift_impl!(CheckedShr, checked_shr, u16);
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);
checked_shift_impl!(CheckedShr, checked_shr, i16);
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);

View File

@ -1,47 +0,0 @@
/// Unary operator for retrieving the multiplicative inverse, or reciprocal, of a value.
pub trait Inv {
/// The result after applying the operator.
type Output;
/// Returns the multiplicative inverse of `self`.
///
/// # Examples
///
/// ```
/// use std::f64::INFINITY;
/// use num_traits::Inv;
///
/// assert_eq!(7.0.inv() * 7.0, 1.0);
/// assert_eq!((-0.0).inv(), -INFINITY);
/// ```
fn inv(self) -> Self::Output;
}
impl Inv for f32 {
type Output = f32;
#[inline]
fn inv(self) -> f32 {
1.0 / self
}
}
impl Inv for f64 {
type Output = f64;
#[inline]
fn inv(self) -> f64 {
1.0 / self
}
}
impl<'a> Inv for &'a f32 {
type Output = f32;
#[inline]
fn inv(self) -> f32 {
1.0 / *self
}
}
impl<'a> Inv for &'a f64 {
type Output = f64;
#[inline]
fn inv(self) -> f64 {
1.0 / *self
}
}

View File

@ -1,5 +0,0 @@
pub mod checked;
pub mod inv;
pub mod mul_add;
pub mod saturating;
pub mod wrapping;

View File

@ -1,151 +0,0 @@
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error, yielding a more accurate result than an unfused multiply-add.
///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
/// Note that `A` and `B` are `Self` by default, but this is not mandatory.
///
/// # Example
///
/// ```
/// use std::f32;
///
/// let m = 10.0_f32;
/// let x = 4.0_f32;
/// let b = 60.0_f32;
///
/// // 100.0
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
///
/// assert!(abs_difference <= 100.0 * f32::EPSILON);
/// ```
pub trait MulAdd<A = Self, B = Self> {
/// The resulting type after applying the fused multiply-add.
type Output;
/// Performs the fused multiply-add operation.
fn mul_add(self, a: A, b: B) -> Self::Output;
}
/// The fused multiply-add assignment operation.
pub trait MulAddAssign<A = Self, B = Self> {
/// Performs the fused multiply-add operation.
fn mul_add_assign(&mut self, a: A, b: B);
}
#[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 {
<Self as ::Float>::mul_add(self, a, b)
}
}
#[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 {
<Self as ::Float>::mul_add(self, a, b)
}
}
macro_rules! mul_add_impl {
($trait_name:ident for $($t:ty)*) => {$(
impl $trait_name for $t {
type Output = Self;
#[inline]
fn mul_add(self, a: Self, b: Self) -> Self::Output {
(self * a) + b
}
}
)*}
}
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(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)
}
}
#[cfg(any(feature = "std", feature = "libm"))]
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)
}
}
macro_rules! mul_add_assign_impl {
($trait_name:ident for $($t:ty)*) => {$(
impl $trait_name for $t {
#[inline]
fn mul_add_assign(&mut self, a: Self, b: Self) {
*self = (*self * a) + b
}
}
)*}
}
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);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mul_add_integer() {
macro_rules! test_mul_add {
($($t:ident)+) => {
$(
{
let m: $t = 2;
let x: $t = 3;
let b: $t = 4;
assert_eq!(MulAdd::mul_add(m, x, b), (m*x + b));
}
)+
};
}
test_mul_add!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
}
#[test]
#[cfg(feature = "std")]
fn mul_add_float() {
macro_rules! test_mul_add {
($($t:ident)+) => {
$(
{
use core::$t;
let m: $t = 12.0;
let x: $t = 3.4;
let b: $t = 5.6;
let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs();
assert!(abs_difference <= 46.4 * $t::EPSILON);
}
)+
};
}
test_mul_add!(f32 f64);
}
}

View File

@ -1,30 +0,0 @@
/// Saturating math operations
pub trait Saturating {
/// Saturating addition operator.
/// Returns a+b, saturating at the numeric bounds instead of overflowing.
fn saturating_add(self, v: Self) -> Self;
/// Saturating subtraction operator.
/// Returns a-b, saturating at the numeric bounds instead of overflowing.
fn saturating_sub(self, v: Self) -> Self;
}
macro_rules! saturating_impl {
($trait_name:ident for $($t:ty)*) => {$(
impl $trait_name for $t {
#[inline]
fn saturating_add(self, v: Self) -> Self {
Self::saturating_add(self, v)
}
#[inline]
fn saturating_sub(self, v: Self) -> Self {
Self::saturating_sub(self, v)
}
}
)*}
}
saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
#[cfg(has_i128)]
saturating_impl!(Saturating for i128 u128);

View File

@ -1,272 +0,0 @@
use core::num::Wrapping;
use core::ops::{Add, Mul, Shl, Shr, Sub};
macro_rules! wrapping_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, v: &Self) -> Self {
<$t>::$method(*self, *v)
}
}
};
($trait_name:ident, $method:ident, $t:ty, $rhs:ty) => {
impl $trait_name<$rhs> for $t {
#[inline]
fn $method(&self, v: &$rhs) -> Self {
<$t>::$method(*self, *v)
}
}
};
}
/// Performs addition that wraps around on overflow.
pub trait WrappingAdd: Sized + Add<Self, Output = Self> {
/// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of
/// the type.
fn wrapping_add(&self, v: &Self) -> Self;
}
wrapping_impl!(WrappingAdd, wrapping_add, u8);
wrapping_impl!(WrappingAdd, wrapping_add, u16);
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);
wrapping_impl!(WrappingAdd, wrapping_add, i16);
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.
pub trait WrappingSub: Sized + Sub<Self, Output = Self> {
/// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary
/// of the type.
fn wrapping_sub(&self, v: &Self) -> Self;
}
wrapping_impl!(WrappingSub, wrapping_sub, u8);
wrapping_impl!(WrappingSub, wrapping_sub, u16);
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);
wrapping_impl!(WrappingSub, wrapping_sub, i16);
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.
pub trait WrappingMul: Sized + Mul<Self, Output = Self> {
/// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary
/// of the type.
fn wrapping_mul(&self, v: &Self) -> Self;
}
wrapping_impl!(WrappingMul, wrapping_mul, u8);
wrapping_impl!(WrappingMul, wrapping_mul, u16);
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);
wrapping_impl!(WrappingMul, wrapping_mul, i16);
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_shift_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, rhs: u32) -> $t {
<$t>::$method(*self, rhs)
}
}
};
}
/// Performs a left shift that does not panic.
pub trait WrappingShl: Sized + Shl<usize, Output = Self> {
/// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
/// where `mask` removes any high order bits of `rhs` that would
/// cause the shift to exceed the bitwidth of the type.
///
/// ```
/// use num_traits::WrappingShl;
///
/// let x: u16 = 0x0001;
///
/// assert_eq!(WrappingShl::wrapping_shl(&x, 0), 0x0001);
/// assert_eq!(WrappingShl::wrapping_shl(&x, 1), 0x0002);
/// assert_eq!(WrappingShl::wrapping_shl(&x, 15), 0x8000);
/// assert_eq!(WrappingShl::wrapping_shl(&x, 16), 0x0001);
/// ```
fn wrapping_shl(&self, rhs: u32) -> Self;
}
wrapping_shift_impl!(WrappingShl, wrapping_shl, u8);
wrapping_shift_impl!(WrappingShl, wrapping_shl, u16);
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);
wrapping_shift_impl!(WrappingShl, wrapping_shl, i16);
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.
pub trait WrappingShr: Sized + Shr<usize, Output = Self> {
/// Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
/// where `mask` removes any high order bits of `rhs` that would
/// cause the shift to exceed the bitwidth of the type.
///
/// ```
/// use num_traits::WrappingShr;
///
/// let x: u16 = 0x8000;
///
/// assert_eq!(WrappingShr::wrapping_shr(&x, 0), 0x8000);
/// assert_eq!(WrappingShr::wrapping_shr(&x, 1), 0x4000);
/// assert_eq!(WrappingShr::wrapping_shr(&x, 15), 0x0001);
/// assert_eq!(WrappingShr::wrapping_shr(&x, 16), 0x8000);
/// ```
fn wrapping_shr(&self, rhs: u32) -> Self;
}
wrapping_shift_impl!(WrappingShr, wrapping_shr, u8);
wrapping_shift_impl!(WrappingShr, wrapping_shr, u16);
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);
wrapping_shift_impl!(WrappingShr, wrapping_shr, i16);
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.
impl<T: WrappingAdd> WrappingAdd for Wrapping<T>
where
Wrapping<T>: Add<Output = Wrapping<T>>,
{
fn wrapping_add(&self, v: &Self) -> Self {
Wrapping(self.0.wrapping_add(&v.0))
}
}
impl<T: WrappingSub> WrappingSub for Wrapping<T>
where
Wrapping<T>: Sub<Output = Wrapping<T>>,
{
fn wrapping_sub(&self, v: &Self) -> Self {
Wrapping(self.0.wrapping_sub(&v.0))
}
}
impl<T: WrappingMul> WrappingMul for Wrapping<T>
where
Wrapping<T>: Mul<Output = Wrapping<T>>,
{
fn wrapping_mul(&self, v: &Self) -> Self {
Wrapping(self.0.wrapping_mul(&v.0))
}
}
impl<T: WrappingShl> WrappingShl for Wrapping<T>
where
Wrapping<T>: Shl<usize, Output = Wrapping<T>>,
{
fn wrapping_shl(&self, rhs: u32) -> Self {
Wrapping(self.0.wrapping_shl(rhs))
}
}
impl<T: WrappingShr> WrappingShr for Wrapping<T>
where
Wrapping<T>: Shr<usize, Output = Wrapping<T>>,
{
fn wrapping_shr(&self, rhs: u32) -> Self {
Wrapping(self.0.wrapping_shr(rhs))
}
}
#[test]
fn test_wrapping_traits() {
fn wrapping_add<T: WrappingAdd>(a: T, b: T) -> T {
a.wrapping_add(&b)
}
fn wrapping_sub<T: WrappingSub>(a: T, b: T) -> T {
a.wrapping_sub(&b)
}
fn wrapping_mul<T: WrappingMul>(a: T, b: T) -> T {
a.wrapping_mul(&b)
}
fn wrapping_shl<T: WrappingShl>(a: T, b: u32) -> T {
a.wrapping_shl(b)
}
fn wrapping_shr<T: WrappingShr>(a: T, b: u32) -> T {
a.wrapping_shr(b)
}
assert_eq!(wrapping_add(255, 1), 0u8);
assert_eq!(wrapping_sub(0, 1), 255u8);
assert_eq!(wrapping_mul(255, 2), 254u8);
assert_eq!(wrapping_shl(255, 8), 255u8);
assert_eq!(wrapping_shr(255, 8), 255u8);
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);
assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0);
assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0);
}
#[test]
fn wrapping_is_wrappingadd() {
fn require_wrappingadd<T: WrappingAdd>(_: &T) {}
require_wrappingadd(&Wrapping(42));
}
#[test]
fn wrapping_is_wrappingsub() {
fn require_wrappingsub<T: WrappingSub>(_: &T) {}
require_wrappingsub(&Wrapping(42));
}
#[test]
fn wrapping_is_wrappingmul() {
fn require_wrappingmul<T: WrappingMul>(_: &T) {}
require_wrappingmul(&Wrapping(42));
}
#[test]
fn wrapping_is_wrappingshl() {
fn require_wrappingshl<T: WrappingShl>(_: &T) {}
require_wrappingshl(&Wrapping(42));
}
#[test]
fn wrapping_is_wrappingshr() {
fn require_wrappingshr<T: WrappingShr>(_: &T) {}
require_wrappingshr(&Wrapping(42));
}

View File

@ -1,262 +0,0 @@
use core::num::Wrapping;
use core::ops::Mul;
use {CheckedMul, One};
/// Binary operator for raising a value to a power.
pub trait Pow<RHS> {
/// The result after applying the operator.
type Output;
/// Returns `self` to the power `rhs`.
///
/// # Examples
///
/// ```
/// use num_traits::Pow;
/// assert_eq!(Pow::pow(10u32, 2u32), 100);
/// ```
fn pow(self, rhs: RHS) -> Self::Output;
}
macro_rules! pow_impl {
($t:ty) => {
pow_impl!($t, u8);
pow_impl!($t, usize);
// FIXME: these should be possible
// pow_impl!($t, u16);
// pow_impl!($t, u32);
// pow_impl!($t, u64);
};
($t:ty, $rhs:ty) => {
pow_impl!($t, $rhs, usize, pow);
};
($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
impl Pow<$rhs> for $t {
type Output = $t;
#[inline]
fn pow(self, rhs: $rhs) -> $t {
($method)(self, <$desired_rhs>::from(rhs))
}
}
impl<'a> Pow<&'a $rhs> for $t {
type Output = $t;
#[inline]
fn pow(self, rhs: &'a $rhs) -> $t {
($method)(self, <$desired_rhs>::from(*rhs))
}
}
impl<'a> Pow<$rhs> for &'a $t {
type Output = $t;
#[inline]
fn pow(self, rhs: $rhs) -> $t {
($method)(*self, <$desired_rhs>::from(rhs))
}
}
impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
type Output = $t;
#[inline]
fn pow(self, rhs: &'a $rhs) -> $t {
($method)(*self, <$desired_rhs>::from(*rhs))
}
}
};
}
pow_impl!(u8, u8, u32, u8::pow);
pow_impl!(u8, u16, u32, u8::pow);
pow_impl!(u8, u32, u32, u8::pow);
pow_impl!(u8, usize);
pow_impl!(i8, u8, u32, i8::pow);
pow_impl!(i8, u16, u32, i8::pow);
pow_impl!(i8, u32, u32, i8::pow);
pow_impl!(i8, usize);
pow_impl!(u16, u8, u32, u16::pow);
pow_impl!(u16, u16, u32, u16::pow);
pow_impl!(u16, u32, u32, u16::pow);
pow_impl!(u16, usize);
pow_impl!(i16, u8, u32, i16::pow);
pow_impl!(i16, u16, u32, i16::pow);
pow_impl!(i16, u32, u32, i16::pow);
pow_impl!(i16, usize);
pow_impl!(u32, u8, u32, u32::pow);
pow_impl!(u32, u16, u32, u32::pow);
pow_impl!(u32, u32, u32, u32::pow);
pow_impl!(u32, usize);
pow_impl!(i32, u8, u32, i32::pow);
pow_impl!(i32, u16, u32, i32::pow);
pow_impl!(i32, u32, u32, i32::pow);
pow_impl!(i32, usize);
pow_impl!(u64, u8, u32, u64::pow);
pow_impl!(u64, u16, u32, u64::pow);
pow_impl!(u64, u32, u32, u64::pow);
pow_impl!(u64, usize);
pow_impl!(i64, u8, u32, i64::pow);
pow_impl!(i64, u16, u32, i64::pow);
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);
pow_impl!(usize, u16, u32, usize::pow);
pow_impl!(usize, u32, u32, usize::pow);
pow_impl!(usize, usize);
pow_impl!(isize, u8, u32, isize::pow);
pow_impl!(isize, u16, u32, isize::pow);
pow_impl!(isize, u32, u32, isize::pow);
pow_impl!(isize, usize);
pow_impl!(Wrapping<u8>);
pow_impl!(Wrapping<i8>);
pow_impl!(Wrapping<u16>);
pow_impl!(Wrapping<i16>);
pow_impl!(Wrapping<u32>);
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>);
// FIXME: these should be possible
// pow_impl!(u8, u64);
// pow_impl!(i16, u64);
// pow_impl!(i8, u64);
// pow_impl!(u16, u64);
// pow_impl!(u32, u64);
// pow_impl!(i32, u64);
// pow_impl!(u64, u64);
// pow_impl!(i64, u64);
// pow_impl!(usize, u64);
// pow_impl!(isize, u64);
#[cfg(any(feature = "std", feature = "libm"))]
mod float_impls {
use super::Pow;
use Float;
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)`) returns `1`. Mathematically this is undefined.
///
/// # Example
///
/// ```rust
/// use num_traits::pow;
///
/// assert_eq!(pow(2i8, 4), 16);
/// assert_eq!(pow(6u8, 3), 216);
/// assert_eq!(pow(0u8, 0), 1); // Be aware if this case affects you
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
if exp == 0 {
return T::one();
}
while exp & 1 == 0 {
base = base.clone() * base;
exp >>= 1;
}
if exp == 1 {
return base;
}
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = base.clone() * base;
if exp & 1 == 1 {
acc = acc * base.clone();
}
}
acc
}
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Note that `0⁰` (`checked_pow(0, 0)`) returns `Some(1)`. Mathematically this is undefined.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num_traits::checked_pow;
///
/// assert_eq!(checked_pow(2i8, 4), Some(16));
/// assert_eq!(checked_pow(7i8, 8), None);
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
/// assert_eq!(checked_pow(0u32, 0), Some(1)); // Be aware if this case affect you
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
if exp == 0 {
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));
exp >>= 1;
}
if exp == 1 {
return Some(base);
}
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = optry!(base.checked_mul(&base));
if exp & 1 == 1 {
acc = optry!(acc.checked_mul(&base));
}
}
Some(acc)
}

908
src/rational.rs Normal file
View File

@ -0,0 +1,908 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Rational numbers
use Integer;
use std::cmp;
use std::error::Error;
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use std::str::FromStr;
#[cfg(feature = "bigint")]
use bigint::{BigInt, BigUint, Sign};
use traits::{FromPrimitive, Float, PrimInt};
use {Num, Signed, Zero, One};
/// Represents the ratio between 2 numbers.
#[derive(Copy, Clone, Hash, Debug)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[allow(missing_docs)]
pub struct Ratio<T> {
numer: T,
denom: T
}
/// Alias for a `Ratio` of machine-sized integers.
pub type Rational = Ratio<isize>;
pub type Rational32 = Ratio<i32>;
pub type Rational64 = Ratio<i64>;
#[cfg(feature = "bigint")]
/// Alias for arbitrary precision rationals.
pub type BigRational = Ratio<BigInt>;
impl<T: Clone + Integer + PartialOrd> Ratio<T> {
/// Creates a ratio representing the integer `t`.
#[inline]
pub fn from_integer(t: T) -> Ratio<T> {
Ratio::new_raw(t, One::one())
}
/// Creates a ratio without checking for `denom == 0` or reducing.
#[inline]
pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
Ratio { numer: numer, denom: denom }
}
/// Create a new Ratio. Fails if `denom == 0`.
#[inline]
pub fn new(numer: T, denom: T) -> Ratio<T> {
if denom == Zero::zero() {
panic!("denominator == 0");
}
let mut ret = Ratio::new_raw(numer, denom);
ret.reduce();
ret
}
/// Converts to an integer.
#[inline]
pub fn to_integer(&self) -> T {
self.trunc().numer
}
/// Gets an immutable reference to the numerator.
#[inline]
pub fn numer<'a>(&'a self) -> &'a T {
&self.numer
}
/// Gets an immutable reference to the denominator.
#[inline]
pub fn denom<'a>(&'a self) -> &'a T {
&self.denom
}
/// Returns true if the rational number is an integer (denominator is 1).
#[inline]
pub fn is_integer(&self) -> bool {
self.denom == One::one()
}
/// Put self into lowest terms, with denom > 0.
fn reduce(&mut self) {
let g : T = self.numer.gcd(&self.denom);
// FIXME(#5992): assignment operator overloads
// self.numer /= g;
self.numer = self.numer.clone() / g.clone();
// FIXME(#5992): assignment operator overloads
// self.denom /= g;
self.denom = self.denom.clone() / g;
// keep denom positive!
if self.denom < T::zero() {
self.numer = T::zero() - self.numer.clone();
self.denom = T::zero() - self.denom.clone();
}
}
/// Returns a `reduce`d copy of self.
pub fn reduced(&self) -> Ratio<T> {
let mut ret = self.clone();
ret.reduce();
ret
}
/// Returns the reciprocal.
#[inline]
pub fn recip(&self) -> Ratio<T> {
Ratio::new_raw(self.denom.clone(), self.numer.clone())
}
/// Rounds towards minus infinity.
#[inline]
pub fn floor(&self) -> Ratio<T> {
if *self < Zero::zero() {
let one: T = One::one();
Ratio::from_integer((self.numer.clone() - self.denom.clone() + one) / self.denom.clone())
} else {
Ratio::from_integer(self.numer.clone() / self.denom.clone())
}
}
/// Rounds towards plus infinity.
#[inline]
pub fn ceil(&self) -> Ratio<T> {
if *self < Zero::zero() {
Ratio::from_integer(self.numer.clone() / self.denom.clone())
} else {
let one: T = One::one();
Ratio::from_integer((self.numer.clone() + self.denom.clone() - one) / self.denom.clone())
}
}
/// Rounds to the nearest integer. Rounds half-way cases away from zero.
#[inline]
pub fn round(&self) -> Ratio<T> {
let zero: Ratio<T> = Zero::zero();
let one: T = One::one();
let two: T = one.clone() + one.clone();
// Find unsigned fractional part of rational number
let mut fractional = self.fract();
if fractional < zero { fractional = zero - fractional };
// The algorithm compares the unsigned fractional part with 1/2, that
// is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
// a >= (b/2)+1. This avoids overflow issues.
let half_or_larger = if fractional.denom().is_even() {
*fractional.numer() >= fractional.denom().clone() / two.clone()
} else {
*fractional.numer() >= (fractional.denom().clone() / two.clone()) + one.clone()
};
if half_or_larger {
let one: Ratio<T> = One::one();
if *self >= Zero::zero() {
self.trunc() + one
} else {
self.trunc() - one
}
} else {
self.trunc()
}
}
/// Rounds towards zero.
#[inline]
pub fn trunc(&self) -> Ratio<T> {
Ratio::from_integer(self.numer.clone() / self.denom.clone())
}
/// Returns the fractional part of a number.
#[inline]
pub fn fract(&self) -> Ratio<T> {
Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone())
}
}
impl<T: Clone + Integer + PartialOrd + PrimInt> Ratio<T> {
/// Raises the ratio to the power of an exponent
#[inline]
pub fn pow(&self, expon: i32) -> Ratio<T> {
match expon.cmp(&0) {
cmp::Ordering::Equal => One::one(),
cmp::Ordering::Less => self.recip().pow(-expon),
cmp::Ordering::Greater => Ratio::new_raw(self.numer.pow(expon as u32),
self.denom.pow(expon as u32)),
}
}
}
#[cfg(feature = "bigint")]
impl Ratio<BigInt> {
/// Converts a float into a rational number.
pub fn from_float<T: Float>(f: T) -> Option<BigRational> {
if !f.is_finite() {
return None;
}
let (mantissa, exponent, sign) = f.integer_decode();
let bigint_sign = if sign == 1 { Sign::Plus } else { Sign::Minus };
if exponent < 0 {
let one: BigInt = One::one();
let denom: BigInt = one << ((-exponent) as usize);
let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
} else {
let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
numer = numer << (exponent as usize);
Some(Ratio::from_integer(BigInt::from_biguint(bigint_sign, numer)))
}
}
}
/* Comparisons */
// comparing a/b and c/d is the same as comparing a*d and b*c, so we
// abstract that pattern. The following macro takes a trait and either
// a comma-separated list of "method name -> return value" or just
// "method name" (return value is bool in that case)
macro_rules! cmp_impl {
(impl $imp:ident, $($method:ident),+) => {
cmp_impl!(impl $imp, $($method -> bool),+);
};
// return something other than a Ratio<T>
(impl $imp:ident, $($method:ident -> $res:ty),*) => {
impl<T> $imp for Ratio<T> where
T: Clone + Mul<T, Output = T> + $imp
{
$(
#[inline]
fn $method(&self, other: &Ratio<T>) -> $res {
(self.numer.clone() * other.denom.clone()). $method (&(self.denom.clone()*other.numer.clone()))
}
)*
}
};
}
cmp_impl!(impl PartialEq, eq, ne);
cmp_impl!(impl PartialOrd, lt -> bool, gt -> bool, le -> bool, ge -> bool,
partial_cmp -> Option<cmp::Ordering>);
cmp_impl!(impl Eq, );
cmp_impl!(impl Ord, cmp -> cmp::Ordering);
macro_rules! forward_val_val_binop {
(impl $imp:ident, $method:ident) => {
impl<T: Clone + Integer + PartialOrd> $imp<Ratio<T>> for Ratio<T> {
type Output = Ratio<T>;
#[inline]
fn $method(self, other: Ratio<T>) -> Ratio<T> {
(&self).$method(&other)
}
}
}
}
macro_rules! forward_ref_val_binop {
(impl $imp:ident, $method:ident) => {
impl<'a, T> $imp<Ratio<T>> for &'a Ratio<T> where
T: Clone + Integer + PartialOrd
{
type Output = Ratio<T>;
#[inline]
fn $method(self, other: Ratio<T>) -> Ratio<T> {
self.$method(&other)
}
}
}
}
macro_rules! forward_val_ref_binop {
(impl $imp:ident, $method:ident) => {
impl<'a, T> $imp<&'a Ratio<T>> for Ratio<T> where
T: Clone + Integer + PartialOrd
{
type Output = Ratio<T>;
#[inline]
fn $method(self, other: &Ratio<T>) -> Ratio<T> {
(&self).$method(other)
}
}
}
}
macro_rules! forward_all_binop {
(impl $imp:ident, $method:ident) => {
forward_val_val_binop!(impl $imp, $method);
forward_ref_val_binop!(impl $imp, $method);
forward_val_ref_binop!(impl $imp, $method);
};
}
/* Arithmetic */
forward_all_binop!(impl Mul, mul);
// a/b * c/d = (a*c)/(b*d)
impl<'a, 'b, T> Mul<&'b Ratio<T>> for &'a Ratio<T>
where T: Clone + Integer + PartialOrd
{
type Output = Ratio<T>;
#[inline]
fn mul(self, rhs: &Ratio<T>) -> Ratio<T> {
Ratio::new(self.numer.clone() * rhs.numer.clone(), self.denom.clone() * rhs.denom.clone())
}
}
forward_all_binop!(impl Div, div);
// (a/b) / (c/d) = (a*d)/(b*c)
impl<'a, 'b, T> Div<&'b Ratio<T>> for &'a Ratio<T>
where T: Clone + Integer + PartialOrd
{
type Output = Ratio<T>;
#[inline]
fn div(self, rhs: &Ratio<T>) -> Ratio<T> {
Ratio::new(self.numer.clone() * rhs.denom.clone(), self.denom.clone() * rhs.numer.clone())
}
}
// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern
macro_rules! arith_impl {
(impl $imp:ident, $method:ident) => {
forward_all_binop!(impl $imp, $method);
impl<'a, 'b, T: Clone + Integer + PartialOrd>
$imp<&'b Ratio<T>> for &'a Ratio<T> {
type Output = Ratio<T>;
#[inline]
fn $method(self, rhs: &Ratio<T>) -> Ratio<T> {
Ratio::new((self.numer.clone() * rhs.denom.clone()).$method(self.denom.clone() * rhs.numer.clone()),
self.denom.clone() * rhs.denom.clone())
}
}
}
}
// a/b + c/d = (a*d + b*c)/(b*d)
arith_impl!(impl Add, add);
// a/b - c/d = (a*d - b*c)/(b*d)
arith_impl!(impl Sub, sub);
// a/b % c/d = (a*d % b*c)/(b*d)
arith_impl!(impl Rem, rem);
impl<T> Neg for Ratio<T>
where T: Clone + Integer + PartialOrd + Neg<Output = T>
{
type Output = Ratio<T>;
#[inline]
fn neg(self) -> Ratio<T> { -&self }
}
impl<'a, T> Neg for &'a Ratio<T>
where T: Clone + Integer + PartialOrd + Neg<Output = T>
{
type Output = Ratio<T>;
#[inline]
fn neg(self) -> Ratio<T> {
Ratio::new_raw(-self.numer.clone(), self.denom.clone())
}
}
/* Constants */
impl<T: Clone + Integer + PartialOrd>
Zero for Ratio<T> {
#[inline]
fn zero() -> Ratio<T> {
Ratio::new_raw(Zero::zero(), One::one())
}
#[inline]
fn is_zero(&self) -> bool {
*self == Zero::zero()
}
}
impl<T: Clone + Integer + PartialOrd>
One for Ratio<T> {
#[inline]
fn one() -> Ratio<T> {
Ratio::new_raw(One::one(), One::one())
}
}
impl<T: Clone + Integer + PartialOrd> Num for Ratio<T> {
type FromStrRadixErr = ParseRatioError;
/// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
let split: Vec<&str> = s.splitn(2, '/').collect();
if split.len() < 2 {
Err(ParseRatioError{kind: RatioErrorKind::ParseError})
} else {
let a_result: Result<T, _> = T::from_str_radix(
split[0],
radix).map_err(|_| ParseRatioError{kind: RatioErrorKind::ParseError});
a_result.and_then(|a| {
let b_result: Result<T, _> =
T::from_str_radix(split[1], radix).map_err(
|_| ParseRatioError{kind: RatioErrorKind::ParseError});
b_result.and_then(|b| if b.is_zero() {
Err(ParseRatioError{kind: RatioErrorKind::ZeroDenominator})
} else {
Ok(Ratio::new(a.clone(), b.clone()))
})
})
}
}
}
impl<T: Clone + Integer + PartialOrd + Signed> Signed for Ratio<T> {
#[inline]
fn abs(&self) -> Ratio<T> {
if self.is_negative() { -self.clone() } else { self.clone() }
}
#[inline]
fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
if *self <= *other { Zero::zero() } else { self - other }
}
#[inline]
fn signum(&self) -> Ratio<T> {
if *self > Zero::zero() {
One::one()
} else if self.is_zero() {
Zero::zero()
} else {
- ::one::<Ratio<T>>()
}
}
#[inline]
fn is_positive(&self) -> bool { *self > Zero::zero() }
#[inline]
fn is_negative(&self) -> bool { *self < Zero::zero() }
}
/* String conversions */
impl<T> fmt::Display for Ratio<T> where
T: fmt::Display + Eq + One
{
/// Renders as `numer/denom`. If denom=1, renders as numer.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.denom == One::one() {
write!(f, "{}", self.numer)
} else {
write!(f, "{}/{}", self.numer, self.denom)
}
}
}
impl<T: FromStr + Clone + Integer + PartialOrd> FromStr for Ratio<T> {
type Err = ParseRatioError;
/// Parses `numer/denom` or just `numer`.
fn from_str(s: &str) -> Result<Ratio<T>, ParseRatioError> {
let mut split = s.splitn(2, '/');
let n = try!(split.next().ok_or(
ParseRatioError{kind: RatioErrorKind::ParseError}));
let num = try!(FromStr::from_str(n).map_err(
|_| ParseRatioError{kind: RatioErrorKind::ParseError}));
let d = split.next().unwrap_or("1");
let den = try!(FromStr::from_str(d).map_err(
|_| ParseRatioError{kind: RatioErrorKind::ParseError}));
if Zero::is_zero(&den) {
Err(ParseRatioError{kind: RatioErrorKind::ZeroDenominator})
} else {
Ok(Ratio::new(num, den))
}
}
}
// FIXME: Bubble up specific errors
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ParseRatioError { kind: RatioErrorKind }
#[derive(Copy, Clone, Debug, PartialEq)]
enum RatioErrorKind {
ParseError,
ZeroDenominator,
}
impl fmt::Display for ParseRatioError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl Error for ParseRatioError {
fn description(&self) -> &str { self.kind.description() }
}
impl RatioErrorKind {
fn description(&self) -> &'static str {
match *self {
RatioErrorKind::ParseError => "failed to parse integer",
RatioErrorKind::ZeroDenominator => "zero value denominator",
}
}
}
#[cfg(test)]
mod test {
use super::{Ratio, Rational};
#[cfg(feature = "bigint")]
use super::BigRational;
use std::str::FromStr;
use std::i32;
use {Zero, One, Signed, FromPrimitive, Float};
pub const _0 : Rational = Ratio { numer: 0, denom: 1};
pub const _1 : Rational = Ratio { numer: 1, denom: 1};
pub const _2: Rational = Ratio { numer: 2, denom: 1};
pub const _1_2: Rational = Ratio { numer: 1, denom: 2};
pub const _3_2: Rational = Ratio { numer: 3, denom: 2};
pub const _NEG1_2: Rational = Ratio { numer: -1, denom: 2};
pub const _1_3: Rational = Ratio { numer: 1, denom: 3};
pub const _NEG1_3: Rational = Ratio { numer: -1, denom: 3};
pub const _2_3: Rational = Ratio { numer: 2, denom: 3};
pub const _NEG2_3: Rational = Ratio { numer: -2, denom: 3};
#[cfg(feature = "bigint")]
pub fn to_big(n: Rational) -> BigRational {
Ratio::new(
FromPrimitive::from_isize(n.numer).unwrap(),
FromPrimitive::from_isize(n.denom).unwrap()
)
}
#[cfg(not(feature = "bigint"))]
pub fn to_big(n: Rational) -> Rational {
Ratio::new(
FromPrimitive::from_isize(n.numer).unwrap(),
FromPrimitive::from_isize(n.denom).unwrap()
)
}
#[test]
fn test_test_constants() {
// check our constants are what Ratio::new etc. would make.
assert_eq!(_0, Zero::zero());
assert_eq!(_1, One::one());
assert_eq!(_2, Ratio::from_integer(2));
assert_eq!(_1_2, Ratio::new(1,2));
assert_eq!(_3_2, Ratio::new(3,2));
assert_eq!(_NEG1_2, Ratio::new(-1,2));
}
#[test]
fn test_new_reduce() {
let one22 = Ratio::new(2,2);
assert_eq!(one22, One::one());
}
#[test]
#[should_panic]
fn test_new_zero() {
let _a = Ratio::new(1,0);
}
#[test]
fn test_cmp() {
assert!(_0 == _0 && _1 == _1);
assert!(_0 != _1 && _1 != _0);
assert!(_0 < _1 && !(_1 < _0));
assert!(_1 > _0 && !(_0 > _1));
assert!(_0 <= _0 && _1 <= _1);
assert!(_0 <= _1 && !(_1 <= _0));
assert!(_0 >= _0 && _1 >= _1);
assert!(_1 >= _0 && !(_0 >= _1));
}
#[test]
fn test_to_integer() {
assert_eq!(_0.to_integer(), 0);
assert_eq!(_1.to_integer(), 1);
assert_eq!(_2.to_integer(), 2);
assert_eq!(_1_2.to_integer(), 0);
assert_eq!(_3_2.to_integer(), 1);
assert_eq!(_NEG1_2.to_integer(), 0);
}
#[test]
fn test_numer() {
assert_eq!(_0.numer(), &0);
assert_eq!(_1.numer(), &1);
assert_eq!(_2.numer(), &2);
assert_eq!(_1_2.numer(), &1);
assert_eq!(_3_2.numer(), &3);
assert_eq!(_NEG1_2.numer(), &(-1));
}
#[test]
fn test_denom() {
assert_eq!(_0.denom(), &1);
assert_eq!(_1.denom(), &1);
assert_eq!(_2.denom(), &1);
assert_eq!(_1_2.denom(), &2);
assert_eq!(_3_2.denom(), &2);
assert_eq!(_NEG1_2.denom(), &2);
}
#[test]
fn test_is_integer() {
assert!(_0.is_integer());
assert!(_1.is_integer());
assert!(_2.is_integer());
assert!(!_1_2.is_integer());
assert!(!_3_2.is_integer());
assert!(!_NEG1_2.is_integer());
}
#[test]
fn test_show() {
assert_eq!(format!("{}", _2), "2".to_string());
assert_eq!(format!("{}", _1_2), "1/2".to_string());
assert_eq!(format!("{}", _0), "0".to_string());
assert_eq!(format!("{}", Ratio::from_integer(-2)), "-2".to_string());
}
mod arith {
use super::{_0, _1, _2, _1_2, _3_2, _NEG1_2, to_big};
use super::super::{Ratio, Rational};
#[test]
fn test_add() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a + b, c);
assert_eq!(to_big(a) + to_big(b), to_big(c));
}
test(_1, _1_2, _3_2);
test(_1, _1, _2);
test(_1_2, _3_2, _2);
test(_1_2, _NEG1_2, _0);
}
#[test]
fn test_sub() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a - b, c);
assert_eq!(to_big(a) - to_big(b), to_big(c))
}
test(_1, _1_2, _1_2);
test(_3_2, _1_2, _1);
test(_1, _NEG1_2, _3_2);
}
#[test]
fn test_mul() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a * b, c);
assert_eq!(to_big(a) * to_big(b), to_big(c))
}
test(_1, _1_2, _1_2);
test(_1_2, _3_2, Ratio::new(3,4));
test(_1_2, _NEG1_2, Ratio::new(-1, 4));
}
#[test]
fn test_div() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a / b, c);
assert_eq!(to_big(a) / to_big(b), to_big(c))
}
test(_1, _1_2, _2);
test(_3_2, _1_2, _1 + _2);
test(_1, _NEG1_2, _NEG1_2 + _NEG1_2 + _NEG1_2 + _NEG1_2);
}
#[test]
fn test_rem() {
fn test(a: Rational, b: Rational, c: Rational) {
assert_eq!(a % b, c);
assert_eq!(to_big(a) % to_big(b), to_big(c))
}
test(_3_2, _1, _1_2);
test(_2, _NEG1_2, _0);
test(_1_2, _2, _1_2);
}
#[test]
fn test_neg() {
fn test(a: Rational, b: Rational) {
assert_eq!(-a, b);
assert_eq!(-to_big(a), to_big(b))
}
test(_0, _0);
test(_1_2, _NEG1_2);
test(-_1, _1);
}
#[test]
fn test_zero() {
assert_eq!(_0 + _0, _0);
assert_eq!(_0 * _0, _0);
assert_eq!(_0 * _1, _0);
assert_eq!(_0 / _NEG1_2, _0);
assert_eq!(_0 - _0, _0);
}
#[test]
#[should_panic]
fn test_div_0() {
let _a = _1 / _0;
}
}
#[test]
fn test_round() {
assert_eq!(_1_3.ceil(), _1);
assert_eq!(_1_3.floor(), _0);
assert_eq!(_1_3.round(), _0);
assert_eq!(_1_3.trunc(), _0);
assert_eq!(_NEG1_3.ceil(), _0);
assert_eq!(_NEG1_3.floor(), -_1);
assert_eq!(_NEG1_3.round(), _0);
assert_eq!(_NEG1_3.trunc(), _0);
assert_eq!(_2_3.ceil(), _1);
assert_eq!(_2_3.floor(), _0);
assert_eq!(_2_3.round(), _1);
assert_eq!(_2_3.trunc(), _0);
assert_eq!(_NEG2_3.ceil(), _0);
assert_eq!(_NEG2_3.floor(), -_1);
assert_eq!(_NEG2_3.round(), -_1);
assert_eq!(_NEG2_3.trunc(), _0);
assert_eq!(_1_2.ceil(), _1);
assert_eq!(_1_2.floor(), _0);
assert_eq!(_1_2.round(), _1);
assert_eq!(_1_2.trunc(), _0);
assert_eq!(_NEG1_2.ceil(), _0);
assert_eq!(_NEG1_2.floor(), -_1);
assert_eq!(_NEG1_2.round(), -_1);
assert_eq!(_NEG1_2.trunc(), _0);
assert_eq!(_1.ceil(), _1);
assert_eq!(_1.floor(), _1);
assert_eq!(_1.round(), _1);
assert_eq!(_1.trunc(), _1);
// Overflow checks
let _neg1 = Ratio::from_integer(-1);
let _large_rat1 = Ratio::new(i32::MAX, i32::MAX-1);
let _large_rat2 = Ratio::new(i32::MAX-1, i32::MAX);
let _large_rat3 = Ratio::new(i32::MIN+2, i32::MIN+1);
let _large_rat4 = Ratio::new(i32::MIN+1, i32::MIN+2);
let _large_rat5 = Ratio::new(i32::MIN+2, i32::MAX);
let _large_rat6 = Ratio::new(i32::MAX, i32::MIN+2);
let _large_rat7 = Ratio::new(1, i32::MIN+1);
let _large_rat8 = Ratio::new(1, i32::MAX);
assert_eq!(_large_rat1.round(), One::one());
assert_eq!(_large_rat2.round(), One::one());
assert_eq!(_large_rat3.round(), One::one());
assert_eq!(_large_rat4.round(), One::one());
assert_eq!(_large_rat5.round(), _neg1);
assert_eq!(_large_rat6.round(), _neg1);
assert_eq!(_large_rat7.round(), Zero::zero());
assert_eq!(_large_rat8.round(), Zero::zero());
}
#[test]
fn test_fract() {
assert_eq!(_1.fract(), _0);
assert_eq!(_NEG1_2.fract(), _NEG1_2);
assert_eq!(_1_2.fract(), _1_2);
assert_eq!(_3_2.fract(), _1_2);
}
#[test]
fn test_recip() {
assert_eq!(_1 * _1.recip(), _1);
assert_eq!(_2 * _2.recip(), _1);
assert_eq!(_1_2 * _1_2.recip(), _1);
assert_eq!(_3_2 * _3_2.recip(), _1);
assert_eq!(_NEG1_2 * _NEG1_2.recip(), _1);
}
#[test]
fn test_pow() {
assert_eq!(_1_2.pow(2), Ratio::new(1, 4));
assert_eq!(_1_2.pow(-2), Ratio::new(4, 1));
assert_eq!(_1.pow(1), _1);
assert_eq!(_NEG1_2.pow(2), _1_2.pow(2));
assert_eq!(_NEG1_2.pow(3), -_1_2.pow(3));
assert_eq!(_3_2.pow(0), _1);
assert_eq!(_3_2.pow(-1), _3_2.recip());
assert_eq!(_3_2.pow(3), Ratio::new(27, 8));
}
#[test]
fn test_to_from_str() {
fn test(r: Rational, s: String) {
assert_eq!(FromStr::from_str(&s), Ok(r));
assert_eq!(r.to_string(), s);
}
test(_1, "1".to_string());
test(_0, "0".to_string());
test(_1_2, "1/2".to_string());
test(_3_2, "3/2".to_string());
test(_2, "2".to_string());
test(_NEG1_2, "-1/2".to_string());
}
#[test]
fn test_from_str_fail() {
fn test(s: &str) {
let rational: Result<Rational, _> = FromStr::from_str(s);
assert!(rational.is_err());
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "1/0"];
for &s in xs.iter() {
test(s);
}
}
#[cfg(feature = "bigint")]
#[test]
fn test_from_float() {
fn test<T: Float>(given: T, (numer, denom): (&str, &str)) {
let ratio: BigRational = Ratio::from_float(given).unwrap();
assert_eq!(ratio, Ratio::new(
FromStr::from_str(numer).unwrap(),
FromStr::from_str(denom).unwrap()));
}
// f32
test(3.14159265359f32, ("13176795", "4194304"));
test(2f32.powf(100.), ("1267650600228229401496703205376", "1"));
test(-2f32.powf(100.), ("-1267650600228229401496703205376", "1"));
test(1.0 / 2f32.powf(100.), ("1", "1267650600228229401496703205376"));
test(684729.48391f32, ("1369459", "2"));
test(-8573.5918555f32, ("-4389679", "512"));
// f64
test(3.14159265359f64, ("3537118876014453", "1125899906842624"));
test(2f64.powf(100.), ("1267650600228229401496703205376", "1"));
test(-2f64.powf(100.), ("-1267650600228229401496703205376", "1"));
test(684729.48391f64, ("367611342500051", "536870912"));
test(-8573.5918555f64, ("-4713381968463931", "549755813888"));
test(1.0 / 2f64.powf(100.), ("1", "1267650600228229401496703205376"));
}
#[cfg(feature = "bigint")]
#[test]
fn test_from_float_fail() {
use std::{f32, f64};
assert_eq!(Ratio::from_float(f32::NAN), None);
assert_eq!(Ratio::from_float(f32::INFINITY), None);
assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
assert_eq!(Ratio::from_float(f64::NAN), None);
assert_eq!(Ratio::from_float(f64::INFINITY), None);
assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);
}
#[test]
fn test_signed() {
assert_eq!(_NEG1_2.abs(), _1_2);
assert_eq!(_3_2.abs_sub(&_1_2), _1);
assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
assert_eq!(_1_2.signum(), One::one());
assert_eq!(_NEG1_2.signum(), - ::one::<Ratio<isize>>());
assert!(_NEG1_2.is_negative());
assert!(! _NEG1_2.is_positive());
assert!(! _1_2.is_negative());
}
#[test]
fn test_hash() {
assert!(::hash(&_0) != ::hash(&_1));
assert!(::hash(&_0) != ::hash(&_3_2));
}
}

View File

@ -1,834 +0,0 @@
#![cfg(any(feature = "std", feature = "libm"))]
use core::ops::Neg;
use {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`.
/// A trait for real number types that do not necessarily have
/// floating-point-specific characteristics such as NaN and infinity.
///
/// 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, 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.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x: f64 = Real::min_value();
///
/// assert_eq!(x, f64::MIN);
/// ```
fn min_value() -> Self;
/// Returns the smallest positive, normalized value that this type can represent.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x: f64 = Real::min_positive_value();
///
/// assert_eq!(x, f64::MIN_POSITIVE);
/// ```
fn min_positive_value() -> Self;
/// Returns epsilon, a small positive value.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x: f64 = Real::epsilon();
///
/// assert_eq!(x, f64::EPSILON);
/// ```
///
/// # Panics
///
/// The default implementation will panic if `f32::EPSILON` cannot
/// be cast to `Self`.
fn epsilon() -> Self;
/// Returns the largest finite value that this type can represent.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x: f64 = Real::max_value();
/// assert_eq!(x, f64::MAX);
/// ```
fn max_value() -> Self;
/// Returns the largest integer less than or equal to a number.
///
/// ```
/// use num_traits::real::Real;
///
/// let f = 3.99;
/// let g = 3.0;
///
/// assert_eq!(f.floor(), 3.0);
/// assert_eq!(g.floor(), 3.0);
/// ```
fn floor(self) -> Self;
/// Returns the smallest integer greater than or equal to a number.
///
/// ```
/// use num_traits::real::Real;
///
/// let f = 3.01;
/// let g = 4.0;
///
/// assert_eq!(f.ceil(), 4.0);
/// assert_eq!(g.ceil(), 4.0);
/// ```
fn ceil(self) -> Self;
/// Returns the nearest integer to a number. Round half-way cases away from
/// `0.0`.
///
/// ```
/// use num_traits::real::Real;
///
/// let f = 3.3;
/// let g = -3.3;
///
/// assert_eq!(f.round(), 3.0);
/// assert_eq!(g.round(), -3.0);
/// ```
fn round(self) -> Self;
/// Return the integer part of a number.
///
/// ```
/// use num_traits::real::Real;
///
/// let f = 3.3;
/// let g = -3.7;
///
/// assert_eq!(f.trunc(), 3.0);
/// assert_eq!(g.trunc(), -3.0);
/// ```
fn trunc(self) -> Self;
/// Returns the fractional part of a number.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 3.5;
/// let y = -3.5;
/// let abs_difference_x = (x.fract() - 0.5).abs();
/// let abs_difference_y = (y.fract() - (-0.5)).abs();
///
/// assert!(abs_difference_x < 1e-10);
/// assert!(abs_difference_y < 1e-10);
/// ```
fn fract(self) -> Self;
/// Computes the absolute value of `self`. Returns `Float::nan()` if the
/// number is `Float::nan()`.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x = 3.5;
/// let y = -3.5;
///
/// let abs_difference_x = (x.abs() - x).abs();
/// let abs_difference_y = (y.abs() - (-y)).abs();
///
/// assert!(abs_difference_x < 1e-10);
/// assert!(abs_difference_y < 1e-10);
///
/// assert!(::num_traits::Float::is_nan(f64::NAN.abs()));
/// ```
fn abs(self) -> Self;
/// Returns a number that represents the sign of `self`.
///
/// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
/// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
/// - `Float::nan()` if the number is `Float::nan()`
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let f = 3.5;
///
/// assert_eq!(f.signum(), 1.0);
/// assert_eq!(f64::NEG_INFINITY.signum(), -1.0);
///
/// assert!(f64::NAN.signum().is_nan());
/// ```
fn signum(self) -> Self;
/// Returns `true` if `self` is positive, including `+0.0`,
/// `Float::infinity()`, and with newer versions of Rust `f64::NAN`.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let neg_nan: f64 = -f64::NAN;
///
/// let f = 7.0;
/// let g = -7.0;
///
/// assert!(f.is_sign_positive());
/// assert!(!g.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 with newer versions of Rust `-f64::NAN`.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let nan: f64 = f64::NAN;
///
/// let f = 7.0;
/// let g = -7.0;
///
/// assert!(!f.is_sign_negative());
/// assert!(g.is_sign_negative());
/// assert!(!nan.is_sign_negative());
/// ```
fn is_sign_negative(self) -> bool;
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error, yielding a more accurate result than an unfused multiply-add.
///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
/// ```
/// use num_traits::real::Real;
///
/// let m = 10.0;
/// let x = 4.0;
/// let b = 60.0;
///
/// // 100.0
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn mul_add(self, a: Self, b: Self) -> Self;
/// Take the reciprocal (inverse) of a number, `1/x`.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 2.0;
/// let abs_difference = (x.recip() - (1.0/x)).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn recip(self) -> Self;
/// Raise a number to an integer power.
///
/// Using this function is generally faster than using `powf`
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 2.0;
/// let abs_difference = (x.powi(2) - x*x).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn powi(self, n: i32) -> Self;
/// Raise a number to a real number power.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 2.0;
/// let abs_difference = (x.powf(2.0) - x*x).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn powf(self, n: Self) -> Self;
/// Take the square root of a number.
///
/// Returns NaN if `self` is a negative floating-point number.
///
/// # Panics
///
/// If the implementing type doesn't support NaN, this method should panic if `self < 0`.
///
/// ```
/// use num_traits::real::Real;
///
/// let positive = 4.0;
/// let negative = -4.0;
///
/// let abs_difference = (positive.sqrt() - 2.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// assert!(::num_traits::Float::is_nan(negative.sqrt()));
/// ```
fn sqrt(self) -> Self;
/// Returns `e^(self)`, (the exponential function).
///
/// ```
/// use num_traits::real::Real;
///
/// let one = 1.0;
/// // e^1
/// let e = one.exp();
///
/// // ln(e) - 1 == 0
/// let abs_difference = (e.ln() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn exp(self) -> Self;
/// Returns `2^(self)`.
///
/// ```
/// use num_traits::real::Real;
///
/// let f = 2.0;
///
/// // 2^2 - 4 == 0
/// let abs_difference = (f.exp2() - 4.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn exp2(self) -> Self;
/// Returns the natural logarithm of the number.
///
/// # Panics
///
/// If `self <= 0` and this type does not support a NaN representation, this function should panic.
///
/// ```
/// use num_traits::real::Real;
///
/// let one = 1.0;
/// // e^1
/// let e = one.exp();
///
/// // ln(e) - 1 == 0
/// let abs_difference = (e.ln() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn ln(self) -> Self;
/// Returns the logarithm of the number with respect to an arbitrary base.
///
/// # Panics
///
/// If `self <= 0` and this type does not support a NaN representation, this function should panic.
///
/// ```
/// use num_traits::real::Real;
///
/// let ten = 10.0;
/// let two = 2.0;
///
/// // log10(10) - 1 == 0
/// let abs_difference_10 = (ten.log(10.0) - 1.0).abs();
///
/// // log2(2) - 1 == 0
/// let abs_difference_2 = (two.log(2.0) - 1.0).abs();
///
/// assert!(abs_difference_10 < 1e-10);
/// assert!(abs_difference_2 < 1e-10);
/// ```
fn log(self, base: Self) -> Self;
/// Returns the base 2 logarithm of the number.
///
/// # Panics
///
/// If `self <= 0` and this type does not support a NaN representation, this function should panic.
///
/// ```
/// use num_traits::real::Real;
///
/// let two = 2.0;
///
/// // log2(2) - 1 == 0
/// let abs_difference = (two.log2() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn log2(self) -> Self;
/// Returns the base 10 logarithm of the number.
///
/// # Panics
///
/// If `self <= 0` and this type does not support a NaN representation, this function should panic.
///
///
/// ```
/// use num_traits::real::Real;
///
/// let ten = 10.0;
///
/// // log10(10) - 1 == 0
/// let abs_difference = (ten.log10() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn log10(self) -> Self;
/// Converts radians to degrees.
///
/// ```
/// use std::f64::consts;
///
/// let angle = consts::PI;
///
/// let abs_difference = (angle.to_degrees() - 180.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn to_degrees(self) -> Self;
/// Converts degrees to radians.
///
/// ```
/// use std::f64::consts;
///
/// let angle = 180.0_f64;
///
/// let abs_difference = (angle.to_radians() - consts::PI).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn to_radians(self) -> Self;
/// Returns the maximum of the two numbers.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 1.0;
/// let y = 2.0;
///
/// assert_eq!(x.max(y), y);
/// ```
fn max(self, other: Self) -> Self;
/// Returns the minimum of the two numbers.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 1.0;
/// let y = 2.0;
///
/// assert_eq!(x.min(y), x);
/// ```
fn min(self, other: Self) -> Self;
/// The positive difference of two numbers.
///
/// * If `self <= other`: `0:0`
/// * Else: `self - other`
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 3.0;
/// let y = -3.0;
///
/// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs();
/// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs();
///
/// assert!(abs_difference_x < 1e-10);
/// assert!(abs_difference_y < 1e-10);
/// ```
fn abs_sub(self, other: Self) -> Self;
/// Take the cubic root of a number.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 8.0;
///
/// // x^(1/3) - 2 == 0
/// let abs_difference = (x.cbrt() - 2.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn cbrt(self) -> Self;
/// Calculate the length of the hypotenuse of a right-angle triangle given
/// legs of length `x` and `y`.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 2.0;
/// let y = 3.0;
///
/// // sqrt(x^2 + y^2)
/// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn hypot(self, other: Self) -> Self;
/// Computes the sine of a number (in radians).
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x = f64::consts::PI/2.0;
///
/// let abs_difference = (x.sin() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn sin(self) -> Self;
/// Computes the cosine of a number (in radians).
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x = 2.0*f64::consts::PI;
///
/// let abs_difference = (x.cos() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn cos(self) -> Self;
/// Computes the tangent of a number (in radians).
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x = f64::consts::PI/4.0;
/// let abs_difference = (x.tan() - 1.0).abs();
///
/// assert!(abs_difference < 1e-14);
/// ```
fn tan(self) -> Self;
/// Computes the arcsine of a number. Return value is in radians in
/// the range [-pi/2, pi/2] or NaN if the number is outside the range
/// [-1, 1].
///
/// # Panics
///
/// If this type does not support a NaN representation, this function should panic
/// if the number is outside the range [-1, 1].
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let f = f64::consts::PI / 2.0;
///
/// // asin(sin(pi/2))
/// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn asin(self) -> Self;
/// Computes the arccosine of a number. Return value is in radians in
/// the range [0, pi] or NaN if the number is outside the range
/// [-1, 1].
///
/// # Panics
///
/// If this type does not support a NaN representation, this function should panic
/// if the number is outside the range [-1, 1].
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let f = f64::consts::PI / 4.0;
///
/// // acos(cos(pi/4))
/// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn acos(self) -> Self;
/// Computes the arctangent of a number. Return value is in radians in the
/// range [-pi/2, pi/2];
///
/// ```
/// use num_traits::real::Real;
///
/// let f = 1.0;
///
/// // atan(tan(1))
/// let abs_difference = (f.tan().atan() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn atan(self) -> Self;
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`).
///
/// * `x = 0`, `y = 0`: `0`
/// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
/// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
/// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let pi = f64::consts::PI;
/// // All angles from horizontal right (+x)
/// // 45 deg counter-clockwise
/// let x1 = 3.0;
/// let y1 = -3.0;
///
/// // 135 deg clockwise
/// let x2 = -3.0;
/// let y2 = 3.0;
///
/// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs();
/// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs();
///
/// assert!(abs_difference_1 < 1e-10);
/// assert!(abs_difference_2 < 1e-10);
/// ```
fn atan2(self, other: Self) -> Self;
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
/// `(sin(x), cos(x))`.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x = f64::consts::PI/4.0;
/// let f = x.sin_cos();
///
/// let abs_difference_0 = (f.0 - x.sin()).abs();
/// let abs_difference_1 = (f.1 - x.cos()).abs();
///
/// assert!(abs_difference_0 < 1e-10);
/// assert!(abs_difference_0 < 1e-10);
/// ```
fn sin_cos(self) -> (Self, Self);
/// Returns `e^(self) - 1` in a way that is accurate even if the
/// number is close to zero.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 7.0;
///
/// // e^(ln(7)) - 1
/// let abs_difference = (x.ln().exp_m1() - 6.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn exp_m1(self) -> Self;
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
/// the operations were performed separately.
///
/// # Panics
///
/// If this type does not support a NaN representation, this function should panic
/// if `self-1 <= 0`.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let x = f64::consts::E - 1.0;
///
/// // ln(1 + (e - 1)) == ln(e) == 1
/// let abs_difference = (x.ln_1p() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn ln_1p(self) -> Self;
/// Hyperbolic sine function.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let e = f64::consts::E;
/// let x = 1.0;
///
/// let f = x.sinh();
/// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
/// let g = (e*e - 1.0)/(2.0*e);
/// let abs_difference = (f - g).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn sinh(self) -> Self;
/// Hyperbolic cosine function.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let e = f64::consts::E;
/// let x = 1.0;
/// let f = x.cosh();
/// // Solving cosh() at 1 gives this result
/// let g = (e*e + 1.0)/(2.0*e);
/// let abs_difference = (f - g).abs();
///
/// // Same result
/// assert!(abs_difference < 1.0e-10);
/// ```
fn cosh(self) -> Self;
/// Hyperbolic tangent function.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let e = f64::consts::E;
/// let x = 1.0;
///
/// let f = x.tanh();
/// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
/// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2));
/// let abs_difference = (f - g).abs();
///
/// assert!(abs_difference < 1.0e-10);
/// ```
fn tanh(self) -> Self;
/// Inverse hyperbolic sine function.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 1.0;
/// let f = x.sinh().asinh();
///
/// let abs_difference = (f - x).abs();
///
/// assert!(abs_difference < 1.0e-10);
/// ```
fn asinh(self) -> Self;
/// Inverse hyperbolic cosine function.
///
/// ```
/// use num_traits::real::Real;
///
/// let x = 1.0;
/// let f = x.cosh().acosh();
///
/// let abs_difference = (f - x).abs();
///
/// assert!(abs_difference < 1.0e-10);
/// ```
fn acosh(self) -> Self;
/// Inverse hyperbolic tangent function.
///
/// ```
/// use num_traits::real::Real;
/// use std::f64;
///
/// let e = f64::consts::E;
/// let f = e.tanh().atanh();
///
/// let abs_difference = (f - e).abs();
///
/// assert!(abs_difference < 1.0e-10);
/// ```
fn atanh(self) -> Self;
}
impl<T: Float> Real for T {
forward! {
Float::min_value() -> Self;
Float::min_positive_value() -> Self;
Float::epsilon() -> Self;
Float::max_value() -> Self;
}
forward! {
Float::floor(self) -> Self;
Float::ceil(self) -> Self;
Float::round(self) -> Self;
Float::trunc(self) -> Self;
Float::fract(self) -> Self;
Float::abs(self) -> Self;
Float::signum(self) -> Self;
Float::is_sign_positive(self) -> bool;
Float::is_sign_negative(self) -> bool;
Float::mul_add(self, a: Self, b: Self) -> Self;
Float::recip(self) -> Self;
Float::powi(self, n: i32) -> Self;
Float::powf(self, n: Self) -> Self;
Float::sqrt(self) -> Self;
Float::exp(self) -> Self;
Float::exp2(self) -> Self;
Float::ln(self) -> Self;
Float::log(self, base: Self) -> Self;
Float::log2(self) -> Self;
Float::log10(self) -> Self;
Float::to_degrees(self) -> Self;
Float::to_radians(self) -> Self;
Float::max(self, other: Self) -> Self;
Float::min(self, other: Self) -> Self;
Float::abs_sub(self, other: Self) -> Self;
Float::cbrt(self) -> Self;
Float::hypot(self, other: Self) -> Self;
Float::sin(self) -> Self;
Float::cos(self) -> Self;
Float::tan(self) -> Self;
Float::asin(self) -> Self;
Float::acos(self) -> Self;
Float::atan(self) -> Self;
Float::atan2(self, other: Self) -> Self;
Float::sin_cos(self) -> (Self, Self);
Float::exp_m1(self) -> Self;
Float::ln_1p(self) -> Self;
Float::sinh(self) -> Self;
Float::cosh(self) -> Self;
Float::tanh(self) -> Self;
Float::asinh(self) -> Self;
Float::acosh(self) -> Self;
Float::atanh(self) -> Self;
}
}

View File

@ -1,225 +0,0 @@
use core::num::Wrapping;
use core::ops::Neg;
use float::FloatCore;
use Num;
/// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Sized + Num + Neg<Output = Self> {
/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
fn abs(&self) -> Self;
/// The positive difference of two numbers.
///
/// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
/// between `self` and `other` is returned.
fn abs_sub(&self, other: &Self) -> Self;
/// Returns the sign of the number.
///
/// For `f32` and `f64`:
///
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
fn signum(&self) -> Self;
/// Returns true if the number is positive and false if the number is zero or negative.
fn is_positive(&self) -> bool;
/// Returns true if the number is negative and false if the number is zero or positive.
fn is_negative(&self) -> bool;
}
macro_rules! signed_impl {
($($t:ty)*) => ($(
impl Signed for $t {
#[inline]
fn abs(&self) -> $t {
if self.is_negative() { -*self } else { *self }
}
#[inline]
fn abs_sub(&self, other: &$t) -> $t {
if *self <= *other { 0 } else { *self - *other }
}
#[inline]
fn signum(&self) -> $t {
match *self {
n if n > 0 => 1,
0 => 0,
_ => -1,
}
}
#[inline]
fn is_positive(&self) -> bool { *self > 0 }
#[inline]
fn is_negative(&self) -> bool { *self < 0 }
}
)*)
}
signed_impl!(isize i8 i16 i32 i64);
#[cfg(has_i128)]
signed_impl!(i128);
impl<T: Signed> Signed for Wrapping<T>
where
Wrapping<T>: Num + Neg<Output = Wrapping<T>>,
{
#[inline]
fn abs(&self) -> Self {
Wrapping(self.0.abs())
}
#[inline]
fn abs_sub(&self, other: &Self) -> Self {
Wrapping(self.0.abs_sub(&other.0))
}
#[inline]
fn signum(&self) -> Self {
Wrapping(self.0.signum())
}
#[inline]
fn is_positive(&self) -> bool {
self.0.is_positive()
}
#[inline]
fn is_negative(&self) -> bool {
self.0.is_negative()
}
}
macro_rules! signed_float_impl {
($t:ty) => {
impl Signed for $t {
/// Computes the absolute value. Returns `NAN` if the number is `NAN`.
#[inline]
fn abs(&self) -> $t {
FloatCore::abs(*self)
}
/// The positive difference of two numbers. Returns `0.0` if the number is
/// less than or equal to `other`, otherwise the difference between`self`
/// and `other` is returned.
#[inline]
fn abs_sub(&self, other: &$t) -> $t {
if *self <= *other {
0.
} else {
*self - *other
}
}
/// # Returns
///
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// - `NAN` if the number is NaN
#[inline]
fn signum(&self) -> $t {
FloatCore::signum(*self)
}
/// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
#[inline]
fn is_positive(&self) -> bool {
FloatCore::is_sign_positive(*self)
}
/// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
#[inline]
fn is_negative(&self) -> bool {
FloatCore::is_sign_negative(*self)
}
}
};
}
signed_float_impl!(f32);
signed_float_impl!(f64);
/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
///
/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
value.abs()
}
/// The positive difference of two numbers.
///
/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
/// between `x` and `y` is returned.
#[inline(always)]
pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
x.abs_sub(&y)
}
/// Returns the sign of the number.
///
/// For `f32` and `f64`:
///
/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// * `-1` if the number is negative
#[inline(always)]
pub fn signum<T: Signed>(value: T) -> T {
value.signum()
}
/// A trait for values which cannot be negative
pub trait Unsigned: Num {}
macro_rules! empty_trait_impl {
($name:ident for $($t:ty)*) => ($(
impl $name for $t {}
)*)
}
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 {}
#[test]
fn unsigned_wrapping_is_unsigned() {
fn require_unsigned<T: Unsigned>(_: &T) {}
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));
}
*/

2552
src/traits.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,396 +0,0 @@
//! Tests of `num_traits::cast`.
#![no_std]
#[cfg(feature = "std")]
#[macro_use]
extern crate std;
extern crate num_traits;
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::fmt::Debug;
use core::mem;
use core::num::Wrapping;
#[test]
fn to_primitive_float() {
let f32_toolarge = 1e39f64;
assert_eq!(f32_toolarge.to_f32(), None);
assert_eq!((f32::MAX as f64).to_f32(), Some(f32::MAX));
assert_eq!((-f32::MAX as f64).to_f32(), Some(-f32::MAX));
assert_eq!(f64::INFINITY.to_f32(), Some(f32::INFINITY));
assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY));
assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan()));
}
#[test]
fn wrapping_to_primitive() {
macro_rules! test_wrapping_to_primitive {
($($t:ty)+) => {
$({
let i: $t = 0;
let w = Wrapping(i);
assert_eq!(i.to_u8(), w.to_u8());
assert_eq!(i.to_u16(), w.to_u16());
assert_eq!(i.to_u32(), w.to_u32());
assert_eq!(i.to_u64(), w.to_u64());
assert_eq!(i.to_usize(), w.to_usize());
assert_eq!(i.to_i8(), w.to_i8());
assert_eq!(i.to_i16(), w.to_i16());
assert_eq!(i.to_i32(), w.to_i32());
assert_eq!(i.to_i64(), w.to_i64());
assert_eq!(i.to_isize(), w.to_isize());
assert_eq!(i.to_f32(), w.to_f32());
assert_eq!(i.to_f64(), w.to_f64());
})+
};
}
test_wrapping_to_primitive!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
}
#[test]
fn wrapping_is_toprimitive() {
fn require_toprimitive<T: ToPrimitive>(_: &T) {}
require_toprimitive(&Wrapping(42));
}
#[test]
fn wrapping_is_fromprimitive() {
fn require_fromprimitive<T: FromPrimitive>(_: &T) {}
require_fromprimitive(&Wrapping(42));
}
#[test]
fn wrapping_is_numcast() {
fn require_numcast<T: NumCast>(_: &T) {}
require_numcast(&Wrapping(42));
}
#[test]
fn as_primitive() {
let x: f32 = (1.625f64).as_();
assert_eq!(x, 1.625f32);
let x: f32 = (3.14159265358979323846f64).as_();
assert_eq!(x, 3.1415927f32);
let x: u8 = (768i16).as_();
assert_eq!(x, 0);
}
#[test]
fn float_to_integer_checks_overflow() {
// This will overflow an i32
let source: f64 = 1.0e+123f64;
// Expect the overflow to be caught
assert_eq!(cast::<f64, i32>(source), None);
}
#[test]
fn cast_to_int_checks_overflow() {
let big_f: f64 = 1.0e123;
let normal_f: f64 = 1.0;
let small_f: f64 = -1.0e123;
assert_eq!(None, cast::<f64, isize>(big_f));
assert_eq!(None, cast::<f64, i8>(big_f));
assert_eq!(None, cast::<f64, i16>(big_f));
assert_eq!(None, cast::<f64, i32>(big_f));
assert_eq!(None, cast::<f64, i64>(big_f));
assert_eq!(Some(normal_f as isize), cast::<f64, isize>(normal_f));
assert_eq!(Some(normal_f as i8), cast::<f64, i8>(normal_f));
assert_eq!(Some(normal_f as i16), cast::<f64, i16>(normal_f));
assert_eq!(Some(normal_f as i32), cast::<f64, i32>(normal_f));
assert_eq!(Some(normal_f as i64), cast::<f64, i64>(normal_f));
assert_eq!(None, cast::<f64, isize>(small_f));
assert_eq!(None, cast::<f64, i8>(small_f));
assert_eq!(None, cast::<f64, i16>(small_f));
assert_eq!(None, cast::<f64, i32>(small_f));
assert_eq!(None, cast::<f64, i64>(small_f));
}
#[test]
fn cast_to_unsigned_int_checks_overflow() {
let big_f: f64 = 1.0e123;
let normal_f: f64 = 1.0;
let small_f: f64 = -1.0e123;
assert_eq!(None, cast::<f64, usize>(big_f));
assert_eq!(None, cast::<f64, u8>(big_f));
assert_eq!(None, cast::<f64, u16>(big_f));
assert_eq!(None, cast::<f64, u32>(big_f));
assert_eq!(None, cast::<f64, u64>(big_f));
assert_eq!(Some(normal_f as usize), cast::<f64, usize>(normal_f));
assert_eq!(Some(normal_f as u8), cast::<f64, u8>(normal_f));
assert_eq!(Some(normal_f as u16), cast::<f64, u16>(normal_f));
assert_eq!(Some(normal_f as u32), cast::<f64, u32>(normal_f));
assert_eq!(Some(normal_f as u64), cast::<f64, u64>(normal_f));
assert_eq!(None, cast::<f64, usize>(small_f));
assert_eq!(None, cast::<f64, u8>(small_f));
assert_eq!(None, cast::<f64, u16>(small_f));
assert_eq!(None, cast::<f64, u32>(small_f));
assert_eq!(None, cast::<f64, u64>(small_f));
}
#[test]
#[cfg(has_i128)]
fn cast_to_i128_checks_overflow() {
let big_f: f64 = 1.0e123;
let normal_f: f64 = 1.0;
let small_f: f64 = -1.0e123;
assert_eq!(None, cast::<f64, i128>(big_f));
assert_eq!(None, cast::<f64, u128>(big_f));
assert_eq!(Some(normal_f as i128), cast::<f64, i128>(normal_f));
assert_eq!(Some(normal_f as u128), cast::<f64, u128>(normal_f));
assert_eq!(None, cast::<f64, i128>(small_f));
assert_eq!(None, cast::<f64, u128>(small_f));
}
#[cfg(feature = "std")]
fn dbg(args: ::core::fmt::Arguments) {
println!("{}", args);
}
#[cfg(not(feature = "std"))]
fn dbg(_: ::core::fmt::Arguments) {}
// Rust 1.8 doesn't handle cfg on macros correctly
macro_rules! dbg { ($($tok:tt)*) => { dbg(format_args!($($tok)*)) } }
macro_rules! float_test_edge {
($f:ident -> $($t:ident)+) => { $({
dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t));
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()
};
let fmin = small.raw_offset(-1);
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));
assert_eq!(None, cast::<$f, $t>(small));
let (max, large) = if mem::size_of::<$t>() < mem::size_of::<$f>() {
($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
assert_eq!(max.count_ones(), $f::MANTISSA_DIGITS);
(max, large)
};
let fmax = large.raw_offset(-1);
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));
assert_eq!(None, cast::<$f, $t>(large));
dbg!(" testing non-finite values");
assert_eq!(None, cast::<$f, $t>($f::NAN));
assert_eq!(None, cast::<$f, $t>($f::INFINITY));
assert_eq!(None, cast::<$f, $t>($f::NEG_INFINITY));
})+}
}
trait RawOffset: Sized {
type Raw;
fn raw_offset(self, offset: Self::Raw) -> 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)
}
}
}
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)
}
}
}
#[test]
fn cast_float_to_int_edge_cases() {
float_test_edge!(f32 -> isize i8 i16 i32 i64);
float_test_edge!(f32 -> usize u8 u16 u32 u64);
float_test_edge!(f64 -> isize i8 i16 i32 i64);
float_test_edge!(f64 -> usize u8 u16 u32 u64);
}
#[test]
#[cfg(has_i128)]
fn cast_float_to_i128_edge_cases() {
float_test_edge!(f32 -> i128 u128);
float_test_edge!(f64 -> i128 u128);
}
macro_rules! int_test_edge {
($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({
fn test_edge() {
dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t));
match ($f::MIN as $BigS).cmp(&($t::MIN as $BigS)) {
Greater => {
assert_eq!(Some($f::MIN as $t), cast::<$f, $t>($f::MIN));
}
Equal => {
assert_eq!(Some($t::MIN), cast::<$f, $t>($f::MIN));
}
Less => {
let min = $t::MIN as $f;
assert_eq!(Some($t::MIN), cast::<$f, $t>(min));
assert_eq!(None, cast::<$f, $t>(min - 1));
}
}
match ($f::MAX as $BigU).cmp(&($t::MAX as $BigU)) {
Greater => {
let max = $t::MAX as $f;
assert_eq!(Some($t::MAX), cast::<$f, $t>(max));
assert_eq!(None, cast::<$f, $t>(max + 1));
}
Equal => {
assert_eq!(Some($t::MAX), cast::<$f, $t>($f::MAX));
}
Less => {
assert_eq!(Some($f::MAX as $t), cast::<$f, $t>($f::MAX));
}
}
}
test_edge();
})+}
}
#[test]
fn cast_int_to_int_edge_cases() {
use core::cmp::Ordering::*;
macro_rules! test_edge {
($( $from:ident )+) => { $({
int_test_edge!($from -> { isize i8 i16 i32 i64 } with i64 u64);
int_test_edge!($from -> { usize u8 u16 u32 u64 } with i64 u64);
})+}
}
test_edge!(isize i8 i16 i32 i64);
test_edge!(usize u8 u16 u32 u64);
}
#[test]
#[cfg(has_i128)]
fn cast_int_to_128_edge_cases() {
use core::cmp::Ordering::*;
macro_rules! test_edge {
($( $t:ident )+) => {
$(
int_test_edge!($t -> { i128 u128 } with i128 u128);
)+
int_test_edge!(i128 -> { $( $t )+ } with i128 u128);
int_test_edge!(u128 -> { $( $t )+ } with i128 u128);
}
}
test_edge!(isize i8 i16 i32 i64 i128);
test_edge!(usize u8 u16 u32 u64 u128);
}
#[test]
fn newtype_from_primitive() {
#[derive(PartialEq, Debug)]
struct New<T>(T);
// minimal impl
impl<T: FromPrimitive> FromPrimitive for New<T> {
fn from_i64(n: i64) -> Option<Self> {
T::from_i64(n).map(New)
}
fn from_u64(n: u64) -> Option<Self> {
T::from_u64(n).map(New)
}
}
macro_rules! assert_eq_from {
($( $from:ident )+) => {$(
assert_eq!(T::$from(Bounded::min_value()).map(New),
New::<T>::$from(Bounded::min_value()));
assert_eq!(T::$from(Bounded::max_value()).map(New),
New::<T>::$from(Bounded::max_value()));
)+}
}
fn check<T: PartialEq + Debug + FromPrimitive>() {
assert_eq_from!(from_i8 from_i16 from_i32 from_i64 from_isize);
assert_eq_from!(from_u8 from_u16 from_u32 from_u64 from_usize);
assert_eq_from!(from_f32 from_f64);
}
macro_rules! check {
($( $ty:ty )+) => {$( check::<$ty>(); )+}
}
check!(i8 i16 i32 i64 isize);
check!(u8 u16 u32 u64 usize);
}
#[test]
fn newtype_to_primitive() {
#[derive(PartialEq, Debug)]
struct New<T>(T);
// minimal impl
impl<T: ToPrimitive> ToPrimitive for New<T> {
fn to_i64(&self) -> Option<i64> {
self.0.to_i64()
}
fn to_u64(&self) -> Option<u64> {
self.0.to_u64()
}
}
macro_rules! assert_eq_to {
($( $to:ident )+) => {$(
assert_eq!(T::$to(&Bounded::min_value()),
New::<T>::$to(&New(Bounded::min_value())));
assert_eq!(T::$to(&Bounded::max_value()),
New::<T>::$to(&New(Bounded::max_value())));
)+}
}
fn check<T: PartialEq + Debug + Bounded + ToPrimitive>() {
assert_eq_to!(to_i8 to_i16 to_i32 to_i64 to_isize);
assert_eq_to!(to_u8 to_u16 to_u32 to_u64 to_usize);
assert_eq_to!(to_f32 to_f64);
}
macro_rules! check {
($( $ty:ty )+) => {$( check::<$ty>(); )+}
}
check!(i8 i16 i32 i64 isize);
check!(u8 u16 u32 u64 usize);
}