Skip to content

Commit

Permalink
Add basic conversions for i128 and u128
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed May 16, 2018
1 parent 275ba23 commit 04252b7
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 28 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/rust-num/num-bigint"
version = "0.2.0-git"
publish = false
readme = "README.md"
build = "build.rs"

[[bench]]
name = "bigint"
Expand All @@ -28,11 +29,11 @@ name = "shootout-pidigits"
[dependencies]

[dependencies.num-integer]
version = "0.1.36"
version = "0.1.38"
default-features = false

[dependencies.num-traits]
version = "0.2.1"
version = "0.2.4"
default-features = false
features = ["std"]

Expand All @@ -52,3 +53,4 @@ version = "0.4"

[features]
default = []
i128 = ["num-integer/i128", "num-traits/i128"]
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -22,6 +22,12 @@ and this to your crate root:
extern crate num_bigint;
```

## Features

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).
Expand Down
35 changes: 35 additions & 0 deletions build.rs
@@ -0,0 +1,35 @@
use std::env;
use std::io::Write;
use std::process::{Command, Stdio};

fn main() {
if probe("fn main() { 0i128; }") {
println!("cargo:rustc-cfg=has_i128");
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
panic!("i128 support was not detected!");
}
}

/// Test if a code snippet can be compiled
fn probe(code: &str) -> bool {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");

let mut child = Command::new(rustc)
.arg("--out-dir")
.arg(out_dir)
.arg("--emit=obj")
.arg("-")
.stdin(Stdio::piped())
.spawn()
.expect("rustc probe");

child
.stdin
.as_mut()
.expect("rustc stdin")
.write_all(code.as_bytes())
.expect("write rustc stdin");

child.wait().expect("rustc probe").success()
}
84 changes: 83 additions & 1 deletion src/bigint.rs
Expand Up @@ -7,7 +7,9 @@ use std::fmt;
use std::mem;
use std::cmp::Ordering::{self, Less, Greater, Equal};
use std::{i64, u64};
#[allow(unused_imports)]
#[cfg(has_i128)]
use std::{i128, u128};
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::iter::{Product, Sum};

Expand Down Expand Up @@ -1811,6 +1813,27 @@ impl ToPrimitive for BigInt {
}
}

#[inline]
#[cfg(has_i128)]
fn to_i128(&self) -> Option<i128> {
match self.sign {
Plus => self.data.to_i128(),
NoSign => Some(0),
Minus => {
self.data.to_u128().and_then(|n| {
let m: u128 = 1 << 127;
if n < m {
Some(-(n as i128))
} else if n == m {
Some(i128::MIN)
} else {
None
}
})
}
}
}

#[inline]
fn to_u64(&self) -> Option<u64> {
match self.sign {
Expand All @@ -1820,6 +1843,16 @@ impl ToPrimitive for BigInt {
}
}

#[inline]
#[cfg(has_i128)]
fn to_u128(&self) -> Option<u128> {
match self.sign {
Plus => self.data.to_u128(),
NoSign => Some(0),
Minus => None,
}
}

#[inline]
fn to_f32(&self) -> Option<f32> {
self.data.to_f32().map(|n| {
Expand Down Expand Up @@ -1849,11 +1882,23 @@ impl FromPrimitive for BigInt {
Some(BigInt::from(n))
}

#[inline]
#[cfg(has_i128)]
fn from_i128(n: i128) -> Option<BigInt> {
Some(BigInt::from(n))
}

#[inline]
fn from_u64(n: u64) -> Option<BigInt> {
Some(BigInt::from(n))
}

#[inline]
#[cfg(has_i128)]
fn from_u128(n: u128) -> Option<BigInt> {
Some(BigInt::from(n))
}

#[inline]
fn from_f64(n: f64) -> Option<BigInt> {
if n >= 0.0 {
Expand All @@ -1879,6 +1924,22 @@ impl From<i64> for BigInt {
}
}

#[cfg(has_i128)]
impl From<i128> for BigInt {
#[inline]
fn from(n: i128) -> Self {
if n >= 0 {
BigInt::from(n as u128)
} else {
let u = u128::MAX - (n as u128) + 1;
BigInt {
sign: Minus,
data: BigUint::from(u),
}
}
}
}

macro_rules! impl_bigint_from_int {
($T:ty) => {
impl From<$T> for BigInt {
Expand Down Expand Up @@ -1909,6 +1970,21 @@ impl From<u64> for BigInt {
}
}

#[cfg(has_i128)]
impl From<u128> for BigInt {
#[inline]
fn from(n: u128) -> Self {
if n > 0 {
BigInt {
sign: Plus,
data: BigUint::from(n),
}
} else {
BigInt::zero()
}
}
}

macro_rules! impl_bigint_from_uint {
($T:ty) => {
impl From<$T> for BigInt {
Expand Down Expand Up @@ -2040,11 +2116,17 @@ impl_to_bigint!(i8, FromPrimitive::from_i8);
impl_to_bigint!(i16, FromPrimitive::from_i16);
impl_to_bigint!(i32, FromPrimitive::from_i32);
impl_to_bigint!(i64, FromPrimitive::from_i64);
#[cfg(has_i128)]
impl_to_bigint!(i128, FromPrimitive::from_i128);

impl_to_bigint!(usize, FromPrimitive::from_usize);
impl_to_bigint!(u8, FromPrimitive::from_u8);
impl_to_bigint!(u16, FromPrimitive::from_u16);
impl_to_bigint!(u32, FromPrimitive::from_u32);
impl_to_bigint!(u64, FromPrimitive::from_u64);
#[cfg(has_i128)]
impl_to_bigint!(u128, FromPrimitive::from_u128);

impl_to_bigint!(f32, FromPrimitive::from_f32);
impl_to_bigint!(f64, FromPrimitive::from_f64);

Expand Down
72 changes: 63 additions & 9 deletions src/biguint.rs
Expand Up @@ -11,7 +11,7 @@ use std::mem;
use std::cmp::Ordering::{self, Less, Greater, Equal};
use std::{f32, f64};
use std::{u8, u64};
#[allow(unused_imports)]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;

#[cfg(feature = "serde")]
Expand Down Expand Up @@ -1059,14 +1059,13 @@ fn high_bits_to_u64(v: &BigUint) -> u64 {
impl ToPrimitive for BigUint {
#[inline]
fn to_i64(&self) -> Option<i64> {
self.to_u64().and_then(|n| {
// If top bit of u64 is set, it's too large to convert to i64.
if n >> 63 == 0 {
Some(n as i64)
} else {
None
}
})
self.to_u64().as_ref().and_then(u64::to_i64)
}

#[inline]
#[cfg(has_i128)]
fn to_i128(&self) -> Option<i128> {
self.to_u128().as_ref().and_then(u128::to_i128)
}

#[inline]
Expand All @@ -1086,6 +1085,24 @@ impl ToPrimitive for BigUint {
Some(ret)
}

#[inline]
#[cfg(has_i128)]
fn to_u128(&self) -> Option<u128> {
let mut ret: u128 = 0;
let mut bits = 0;

for i in self.data.iter() {
if bits >= 128 {
return None;
}

ret += (*i as u128) << bits;
bits += big_digit::BITS;
}

Some(ret)
}

#[inline]
fn to_f32(&self) -> Option<f32> {
let mantissa = high_bits_to_u64(self);
Expand Down Expand Up @@ -1131,11 +1148,27 @@ impl FromPrimitive for BigUint {
}
}

#[inline]
#[cfg(has_i128)]
fn from_i128(n: i128) -> Option<BigUint> {
if n >= 0 {
Some(BigUint::from(n as u128))
} else {
None
}
}

#[inline]
fn from_u64(n: u64) -> Option<BigUint> {
Some(BigUint::from(n))
}

#[inline]
#[cfg(has_i128)]
fn from_u128(n: u128) -> Option<BigUint> {
Some(BigUint::from(n))
}

#[inline]
fn from_f64(mut n: f64) -> Option<BigUint> {
// handle NAN, INFINITY, NEG_INFINITY
Expand Down Expand Up @@ -1182,6 +1215,21 @@ impl From<u64> for BigUint {
}
}

#[cfg(has_i128)]
impl From<u128> for BigUint {
#[inline]
fn from(mut n: u128) -> Self {
let mut ret: BigUint = Zero::zero();

while n != 0 {
ret.data.push(n as BigDigit);
n >>= big_digit::BITS;
}

ret
}
}

macro_rules! impl_biguint_from_uint {
($T:ty) => {
impl From<$T> for BigUint {
Expand Down Expand Up @@ -1227,11 +1275,17 @@ impl_to_biguint!(i8, FromPrimitive::from_i8);
impl_to_biguint!(i16, FromPrimitive::from_i16);
impl_to_biguint!(i32, FromPrimitive::from_i32);
impl_to_biguint!(i64, FromPrimitive::from_i64);
#[cfg(has_i128)]
impl_to_biguint!(i128, FromPrimitive::from_i128);

impl_to_biguint!(usize, FromPrimitive::from_usize);
impl_to_biguint!(u8, FromPrimitive::from_u8);
impl_to_biguint!(u16, FromPrimitive::from_u16);
impl_to_biguint!(u32, FromPrimitive::from_u32);
impl_to_biguint!(u64, FromPrimitive::from_u64);
#[cfg(has_i128)]
impl_to_biguint!(u128, FromPrimitive::from_u128);

impl_to_biguint!(f32, FromPrimitive::from_f32);
impl_to_biguint!(f64, FromPrimitive::from_f64);

Expand Down

0 comments on commit 04252b7

Please sign in to comment.