Compare commits

..

202 Commits

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

Greetings,

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

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

Thanks in advance!

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



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

Closes #124.

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

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

Closes #134.

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

`NAN` preserving lower- and upper-clamp.

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

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

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

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

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

Closes: #125 

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



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



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



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



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



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

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

Closes #11.

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

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

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

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

This allows for reuse of BigNums.


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



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



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

Fix #57 and more:

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

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

- CheckedShl was hinting that None was returned on overflow rather than
  on too large a rhs.
- Ditto for CheckedShr.
- CheckedShr documentation erroneously indicated that a left shift was
  going to be performed instead of a right shift.
2018-10-09 11:55:18 +02:00
bors[bot] 5c24fcc4a7 Merge #83
83: Release 0.2.6 r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-09-14 03:54:59 +00:00
Josh Stone b8ad107c1c Release 0.2.6 2018-09-13 15:45:58 -07:00
bors[bot] ac7e550b00 Merge #81
81: Add wrapping shifts r=cuviper a=edmccard

Add traits `WrappingShl` and `WrappingShr` corresponding to the
standard library `wrapping_shl` and `wrapping_shr` methods. Implement
the trait on all primitive integer types as well as on `Wrapping`.

Co-authored-by: Ed McCardell <edmccard@hotmail.com>
2018-09-13 22:29:56 +00:00
Ed McCardell abb51f9a09 Add wrapping shifts
Add traits `WrappingShl` and `WrappingShr` corresponding to the
standard library `wrapping_shl` and `wrapping_shr` methods. Implement
the trait on all primitive integer types as well as on `Wrapping`.
2018-09-02 00:51:04 -04:00
bors[bot] 5985a8b750 Merge #79
79: Updated documentation to note the pow(0, 0) case. r=cuviper a=meltinglava

Ref #78 

Co-authored-by: Roald <meltinglava>
2018-08-07 23:53:03 +00:00
Roald 2b975badfa typo 2018-08-07 12:56:16 +02:00
Roald 0f228be4d5 Updated documentation to note the pow(0, 0) case. 2018-07-21 22:23:13 +02:00
bors[bot] a415e2a751 Merge #74
74: Run cargo fmt r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-07-13 00:31:20 +00:00
Josh Stone d2bf4e04e4 Run cargo fmt 2018-07-12 17:09:22 -07:00
Josh Stone 83841d15f8 Add dates to RELEASES.md 2018-06-21 12:07:31 -07:00
bors[bot] e796afc83a Merge #73
73: Avoid `as` casts in default FromPrimitive methods r=cuviper a=cuviper

Particularly, the default `from_f64` used `n as i64`, which has
undefined behavior on overflow, kind of defeating the purpose here.
Now we use a checked `to_i64()` for this, and even try `to_u64()` as a
fallback for completeness.

Also make similar changes to default `ToPrimitive`, but at least it
didn't have the same casting problem.

Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-06-20 21:26:19 +00:00
Josh Stone 714057979e Release 0.2.5 2018-06-20 14:24:56 -07:00
Josh Stone 60924ecc70 add test newtype_to_primitive 2018-06-20 13:49:57 -07:00
Josh Stone 21e3620999 doc: fix a typo, s/the/then/ 2018-06-20 13:39:08 -07:00
Josh Stone dd7900d62f Avoid closures in default `ToPrimitive` methods
In `to_f64()`, we also try `to_u64()` if `to_i64()` failed.
2018-06-20 13:10:41 -07:00
Josh Stone d968efbc76 Avoid `as` casts in default FromPrimitive methods
Particularly, the default `from_f64` used `n as i64`, which has
undefined behavior on overflow, kind of defeating the purpose here.
Now we use a checked `to_i64()` for this, and even try `to_u64()` as a
fallback for completeness.

(All of the primitive implementations already do better, at least.)
2018-06-20 13:05:03 -07:00
bors[bot] 15dc0e7127 Merge #70
70: Clarify in the docs that `mul_add` is not always faster. r=cuviper a=frewsxcv

More info:

