Skip to content

Commit

Permalink
Auto merge of #61635 - ecstatic-morse:const-signum, r=oli-obk
Browse files Browse the repository at this point in the history
Make `i*::signum` a `const fn`.

Ticks a box in #53718.

This uses a well-known branchless implementation of `signum`: `(n > 0) as i32 - (n < 0) as i32`.

Here's a [playground](https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=747cf191c4974bf66c9d75e509ae6e6e) comparing the two techniques. On x86 in release mode, the branchless implementation is able to replace a `mov` and `cmov` with a `sar` and `add`, so this should be a bit faster as well.

~~This is marked as a draft since I think I'll need to add `#[rustc_const_unstable]` somewhere. Perhaps the reviewer can point me in the right direction.~~
  • Loading branch information
bors committed Jun 8, 2019
2 parents 6312b89 + f6611db commit 7f90abe
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 8 deletions.
9 changes: 3 additions & 6 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1993,13 +1993,10 @@ assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_int_sign")]
#[inline]
pub fn signum(self) -> Self {
match self {
n if n > 0 => 1,
0 => 0,
_ => -1,
}
pub const fn signum(self) -> Self {
(self > 0) as Self - (self < 0) as Self
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/test/run-pass/const-int-sign.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
#![feature(const_int_sign)]

const NEGATIVE_A: bool = (-10i32).is_negative();
const NEGATIVE_B: bool = 10i32.is_negative();
const POSITIVE_A: bool= (-10i32).is_positive();
const POSITIVE_B: bool= 10i32.is_positive();
const POSITIVE_A: bool = (-10i32).is_positive();
const POSITIVE_B: bool = 10i32.is_positive();

const SIGNUM_POS: i32 = 10i32.signum();
const SIGNUM_NIL: i32 = 0i32.signum();
const SIGNUM_NEG: i32 = (-42i32).signum();

fn main() {
assert!(NEGATIVE_A);
assert!(!NEGATIVE_B);
assert!(!POSITIVE_A);
assert!(POSITIVE_B);

assert_eq!(SIGNUM_POS, 1);
assert_eq!(SIGNUM_NIL, 0);
assert_eq!(SIGNUM_NEG, -1);
}

0 comments on commit 7f90abe

Please sign in to comment.