- https://github.com/rust-lang/rust/issues/49842
- https://github.com/rust-lang/rust/pull/50572

Co-authored-by: Corey Farwell <coreyf@rwell.org>
2018-05-21 17:07:28 +00:00
Corey Farwell 4775dee66b Clarify in the docs that `mul_add` is not always faster.
More info:

- https://github.com/rust-lang/rust/issues/49842
- https://github.com/rust-lang/rust/pull/50572
2018-05-20 11:58:10 -04:00
bors[bot] f4125621ac Merge #69
69: Automatically detect support for i128/u128 r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-05-11 23:02:02 +00:00
Josh Stone c00ae2046e Release 0.2.4 2018-05-11 16:01:25 -07:00
Josh Stone 51f6c57c4b Automatically detect support for i128/u128 2018-05-11 15:50:48 -07:00
bors[bot] 4e136ddc85 Merge #68
68: Release 0.2.3 r=cuviper a=cuviper

Closes #66.

Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-05-10 19:22:07 +00:00
Josh Stone 4a03db4e1c Release 0.2.3 2018-05-10 12:15:53 -07:00
bors[bot] c3feb40897 Merge #67
67: Miscellaneous tweaks regarding no_std r=cuviper a=cuviper



Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-05-09 00:40:06 +00:00
Josh Stone 7e055b131f Document more impls that require std 2018-05-08 17:35:59 -07:00
Josh Stone 5add4c580e Enable all features for docs.rs 2018-05-08 17:27:44 -07:00
Josh Stone 817ef94784 Add the no-std crate category 2018-05-08 17:27:33 -07:00
Josh Stone f35cce229e Always use #![no_std], and declare std when enabled 2018-05-08 17:26:38 -07:00
bors[bot] 6edb91f5e8 Merge #60
60: i128 r=cuviper a=regexident



Co-authored-by: Vincent Esche <regexident@gmail.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-05-08 21:43:10 +00:00
Josh Stone 1af2319201 add a couple more Rust versions to CI 2018-05-07 12:38:56 -07:00
Josh Stone bbbc2bd1d7 impl 128-bit numeric casts
This includes new conditional methods `ToPrimitive::{to_i128,to_u128}`
and `FromPrimitive::{from_i128,from_u128}`.  Since features can only be
additive, these methods must not cause a breaking change to anyone when
enabled -- thus they have a default implementation that converts through
64-bit values.  Types that can do better with a full 128-bit integer,
like bigint or floating-point, will probably want to override these.
2018-05-07 12:28:53 -07:00
Josh Stone 6161f1ade1 impl 128-bit MulAdd and MulAddAssign 2018-05-07 12:28:35 -07:00
Josh Stone fe53805550 impl 128-bit CheckedRem and CheckedNeg 2018-05-07 12:28:15 -07:00
Josh Stone 428e0107d2 Add imports for 128-bit Bounded 2018-05-07 12:27:42 -07:00
Josh Stone d2107ae005 There's no u64 exponent impl for i128/u128 Pow 2018-05-07 12:26:44 -07:00
Josh Stone 08ad9b1642 i128 is not Unsigned 2018-05-07 12:26:00 -07:00
Josh Stone 261efafe0b Merge branch 'master' into regexident-i128 2018-05-04 12:28:48 -07:00
bors[bot] dd67e9d2e1 Merge #61
61: Use constant for 180/π in f32::to_degrees r=cuviper a=vks

The current `f32::to_degrees` implementation uses a division to
calculate 180/π, which causes a loss of precision. Using a constant is
still not perfect (implementing a maximally-precise algorithm would come
with a high performance cost), but improves precision with a minimal
change.

This is a backport from [`std`].

[`std`]: e34c31bf02

Co-authored-by: Vinzent Steinberg <vinzent.steinberg@gmail.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-05-04 19:26:46 +00:00
Josh Stone 6aaff332d3 Explicitly test FloatCore in to_degrees_rounding 2018-05-04 12:19:23 -07:00
bors[bot] a49013e338 Merge #59
59: Added `MulAdd` and `MulAddAssign` traits r=cuviper a=regexident

Both `f32` and `f64` implement fused multiply-add, which computes `(self * a) + b` with only one rounding error. This produces a more accurate result with better performance than a separate multiplication operation followed by an add:

```rust
fn mul_add(self, a: f32, b: f32) -> f32[src]
```

It is however not possible to make use of this in a generic context by abstracting over a trait.

My concrete use-case is machine learning, [gradient descent](https://en.wikipedia.org/wiki/Gradient_descent) to be specific,  
where the core operation of updating the gradient could make use of `mul_add` for both its `weights: Vector` as well as its `bias: f32`:

```rust
struct Perceptron {
  weights: Vector,
  bias: f32,
}

impl MulAdd<f32, Self> for Vector {
  // ...
}

impl Perceptron {
  fn learn(&mut self, example: Vector, expected: f32, learning_rate: f32) {
    let alpha = self.error(example, expected, learning_rate);
    self.weights = example.mul_add(alpha, self.weights);
    self.bias = self.bias.mul_add(alpha, self.bias)
  }
}
```

(The actual impl of `Vector` would be generic over its value type: `Vector<T>`, thus requiring the trait.)

Co-authored-by: Vincent Esche <regexident@gmail.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-05-04 19:12:41 +00:00
Josh Stone 0d358034d9 Test MulAdd explicitly, guarded by std for floats 2018-05-04 12:09:02 -07:00
Vincent Esche 157efc5a26 Adjusted CI testing scripts 2018-04-19 09:26:02 +02:00
Vincent Esche 28be885481 Moved impl of `MulAdd`/`MulAddAssign` for `f32`/`f64` behind feature guard 2018-04-18 10:31:37 +02:00
Vincent Esche 257917f3f2 Removed inferrable value suffixes 2018-04-18 10:19:30 +02:00
Josh Stone 4fb749a401 typo: taht -> that 2018-04-13 14:29:00 -07:00
bors[bot] 4195043240 Merge #63
63: Add CheckedRem and CheckedNeg r=cuviper a=LEXUGE

Continue from #58 
I've alreadyremoved all the formats.


Co-authored-by: LEXUGE <lexugeyky@outlook.com>
Co-authored-by: Josh Stone <cuviper@gmail.com>
2018-04-13 21:25:30 +00:00
Josh Stone aa21fba9fc re-export CheckedRem and CheckedNeg at the root 2018-04-13 14:14:49 -07:00
Josh Stone b1c4074cc4 Document CheckedRem and CheckedNeg 2018-04-13 14:14:22 -07:00
Josh Stone 5fb3724b69 rename checked_impl_one_param to checked_impl_unary 2018-04-13 14:13:42 -07:00
LEXUGE f74de249c8
remove formats 2018-04-13 16:04:56 +08:00
Vinzent Steinberg 9ca219c677 Avoid test failure with Rust 1.8 by limiting to no-std builds 2018-04-10 19:56:39 +02:00
bors[bot] 97f3892bd1 Merge #62
62: Update outdated FIXME r=cuviper a=vks



Co-authored-by: Vinzent Steinberg <vinzent.steinberg@gmail.com>
2018-04-10 17:54:20 +00:00
Vinzent Steinberg 2836cfc9ab Update outdated FIXME 2018-04-10 19:51:03 +02:00
Vinzent Steinberg 6430351e74 Use constant for 180/π in f32::to_degrees
The current `f32::to_degrees` implementation uses a division to
calculate 180/π, which causes a loss of precision. Using a constant is
still not perfect (implementing a maximally-precise algorithm would come
with a high performance cost), but improves precision with a minimal
change.

This is a backport from [`std`].

[`std`]: e34c31bf02
2018-04-10 15:26:14 +02:00
Vincent Esche dd5b107c56 Added mention of `i128` feature to ‘README.md’ 2018-04-10 10:42:35 +02:00
Vincent Esche 746db74dac Added impls of `Unsigned` for `i128` and `u128` 2018-04-10 10:39:57 +02:00
Vincent Esche 152b38e03f Added impls of `Num` for `i128` and `u128` 2018-04-10 10:39:54 +02:00
Vincent Esche 6d3b55030f Added ‘i128’ feature and unit test invocation 2018-04-10 10:35:55 +02:00
Vincent Esche 830363024b Added `MulAdd` and `MulAddAssign` traits 2018-04-10 10:08:55 +02:00
Vincent Esche d1334bf903 Added impls of `Signed` for `i128` and `u128` 2018-04-09 12:58:17 +02:00
Vincent Esche f69af180cc Added impls of `Pow` for `i128` and `u128` 2018-04-09 11:11:15 +02:00
Vincent Esche 5ee2570618 Added impls of `Wrapping…` for `i128` and `u128` 2018-04-09 11:11:05 +02:00
Vincent Esche 234706fb97 Added impls of `Saturating…` for `i128` and `u128` 2018-04-09 11:10:57 +02:00
Vincent Esche b44666183d Added impls of `Checked…` for `i128` and `u128` 2018-04-09 11:10:51 +02:00
Vincent Esche bc19c34934 Added impls of `PrimInt` for `i128` and `u128` 2018-04-09 11:10:45 +02:00
Vincent Esche 62723f6f3a Added impls of `Zero` and `One` for `i128` and `u128` 2018-04-09 11:10:36 +02:00
Vincent Esche f8d1896c6c Added impls of `Bounded` for `i128` and `u128` 2018-04-09 11:10:23 +02:00
bors[bot] bb67a3d03a Merge #53
53: Release 0.2.2 r=cuviper a=cuviper
2018-03-18 23:32:18 +00:00
Josh Stone 058a6004f0 Release 0.2.2 2018-03-18 16:27:31 -07:00
bors[bot] fcc33a3577 Merge #52
52: Refactor ToPrimitive range checks r=cuviper a=cuviper

This is a rebase and continuation of PR #28.  The primary benefit is that
floats finally check for overflow before casting to integers, avoiding
undefined behavior.  Fixes #12.

The inter-integer conversions and all of the macros for these have also been
tweaked, hopefully improving readability.  Exhaustive tests have been added for
good and bad conversions around the target MIN and MAX values.
2018-03-13 21:10:04 +00:00
Josh Stone a4d234c253 Further simplify float-to-int range checks
We don't actually need to compute the `trunc()` value, as long as we can
figure out the right values for the exclusive range `(MIN-1, MAX+1)` to
measure the same truncation effect.
2018-03-13 13:38:17 -07:00
Josh Stone f0ed42b3bc Test edge cases of ToPrimitive with ints 2018-03-11 01:37:27 -08:00
Josh Stone 50868c60d2 Refactor to_primitive_int/uint macros 2018-03-11 01:37:00 -08:00
Josh Stone 6d7bbb1b53 Mask debug prints no-std mode 2018-03-11 01:36:17 -08:00
Josh Stone d195eafbe2 Simplify the to_primitive_float macros 2018-03-10 23:33:47 -08:00
Josh Stone f6dc4d29a4 Add thorough tests of float to int edge cases 2018-03-10 23:05:02 -08:00
Josh Stone b025c273c7 Rewrite range checks in float ToPrimitive macros 2018-03-10 23:01:30 -08:00
Dan Barella 8e27c7327d Rename some tests. 2018-03-10 15:14:23 -08:00
Dan Barella aab7098acd Reformat macros. 2018-03-10 15:14:23 -08:00
Alexander Popiak c32cb5c65b Patch in apopiak@'s changes from github.com/rust-num/num/pull/135/. 2018-03-10 15:14:23 -08:00
Dan Barella ab8fda7654 Change assert form. 2018-03-10 15:14:23 -08:00
Dan Barella ecb0816c83 Remove an unneeded assert. 2018-03-10 15:14:23 -08:00
Dan Barella 3534a89858 Don't use assert_ne!
`num` is tested against `rust 1.8.0`, which doesn't include
`assert_ne!` -- so we use a plain ol' `assert` instead.
2018-03-10 15:14:23 -08:00
Dan Barella f99aa0e181 Check overflow when casting floats to integers.
This change adds some new macro rules used when converting from floats
to integers. There are two macro rule variants, one for signed ints, one
for unsigned ints.

Among other things, this change specifically addresses the overflow case
documented in https://github.com/rust-num/num-traits/issues/12
2018-03-10 15:14:23 -08:00
bors[bot] aa36cdb206 Merge #42
42: Release 0.2.1 r=cuviper a=cuviper
2018-03-01 23:29:38 +00:00
Josh Stone ab0de9c329 Release 0.2.1 2018-03-01 14:20:57 -08:00
bors[bot] 5f906234bc Merge #41
41: Various improvements to FloatCore r=vks a=cuviper

- New macros simplify forwarding method implementations.
  - `Float` and `Real` use this to compact their implementations.
  - `FloatCore` now forwards `std` implementations when possible.
- `FloatCore` now requires `NumCast`, like `Float does.
- New additions to `FloatCore`:
  - Constants like `min_value()` -> `f64::MIN`
  - Rounding methods `floor`, `ceil`, `round`, `trunc`, `fract`
  - `integer_decode` matching `Float`'s
- Fix NAN sign handling in `FloatCore` (rust-num/num#312, rust-lang/rust#42425)
- Fix overflow in `FloatCore::powi` exponent negation.
- Add doctests to all `FloatCore` methods.
2018-03-01 20:57:29 +00:00
Josh Stone 04a3f2a591 Comment the Rust version for NAN.is_sign_* behavior 2018-02-28 11:43:55 -08:00
Josh Stone 080f6f259e Comment the i32::MIN case for FloatCore::powi 2018-02-28 11:33:34 -08:00
Josh Stone aa9ceba628 Add doctests to FloatCore 2018-02-27 22:12:37 -08:00
Josh Stone ec3cd50f3d Weaken the std f32::to_degrees/to_radians tests 2018-02-27 22:10:46 -08:00
Josh Stone ac6eca4b66 Use more FloatCore in src/sign.rs 2018-02-27 21:50:44 -08:00
Josh Stone 36c7e324db Fix FloatCore::powi with i32::MIN exponent 2018-02-27 21:34:01 -08:00
Josh Stone 964a7e52a8 Reinstate NAN-sign fixes in FloatCore
Formerly changed on the next branch, part of rust-num/num#319.
2018-02-27 21:03:30 -08:00
Josh Stone 8d16921579 allow unused macros 2018-02-27 17:09:43 -08:00
Josh Stone 6fa29be7c0 Use macros for more float constants 2018-02-27 17:09:43 -08:00
Josh Stone 83d498d0be Add integer_decode to FloatCore 2018-02-27 16:33:04 -08:00
Josh Stone f365a4205f Add rounding methods to FloatCore 2018-02-27 16:33:04 -08:00
Josh Stone 99c6cc11ba Add more constants to FloatCore 2018-02-27 16:33:04 -08:00
Josh Stone 7d6575da0f Add NumCast to FloatCore, matching Float 2018-02-27 16:33:04 -08:00
Josh Stone ac503261ca Forward FloatCore to inherent methods when possible 2018-02-27 16:33:04 -08:00
Josh Stone c848562fcf Use forwarding macros to implement Float and Real 2018-02-27 16:33:04 -08:00
bors[bot] dc6a125a9c Merge #37
37: Add Inv and Pow traits. r=cuviper a=clarcharr

This is not a breaking change, and closes #34 and #38.

This doesn't add any impls for the other `num` crates, just floats with `std` enabled. The trait has to be added before those other crates can be updated.
2018-02-27 19:56:30 +00:00
Clar Charr 79b557f040 Ensure infalliability of conversions, avoid closures. 2018-02-27 14:06:46 -05:00
Clar Charr aca8dc8149 Remove Pow<u64> (accidentally added). 2018-02-27 13:25:53 -05:00
Clar Charr 61a6acc9c2 Add more Pow implementations. 2018-02-27 13:25:53 -05:00
Clar Charr 5d6933f34a Fix doc tests. 2018-02-27 13:25:53 -05:00
Clar Charr ce3badca57 Move Pow to pow module. 2018-02-27 13:25:53 -05:00
Clar Charr c1f4118b4e Fix Inv trait, add Pow trait. 2018-02-27 13:25:53 -05:00
Clar Charr 5bdff3f0ff Add Inv trait. 2018-02-27 13:25:53 -05:00
bors[bot] 3431da80a2 Merge #39
39: Add is_one. r=cuviper a=clarcharr

Implements the version recommended in #5. That issue should remain open to track the breaking-change version.
2018-02-23 22:58:39 +00:00
Clar Charr 51dad501aa Add #[inline] to is_one. 2018-02-23 17:44:07 -05:00
Clar Charr 45856ee846 Make doc comment less scary. 2018-02-23 17:21:47 -05:00
Clar Charr 9461cd84f2 Add is_one. 2018-02-19 15:05:11 -05:00
bors[bot] bfd62d4638 Merge #32
32: Implement CoreFloat trait r=cuviper a=vks

This is a subset of the `Float` trait, but works with `no_std`.
Some code was simplified by using `CoreFloat`.
2018-02-07 22:26:47 +00:00
Vinzent Steinberg 52bc8eb22b Mention FloatCore in README 2018-02-07 12:47:12 +01:00
Vinzent Steinberg d115dadeb1 Don't re-export FloatCore
This avoids breaking `use num_traits::*`.
2018-02-07 12:42:30 +01:00
Vinzent Steinberg 1db660ed56 Inline only actual trait implementations 2018-02-07 12:38:01 +01:00
Vinzent Steinberg efad5329b4 Rename CoreFloat to FloatCore 2018-02-07 12:34:14 +01:00
Josh Stone a062bed8b2 link more release notes 2018-02-06 20:49:17 -08:00
bors[bot] 17cc9c1e75 Merge #33
33: Release 0.2.0 r=cuviper a=cuviper
2018-02-07 01:12:45 +00:00
Josh Stone 2566d53ad2 Bump to 0.2.0 final 2018-02-06 17:01:43 -08:00
Josh Stone aa9ea42f9e Add release notes for 0.2.0 2018-02-06 17:01:31 -08:00
Vinzent Steinberg 8a7f383eb1 Implement CoreFloat trait
This is a subset of the `Float` trait, but works with `no_std`.
Some code was simplified by using `CoreFloat`.
2018-02-02 19:48:25 +01:00
Josh Stone 47515a10e1 Add a min-rustc badge and document compatibility 2018-02-02 10:24:14 -08:00
bors[bot] afa81f80e4 Merge #30
30: Re-introduce the std feature r=vks a=cuviper

This is a port of @vks's rust-num/num#296, but without the feature-toggled changes to `Float`.  Now `Float` and the newer `Real` are completely dependent on having `std` enabled.  In the future we can consider adding separate more-limited float/real traits that can work without `std`, like the `BaseFloat` that was originally proposed in the former PR.

This is a breaking change with a bump to 0.2, since anyone currently using `default-features = false` will lose functionality.  The actual API is otherwise unchanged, so my plan is to employ the "semver trick" -- publishing a new num-traits-0.1 that re-exports everything from 0.2 (with `std`).  Thus all `num-traits` users should remain compatible even if they mix 0.1 and 0.2.

Closes #16.
2018-02-02 17:53:01 +00:00
Toshiki Teramura ffa67c8527 CI typo fix 2018-02-01 11:56:13 -08:00
Josh Stone 67f03391a1 Bump to 0.2 for the breaking feature change 2018-01-31 16:19:00 -08:00
Josh Stone 36b2514f4b Note the std feature in README.md 2018-01-31 16:16:41 -08:00
Josh Stone 4fbc583eb9 Don't use wildcards for pub use 2018-01-31 16:05:43 -08:00
Josh Stone 79786ac518 test no_std in CI 2018-01-31 15:56:25 -08:00
Josh Stone e6bb97b3ac Make `Float` and `Real` depend on the `std` feature
We don't have implementations for many of the methods in `no_std`.  It's
hostile to external implementors if some trait methods are conditional
on a feature, as that feature could be added by anyone in a dependency
tree.  Instead, let's just live without these traits for now.
2018-01-31 15:56:06 -08:00
Vinzent Steinberg a843027b56 Re-introduce the std feature
This is a port of @vks's rust-num/num#296, but without the feature-
toggled changes to `Float`.
2018-01-31 15:42:55 -08:00
24 changed files with 6918 additions and 69 deletions

View File

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

View File

@ -4,15 +4,25 @@ 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" ]
categories = ["algorithms", "science", "no-std"]
license = "MIT/Apache-2.0"
repository = "https://github.com/rust-num/num-traits"
name = "num-traits"
version = "0.1.43"
version = "0.2.8"
readme = "README.md"
build = "build.rs"
exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
[lib]
doctest = false # multiple rlib candidates for `num_traits` found
[package.metadata.docs.rs]
features = ["std"]
[dependencies.num-traits]
version = "0.2.0"
[dependencies]
libm = { version = "0.1.4", optional = true }
[features]
default = ["std"]
std = []
i128 = []
[build-dependencies]
autocfg = "0.1.3"

View File

@ -2,20 +2,18 @@
[![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)
Numeric traits for generic mathematics in Rust.
This version of the crate only exists to re-export compatible
items from `num-traits` 0.2. Please consider updating!
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
num-traits = "0.1"
num-traits = "0.2"
```
and this to your crate root:
@ -24,6 +22,29 @@ and this to your crate root:
extern crate num_traits;
```
## 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).

View File

@ -1,8 +1,116 @@
# Release 0.2.0
# Release 0.2.8 (2019-05-21)
- **breaking change**: There is now a `std` feature, enabled by default, along
- [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.
`#![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]).
@ -10,12 +118,17 @@
**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
- All items are now re-exported from num-traits 0.2 for compatibility.
# Release 0.1.43 (2018-02-06)
# Release 0.1.42
- 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].

14
build.rs Normal file
View File

@ -0,0 +1,14 @@
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

@ -5,8 +5,7 @@
set -ex
export TRAVIS_RUST_VERSION
for TRAVIS_RUST_VERSION in 1.8.0 stable beta nightly; do
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 cargo build --verbose
$run $PWD/ci/test_full.sh
done

View File

@ -4,8 +4,24 @@ set -ex
echo Testing num-traits on rustc ${TRAVIS_RUST_VERSION}
# num-integer should build and test everywhere.
# num-traits should build and test everywhere.
cargo build --verbose
cargo test --verbose
# We have no features to test...
# 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

127
src/bounds.rs Normal file
View File

@ -0,0 +1,127 @@
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));
}

762
src/cast.rs Normal file
View File

@ -0,0 +1,762 @@
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 => {});

2119
src/float.rs Normal file

File diff suppressed because it is too large Load Diff

207
src/identities.rs Normal file
View File

@ -0,0 +1,207 @@
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));
}

409
src/int.rs Normal file
View File

@ -0,0 +1,409 @@
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);

View File

@ -10,79 +10,563 @@
//! Numeric traits for generic mathematics
//!
//! This version of the crate only exists to re-export compatible
//! items from num-traits 0.2. Please consider updating!
//! ## Compatibility
//!
//! The `num-traits` crate is tested for rustc 1.8 and greater.
#![doc(html_root_url = "https://docs.rs/num-traits/0.1")]
#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
#![deny(unconditional_recursion)]
#![no_std]
#[cfg(feature = "std")]
extern crate std;
extern crate num_traits;
// Only `no_std` builds actually use `libm`.
#[cfg(all(not(feature = "std"), feature = "libm"))]
extern crate libm;
use core::fmt;
use core::num::Wrapping;
use core::ops::{Add, Div, Mul, Rem, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
pub use bounds::Bounded;
pub use float::{Float, FloatConst};
// pub use real::Real; // NOTE: Don't do this, it breaks `use num_traits::*;`.
pub use identities::{Zero, One, zero, one};
pub use ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedShl, CheckedShr};
pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub};
pub use ops::saturating::Saturating;
pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
pub use cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast};
#[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 pow::{pow, checked_pow};
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};
#[macro_use]
mod macros;
// Re-exports from num-traits 0.2!
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;
pub use num_traits::{Num, NumOps, NumRef, RefNum};
pub use num_traits::{NumAssignOps, NumAssign, NumAssignRef};
pub use num_traits::{FloatErrorKind, ParseFloatError};
pub use num_traits::clamp;
/// 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;
// Note: the module structure is explicitly re-created, rather than re-exporting en masse,
// so we won't expose any items that may be added later in the new version.
pub mod identities {
pub use num_traits::identities::{Zero, One, zero, one};
/// 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>;
}
pub mod sign {
pub use num_traits::sign::{Signed, Unsigned, abs, abs_sub, signum};
/// The trait for types implementing basic numeric operations
///
/// 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>
{
}
pub mod ops {
pub mod saturating {
pub use num_traits::ops::saturating::Saturating;
}
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>
{
}
pub mod checked {
pub use num_traits::ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
CheckedShl, CheckedShr};
}
/// The trait for `Num` types which also implement numeric operations taking
/// the second operand by reference.
///
/// 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> {}
pub mod wrapping {
pub use num_traits::ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub};
/// The trait for references which implement numeric operations, taking the
/// second operand either by value or by reference.
///
/// This is automatically implemented for types which implement the operators.
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
/// The trait for types implementing numeric assignment operators (like `+=`).
///
/// 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.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssign: Num + NumAssignOps {}
impl<T> NumAssign for T where T: Num + NumAssignOps {}
/// The trait for `NumAssign` types which also implement assignment operations
/// taking the second operand by reference.
///
/// This is automatically implemented for types which implement the operators.
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
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)
}
}
)*)
}
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)
}
}
pub mod bounds {
pub use num_traits::bounds::Bounded;
#[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,
}
pub mod float {
pub use num_traits::float::{Float, FloatConst};
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)
}
}
pub mod real {
pub use num_traits::real::Real;
// 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)
}
}
)*)
}
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
}
}
pub mod cast {
pub use num_traits::cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast};
/// 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
}
}
pub mod int {
pub use num_traits::int::PrimInt;
/// 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
}
}
pub mod pow {
pub use num_traits::pow::{pow, checked_pow};
#[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
}
assert_eq!(compute(1, 2), 1)
}
#[test]
fn check_numref_ops() {
fn compute<T: NumRef>(x: T, y: &T) -> T {
x * y / y % y + y - y
}
assert_eq!(compute(1, &2), 1)
}
#[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)
}
#[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)

37
src/macros.rs Normal file
View File

@ -0,0 +1,37 @@
// 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
}
)*};
}

277
src/ops/checked.rs Normal file
View File

@ -0,0 +1,277 @@
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);

47
src/ops/inv.rs Normal file
View File

@ -0,0 +1,47 @@
/// 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
}
}

5
src/ops/mod.rs Normal file
View File

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

151
src/ops/mul_add.rs Normal file
View File

@ -0,0 +1,151 @@
/// 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);
}
}

30
src/ops/saturating.rs Normal file
View File

@ -0,0 +1,30 @@
/// 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);

272
src/ops/wrapping.rs Normal file
View File

@ -0,0 +1,272 @@
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));
}

262
src/pow.rs Normal file
View File

@ -0,0 +1,262 @@
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)
}

834
src/real.rs Normal file
View File

@ -0,0 +1,834 @@
#![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;
}
}

225
src/sign.rs Normal file
View File

@ -0,0 +1,225 @@
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));
}
*/

396
tests/cast.rs Normal file
View File

@ -0,0 +1,396 @@
//! 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);
}