зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 773188fb9acf (bug 1660551) for causing bustages.
CLOSED TREE
This commit is contained in:
Родитель
b79310d312
Коммит
1b1ee1c86e
|
@ -15,7 +15,7 @@ tag = "v0.4.10"
|
||||||
[source."https://github.com/mozilla/mp4parse-rust"]
|
[source."https://github.com/mozilla/mp4parse-rust"]
|
||||||
git = "https://github.com/mozilla/mp4parse-rust"
|
git = "https://github.com/mozilla/mp4parse-rust"
|
||||||
replace-with = "vendored-sources"
|
replace-with = "vendored-sources"
|
||||||
rev = "6ebb531e1b0381c7a5980279637ef6ae7a3b6bc2"
|
rev = "63325444ae3388599f2f222775eebdde4c2f9f30"
|
||||||
|
|
||||||
[source."https://github.com/mozilla/application-services"]
|
[source."https://github.com/mozilla/application-services"]
|
||||||
git = "https://github.com/mozilla/application-services"
|
git = "https://github.com/mozilla/application-services"
|
||||||
|
|
|
@ -2344,7 +2344,7 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
"num-rational 0.2.1",
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png",
|
||||||
]
|
]
|
||||||
|
@ -3121,7 +3121,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mp4parse"
|
name = "mp4parse"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=6ebb531e1b0381c7a5980279637ef6ae7a3b6bc2#6ebb531e1b0381c7a5980279637ef6ae7a3b6bc2"
|
source = "git+https://github.com/mozilla/mp4parse-rust?rev=63325444ae3388599f2f222775eebdde4c2f9f30#63325444ae3388599f2f222775eebdde4c2f9f30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitreader",
|
"bitreader",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
@ -3138,12 +3138,12 @@ version = "0.1.0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mp4parse_capi"
|
name = "mp4parse_capi"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=6ebb531e1b0381c7a5980279637ef6ae7a3b6bc2#6ebb531e1b0381c7a5980279637ef6ae7a3b6bc2"
|
source = "git+https://github.com/mozilla/mp4parse-rust?rev=63325444ae3388599f2f222775eebdde4c2f9f30#63325444ae3388599f2f222775eebdde4c2f9f30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"log",
|
"log",
|
||||||
"mp4parse",
|
"mp4parse",
|
||||||
"num",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3364,20 +3364,6 @@ dependencies = [
|
||||||
"nsstring",
|
"nsstring",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab3e176191bc4faad357e3122c4747aa098ac880e88b168f106386128736cf4a"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint 0.3.0",
|
|
||||||
"num-complex",
|
|
||||||
"num-integer",
|
|
||||||
"num-iter",
|
|
||||||
"num-rational 0.3.0",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -3389,26 +3375,6 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 1.0.0",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-complex"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -3422,21 +3388,19 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.43"
|
version = "0.1.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
checksum = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.0",
|
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-iter"
|
name = "num-iter"
|
||||||
version = "0.1.41"
|
version = "0.1.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
|
checksum = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.0",
|
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
@ -3451,25 +3415,13 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-rational"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 1.0.0",
|
|
||||||
"num-bigint 0.3.0",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.12"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
checksum = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.0",
|
"autocfg 0.1.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3767,7 +3719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c20593a99fe08068cbe2b59001527f36021d6ad53ac5f2d8793fcf2fe94015a0"
|
checksum = "c20593a99fe08068cbe2b59001527f36021d6ad53ac5f2d8793fcf2fe94015a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.5.2",
|
"libloading 0.5.2",
|
||||||
"num-bigint 0.2.3",
|
"num-bigint",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"107804fbf8f667fbad45e7dea9fa1bb32ce8ef5580b543a54455e678d7769708","src/boxes.rs":"5f84805435af90034075709867e02c74a198e26dc628a9fc95df034928ee5bbc","src/fallible.rs":"7dc89699f1e75433ab5c6bbd23807383b3b918fe572d41e68e5a270591b0a4ab","src/lib.rs":"ff16461743a5e09c2dc8ade092206e4c84ddcae061766b38d53eff6f94916b2e","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"f1a27e785d4006cd910ca3c48c8a972da1db9c9b4a67185f67a191ddc3c69328","tests/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"fd646ffd5fab8beed5949b87482048ba400438fa90860f86f357a7f6141dc649"},"package":null}
|
{"files":{"Cargo.toml":"107804fbf8f667fbad45e7dea9fa1bb32ce8ef5580b543a54455e678d7769708","src/boxes.rs":"5f84805435af90034075709867e02c74a198e26dc628a9fc95df034928ee5bbc","src/fallible.rs":"836a36c2bc9803aead4bb24621e4fa6176c77b3752e69459a1f36555eb8bf2ec","src/lib.rs":"7c8bde48b42f5470a937d3affc4452e06b2158ff07c207f39376bdca11efa832","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"f1a27e785d4006cd910ca3c48c8a972da1db9c9b4a67185f67a191ddc3c69328","tests/bug-1655846.avif":"e0a5a06225800fadf05f5352503a4cec11af73eef705c43b4acab5f4a99dea50","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"fd646ffd5fab8beed5949b87482048ba400438fa90860f86f357a7f6141dc649"},"package":null}
|
|
@ -256,7 +256,7 @@ impl<T> TryVec<T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reserve(&mut self, additional: usize) -> Result<()> {
|
fn reserve(&mut self, additional: usize) -> Result<()> {
|
||||||
#[cfg(feature = "mp4parse_fallible")]
|
#[cfg(feature = "mp4parse_fallible")]
|
||||||
{
|
{
|
||||||
let available = self
|
let available = self
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl ToU64 for usize {
|
||||||
|
|
||||||
/// A trait to indicate a type can be infallibly converted to `usize`.
|
/// A trait to indicate a type can be infallibly converted to `usize`.
|
||||||
/// This should only be implemented for infallible conversions, so only unsigned types are valid.
|
/// This should only be implemented for infallible conversions, so only unsigned types are valid.
|
||||||
pub trait ToUsize {
|
trait ToUsize {
|
||||||
fn to_usize(self) -> usize;
|
fn to_usize(self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,16 +975,16 @@ pub struct TrackTimeScale<T: Num>(pub T, pub usize);
|
||||||
/// A time to be scaled by the track's local (mdhd) timescale.
|
/// A time to be scaled by the track's local (mdhd) timescale.
|
||||||
/// Members are time in scale units and the track id.
|
/// Members are time in scale units and the track id.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct TrackScaledTime<T>(pub T, pub usize);
|
pub struct TrackScaledTime<T: Num>(pub T, pub usize);
|
||||||
|
|
||||||
impl<T> std::ops::Add for TrackScaledTime<T>
|
impl<T> std::ops::Add for TrackScaledTime<T>
|
||||||
where
|
where
|
||||||
T: num_traits::CheckedAdd,
|
T: Num,
|
||||||
{
|
{
|
||||||
type Output = Option<Self>;
|
type Output = TrackScaledTime<T>;
|
||||||
|
|
||||||
fn add(self, other: TrackScaledTime<T>) -> Self::Output {
|
fn add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T> {
|
||||||
self.0.checked_add(&other.0).map(|sum| Self(sum, self.1))
|
TrackScaledTime::<T>(self.0 + other.0, self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1953,7 +1953,6 @@ fn read_stbl<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an ftyp box.
|
/// Parse an ftyp box.
|
||||||
/// See ISO 14496-12:2015 § 4.3
|
|
||||||
fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
|
fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
|
||||||
let major = be_u32(src)?;
|
let major = be_u32(src)?;
|
||||||
let minor = be_u32(src)?;
|
let minor = be_u32(src)?;
|
||||||
|
@ -1963,7 +1962,7 @@ fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
|
||||||
}
|
}
|
||||||
// Is a brand_count of zero valid?
|
// Is a brand_count of zero valid?
|
||||||
let brand_count = bytes_left / 4;
|
let brand_count = bytes_left / 4;
|
||||||
let mut brands = TryVec::with_capacity(brand_count.try_into()?)?;
|
let mut brands = TryVec::new();
|
||||||
for _ in 0..brand_count {
|
for _ in 0..brand_count {
|
||||||
brands.push(be_u32(src)?.into())?;
|
brands.push(be_u32(src)?.into())?;
|
||||||
}
|
}
|
||||||
|
@ -2059,11 +2058,10 @@ fn read_tkhd<T: Read>(src: &mut BMFFBox<T>) -> Result<TrackHeaderBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a elst box.
|
/// Parse a elst box.
|
||||||
/// See ISO 14496-12:2015 § 8.6.6
|
|
||||||
fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
|
fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
|
||||||
let (version, _) = read_fullbox_extra(src)?;
|
let (version, _) = read_fullbox_extra(src)?;
|
||||||
let edit_count = be_u32_with_limit(src)?;
|
let edit_count = be_u32_with_limit(src)?;
|
||||||
let mut edits = TryVec::with_capacity(edit_count.to_usize())?;
|
let mut edits = TryVec::new();
|
||||||
for _ in 0..edit_count {
|
for _ in 0..edit_count {
|
||||||
let (segment_duration, media_time) = match version {
|
let (segment_duration, media_time) = match version {
|
||||||
1 => {
|
1 => {
|
||||||
|
@ -2135,11 +2133,10 @@ fn read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a stco box.
|
/// Parse a stco box.
|
||||||
/// See ISO 14496-12:2015 § 8.7.5
|
|
||||||
fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
let offset_count = be_u32_with_limit(src)?;
|
let offset_count = be_u32_with_limit(src)?;
|
||||||
let mut offsets = TryVec::with_capacity(offset_count.to_usize())?;
|
let mut offsets = TryVec::new();
|
||||||
for _ in 0..offset_count {
|
for _ in 0..offset_count {
|
||||||
offsets.push(be_u32(src)?.into())?;
|
offsets.push(be_u32(src)?.into())?;
|
||||||
}
|
}
|
||||||
|
@ -2151,11 +2148,10 @@ fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a co64 box.
|
/// Parse a co64 box.
|
||||||
/// See ISO 14496-12:2015 § 8.7.5
|
|
||||||
fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
let offset_count = be_u32_with_limit(src)?;
|
let offset_count = be_u32_with_limit(src)?;
|
||||||
let mut offsets = TryVec::with_capacity(offset_count.to_usize())?;
|
let mut offsets = TryVec::new();
|
||||||
for _ in 0..offset_count {
|
for _ in 0..offset_count {
|
||||||
offsets.push(be_u64(src)?)?;
|
offsets.push(be_u64(src)?)?;
|
||||||
}
|
}
|
||||||
|
@ -2167,11 +2163,10 @@ fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a stss box.
|
/// Parse a stss box.
|
||||||
/// See ISO 14496-12:2015 § 8.6.2
|
|
||||||
fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
|
fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
let sample_count = be_u32_with_limit(src)?;
|
let sample_count = be_u32_with_limit(src)?;
|
||||||
let mut samples = TryVec::with_capacity(sample_count.to_usize())?;
|
let mut samples = TryVec::new();
|
||||||
for _ in 0..sample_count {
|
for _ in 0..sample_count {
|
||||||
samples.push(be_u32(src)?)?;
|
samples.push(be_u32(src)?)?;
|
||||||
}
|
}
|
||||||
|
@ -2183,11 +2178,10 @@ fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a stsc box.
|
/// Parse a stsc box.
|
||||||
/// See ISO 14496-12:2015 § 8.7.4
|
|
||||||
fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
|
fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
let sample_count = be_u32_with_limit(src)?;
|
let sample_count = be_u32_with_limit(src)?;
|
||||||
let mut samples = TryVec::with_capacity(sample_count.to_usize())?;
|
let mut samples = TryVec::new();
|
||||||
for _ in 0..sample_count {
|
for _ in 0..sample_count {
|
||||||
let first_chunk = be_u32(src)?;
|
let first_chunk = be_u32(src)?;
|
||||||
let samples_per_chunk = be_u32_with_limit(src)?;
|
let samples_per_chunk = be_u32_with_limit(src)?;
|
||||||
|
@ -2205,23 +2199,16 @@ fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
|
||||||
Ok(SampleToChunkBox { samples })
|
Ok(SampleToChunkBox { samples })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a Composition Time to Sample Box
|
|
||||||
/// See ISO 14496-12:2015 § 8.6.1.3
|
|
||||||
fn read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
|
fn read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
|
||||||
let (version, _) = read_fullbox_extra(src)?;
|
let (version, _) = read_fullbox_extra(src)?;
|
||||||
|
|
||||||
let counts = be_u32_with_limit(src)?;
|
let counts = u64::from(be_u32_with_limit(src)?);
|
||||||
|
|
||||||
if src.bytes_left()
|
if src.bytes_left() < counts.checked_mul(8).expect("counts -> bytes overflow") {
|
||||||
< counts
|
|
||||||
.checked_mul(8)
|
|
||||||
.expect("counts -> bytes overflow")
|
|
||||||
.into()
|
|
||||||
{
|
|
||||||
return Err(Error::InvalidData("insufficient data in 'ctts' box"));
|
return Err(Error::InvalidData("insufficient data in 'ctts' box"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut offsets = TryVec::with_capacity(counts.to_usize())?;
|
let mut offsets = TryVec::new();
|
||||||
for _ in 0..counts {
|
for _ in 0..counts {
|
||||||
let (sample_count, time_offset) = match version {
|
let (sample_count, time_offset) = match version {
|
||||||
// According to spec, Version0 shoule be used when version == 0;
|
// According to spec, Version0 shoule be used when version == 0;
|
||||||
|
@ -2248,14 +2235,12 @@ fn read_ctts<T: Read>(src: &mut BMFFBox<T>) -> Result<CompositionOffsetBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a stsz box.
|
/// Parse a stsz box.
|
||||||
/// See ISO 14496-12:2015 § 8.7.3.2
|
|
||||||
fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
|
fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
let sample_size = be_u32(src)?;
|
let sample_size = be_u32(src)?;
|
||||||
let sample_count = be_u32_with_limit(src)?;
|
let sample_count = be_u32_with_limit(src)?;
|
||||||
let mut sample_sizes = TryVec::new();
|
let mut sample_sizes = TryVec::new();
|
||||||
if sample_size == 0 {
|
if sample_size == 0 {
|
||||||
sample_sizes.reserve(sample_count.to_usize())?;
|
|
||||||
for _ in 0..sample_count {
|
for _ in 0..sample_count {
|
||||||
sample_sizes.push(be_u32(src)?)?;
|
sample_sizes.push(be_u32(src)?)?;
|
||||||
}
|
}
|
||||||
|
@ -2271,11 +2256,10 @@ fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a stts box.
|
/// Parse a stts box.
|
||||||
/// See ISO 14496-12:2015 § 8.6.1.2
|
|
||||||
fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
|
fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
let sample_count = be_u32_with_limit(src)?;
|
let sample_count = be_u32_with_limit(src)?;
|
||||||
let mut samples = TryVec::with_capacity(sample_count.to_usize())?;
|
let mut samples = TryVec::new();
|
||||||
for _ in 0..sample_count {
|
for _ in 0..sample_count {
|
||||||
let sample_count = be_u32_with_limit(src)?;
|
let sample_count = be_u32_with_limit(src)?;
|
||||||
let sample_delta = be_u32(src)?;
|
let sample_delta = be_u32(src)?;
|
||||||
|
@ -2437,7 +2421,7 @@ fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
|
||||||
let des = &mut Cursor::new(remains);
|
let des = &mut Cursor::new(remains);
|
||||||
let tag = des.read_u8()?;
|
let tag = des.read_u8()?;
|
||||||
|
|
||||||
// See ISO 14496-1:2010 § 8.3.3 for interpreting size of expandable classes
|
// See ISO 14496-1:2010 § 8.3.3 for interpreting size of exandable classes
|
||||||
|
|
||||||
let mut end: u32 = 0; // It's u8 without declaration type that is incorrect.
|
let mut end: u32 = 0; // It's u8 without declaration type that is incorrect.
|
||||||
// MSB of extend_or_len indicates more bytes, up to 4 bytes.
|
// MSB of extend_or_len indicates more bytes, up to 4 bytes.
|
||||||
|
@ -2643,11 +2627,7 @@ fn read_ds_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
|
||||||
esds.extended_audio_object_type = extended_audio_object_type;
|
esds.extended_audio_object_type = extended_audio_object_type;
|
||||||
esds.audio_sample_rate = Some(sample_frequency_value);
|
esds.audio_sample_rate = Some(sample_frequency_value);
|
||||||
esds.audio_channel_count = Some(channel_counts);
|
esds.audio_channel_count = Some(channel_counts);
|
||||||
if !esds.decoder_specific_data.is_empty() {
|
assert!(esds.decoder_specific_data.is_empty());
|
||||||
return Err(Error::InvalidData(
|
|
||||||
"There can be only one DecSpecificInfoTag descriptor",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
esds.decoder_specific_data.extend_from_slice(data)?;
|
esds.decoder_specific_data.extend_from_slice(data)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2715,7 +2695,6 @@ fn read_es_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See ISO 14496-14:2010 § 6.7.2
|
|
||||||
fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
|
fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
|
|
||||||
|
@ -2730,7 +2709,6 @@ fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `FLACSpecificBox`.
|
/// Parse `FLACSpecificBox`.
|
||||||
/// See https://github.com/xiph/flac/blob/master/doc/isoflac.txt § 3.3.2
|
|
||||||
fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
|
fn read_dfla<T: Read>(src: &mut BMFFBox<T>) -> Result<FLACSpecificBox> {
|
||||||
let (version, flags) = read_fullbox_extra(src)?;
|
let (version, flags) = read_fullbox_extra(src)?;
|
||||||
if version != 0 {
|
if version != 0 {
|
||||||
|
@ -3157,7 +3135,6 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry>
|
||||||
|
|
||||||
/// Parse a stsd box.
|
/// Parse a stsd box.
|
||||||
/// See ISO 14496-12:2015 § 8.5.2
|
/// See ISO 14496-12:2015 § 8.5.2
|
||||||
/// See ISO 14496-14:2010 § 6.7.2
|
|
||||||
fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
|
fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleDescriptionBox> {
|
||||||
let (_, _) = read_fullbox_extra(src)?;
|
let (_, _) = read_fullbox_extra(src)?;
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"1ea27367203b20aa8992320d1a561f0bf98e309d3f799ffa2c3eea3159d1ee57","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"83462422315c22e496960bae922edb23105c0aa272d2b106edd7574ff068513a","src/lib.rs":"e9b6b19c43962e0b21bbcbcab89c8acb09185f18939ccdf25534971e1146410c","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"ca98516ff423c03b5fcc17b05f993f13b32485e4cf3ba86faf1bea72681d75ce","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"185755909b2f4e0ea99604bb423a07623d614a180accdaebd1c98aef2c2e3ae6","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null}
|
{"files":{"Cargo.toml":"13408d7785c5fe40f9db2bac1f93e8cf2aca7c35b5d2ba9acbbb23eb3a71e40a","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"598f828f07bac9b204d3eb7af4efd7158087382fc322dcce913a28729f854f70","src/lib.rs":"dfd3bccfb80aaab2389d11ae00242709d6c5dae8a299b55098bf5ec39698a097","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"ca98516ff423c03b5fcc17b05f993f13b32485e4cf3ba86faf1bea72681d75ce","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"adc8d264c46aef78c047377fbb792a4400d6db98bc44583b464d7b3dc182c884","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null}
|
|
@ -26,7 +26,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
|
||||||
byteorder = "1.2.1"
|
byteorder = "1.2.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mp4parse = {version = "0.11.2", path = "../mp4parse"}
|
mp4parse = {version = "0.11.2", path = "../mp4parse"}
|
||||||
num = "0.3.0"
|
num-traits = "0.2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
|
|
|
@ -62,7 +62,9 @@ fn dump_file(filename: &str) {
|
||||||
for i in 0..counts {
|
for i in 0..counts {
|
||||||
let mut track_info = Mp4parseTrackInfo {
|
let mut track_info = Mp4parseTrackInfo {
|
||||||
track_type: Mp4parseTrackType::Audio,
|
track_type: Mp4parseTrackType::Audio,
|
||||||
..Default::default()
|
track_id: 0,
|
||||||
|
duration: 0,
|
||||||
|
media_time: 0,
|
||||||
};
|
};
|
||||||
match mp4parse_get_track_info(parser, i, &mut track_info) {
|
match mp4parse_get_track_info(parser, i, &mut track_info) {
|
||||||
Mp4parseStatus::Ok => {
|
Mp4parseStatus::Ok => {
|
||||||
|
|
|
@ -37,17 +37,11 @@
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate mp4parse;
|
extern crate mp4parse;
|
||||||
extern crate num;
|
extern crate num_traits;
|
||||||
|
|
||||||
use byteorder::WriteBytesExt;
|
use byteorder::WriteBytesExt;
|
||||||
use num::{CheckedAdd, CheckedSub};
|
use num_traits::{PrimInt, Zero};
|
||||||
use num::{PrimInt, Zero};
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::ops::Neg;
|
|
||||||
use std::ops::{Add, Sub};
|
|
||||||
|
|
||||||
// Symbols we need from our rust api.
|
// Symbols we need from our rust api.
|
||||||
use mp4parse::read_avif;
|
use mp4parse::read_avif;
|
||||||
|
@ -61,7 +55,6 @@ use mp4parse::MediaContext;
|
||||||
use mp4parse::MediaScaledTime;
|
use mp4parse::MediaScaledTime;
|
||||||
use mp4parse::MediaTimeScale;
|
use mp4parse::MediaTimeScale;
|
||||||
use mp4parse::SampleEntry;
|
use mp4parse::SampleEntry;
|
||||||
use mp4parse::ToUsize;
|
|
||||||
use mp4parse::Track;
|
use mp4parse::Track;
|
||||||
use mp4parse::TrackScaledTime;
|
use mp4parse::TrackScaledTime;
|
||||||
use mp4parse::TrackTimeScale;
|
use mp4parse::TrackTimeScale;
|
||||||
|
@ -151,134 +144,36 @@ impl Default for Mp4ParseEncryptionSchemeType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A zero-overhead wrapper around integer types for the sake of always
|
|
||||||
/// requiring checked arithmetic
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct CheckedInteger<T>(pub T);
|
|
||||||
|
|
||||||
impl<T> From<T> for CheckedInteger<T> {
|
|
||||||
fn from(i: T) -> Self {
|
|
||||||
Self(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Orphan rules prevent a more general implementation, but this suffices
|
|
||||||
impl From<CheckedInteger<i64>> for i64 {
|
|
||||||
fn from(checked: CheckedInteger<i64>) -> i64 {
|
|
||||||
checked.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U: Into<T>> Add<U> for CheckedInteger<T>
|
|
||||||
where
|
|
||||||
T: CheckedAdd,
|
|
||||||
{
|
|
||||||
type Output = Option<Self>;
|
|
||||||
|
|
||||||
fn add(self, other: U) -> Self::Output {
|
|
||||||
self.0.checked_add(&other.into()).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U: Into<T>> Sub<U> for CheckedInteger<T>
|
|
||||||
where
|
|
||||||
T: CheckedSub,
|
|
||||||
{
|
|
||||||
type Output = Option<Self>;
|
|
||||||
|
|
||||||
fn sub(self, other: U) -> Self::Output {
|
|
||||||
self.0.checked_sub(&other.into()).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implement subtraction of checked `u64`s returning i64
|
|
||||||
// This is necessary for handling Mp4parseTrackInfo::media_time gracefully
|
|
||||||
impl Sub for CheckedInteger<u64> {
|
|
||||||
type Output = Option<CheckedInteger<i64>>;
|
|
||||||
|
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
|
||||||
if self >= other {
|
|
||||||
self.0
|
|
||||||
.checked_sub(other.0)
|
|
||||||
.and_then(|u| i64::try_from(u).ok())
|
|
||||||
.map(CheckedInteger)
|
|
||||||
} else {
|
|
||||||
other
|
|
||||||
.0
|
|
||||||
.checked_sub(self.0)
|
|
||||||
.and_then(|u| i64::try_from(u).ok())
|
|
||||||
.map(i64::neg)
|
|
||||||
.map(CheckedInteger)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn u64_subtraction_returning_i64() {
|
|
||||||
// self > other
|
|
||||||
assert_eq!(
|
|
||||||
CheckedInteger(2u64) - CheckedInteger(1u64),
|
|
||||||
Some(CheckedInteger(1i64))
|
|
||||||
);
|
|
||||||
|
|
||||||
// self == other
|
|
||||||
assert_eq!(
|
|
||||||
CheckedInteger(1u64) - CheckedInteger(1u64),
|
|
||||||
Some(CheckedInteger(0i64))
|
|
||||||
);
|
|
||||||
|
|
||||||
// difference too large to store in i64
|
|
||||||
assert_eq!(CheckedInteger(u64::MAX) - CheckedInteger(1u64), None);
|
|
||||||
|
|
||||||
// self < other
|
|
||||||
assert_eq!(
|
|
||||||
CheckedInteger(1u64) - CheckedInteger(2u64),
|
|
||||||
Some(CheckedInteger(-1i64))
|
|
||||||
);
|
|
||||||
|
|
||||||
// difference not representable due to overflow
|
|
||||||
assert_eq!(CheckedInteger(1u64) - CheckedInteger(u64::MAX), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: std::cmp::PartialEq> PartialEq<T> for CheckedInteger<T> {
|
|
||||||
fn eq(&self, other: &T) -> bool {
|
|
||||||
self.0 == *other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Mp4parseTrackInfo {
|
pub struct Mp4parseTrackInfo {
|
||||||
pub track_type: Mp4parseTrackType,
|
pub track_type: Mp4parseTrackType,
|
||||||
pub track_id: u32,
|
pub track_id: u32,
|
||||||
pub duration: u64,
|
pub duration: u64,
|
||||||
pub media_time: CheckedInteger<i64>, // wants to be u64? understand how elst adjustment works
|
pub media_time: i64, // wants to be u64? understand how elst adjustment works
|
||||||
// TODO(kinetik): include crypto guff
|
// TODO(kinetik): include crypto guff
|
||||||
// If this changes to u64, we can get rid of the strange
|
|
||||||
// impl Sub for CheckedInteger<u64>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Default, Debug, PartialEq)]
|
#[derive(Default, Debug, PartialEq)]
|
||||||
pub struct Mp4parseIndice {
|
pub struct Mp4parseIndice {
|
||||||
/// The byte offset in the file where the indexed sample begins.
|
/// The byte offset in the file where the indexed sample begins.
|
||||||
pub start_offset: CheckedInteger<u64>,
|
pub start_offset: u64,
|
||||||
/// The byte offset in the file where the indexed sample ends. This is
|
/// The byte offset in the file where the indexed sample ends. This is
|
||||||
/// equivalent to `start_offset` + the length in bytes of the indexed
|
/// equivalent to `start_offset` + the length in bytes of the indexed
|
||||||
/// sample. Typically this will be the `start_offset` of the next sample
|
/// sample. Typically this will be the `start_offset` of the next sample
|
||||||
/// in the file.
|
/// in the file.
|
||||||
pub end_offset: CheckedInteger<u64>,
|
pub end_offset: u64,
|
||||||
/// The time in microseconds when the indexed sample should be displayed.
|
/// The time in microseconds when the indexed sample should be displayed.
|
||||||
/// Analogous to the concept of presentation time stamp (pts).
|
/// Analogous to the concept of presentation time stamp (pts).
|
||||||
pub start_composition: CheckedInteger<i64>,
|
pub start_composition: i64,
|
||||||
/// The time in microseconds when the indexed sample should stop being
|
/// The time in microseconds when the indexed sample should stop being
|
||||||
/// displayed. Typically this would be the `start_composition` time of the
|
/// displayed. Typically this would be the `start_composition` time of the
|
||||||
/// next sample if samples were ordered by composition time.
|
/// next sample if samples were ordered by composition time.
|
||||||
pub end_composition: CheckedInteger<i64>,
|
pub end_composition: i64,
|
||||||
/// The time in microseconds that the indexed sample should be decoded at.
|
/// The time in microseconds that the indexed sample should be decoded at.
|
||||||
/// Analogous to the concept of decode time stamp (dts).
|
/// Analogous to the concept of decode time stamp (dts).
|
||||||
pub start_decode: CheckedInteger<i64>,
|
pub start_decode: i64,
|
||||||
/// Set if the indexed sample is a sync sample. The meaning of sync is
|
/// Set if the indexed sample is a sync sample. The meaning of sync is
|
||||||
/// somewhat codec specific, but essentially amounts to if the sample is a
|
/// somewhat codec specific, but essentially amounts to if the sample is a
|
||||||
/// key frame.
|
/// key frame.
|
||||||
|
@ -704,7 +599,7 @@ where
|
||||||
|
|
||||||
let integer = numerator / denominator;
|
let integer = numerator / denominator;
|
||||||
let remainder = numerator % denominator;
|
let remainder = numerator % denominator;
|
||||||
num::cast(scale2).and_then(|s| match integer.checked_mul(&s) {
|
num_traits::cast(scale2).and_then(|s| match integer.checked_mul(&s) {
|
||||||
Some(integer) => remainder
|
Some(integer) => remainder
|
||||||
.checked_mul(&s)
|
.checked_mul(&s)
|
||||||
.and_then(|remainder| (remainder / denominator).checked_add(&integer)),
|
.and_then(|remainder| (remainder / denominator).checked_add(&integer)),
|
||||||
|
@ -765,23 +660,19 @@ pub unsafe extern "C" fn mp4parse_get_track_info(
|
||||||
let track = &context.tracks[track_index];
|
let track = &context.tracks[track_index];
|
||||||
|
|
||||||
if let (Some(track_timescale), Some(context_timescale)) = (track.timescale, context.timescale) {
|
if let (Some(track_timescale), Some(context_timescale)) = (track.timescale, context.timescale) {
|
||||||
let media_time: CheckedInteger<_> = match track.media_time.map_or(Some(0), |media_time| {
|
let media_time = match track.media_time.map_or(Some(0), |media_time| {
|
||||||
track_time_to_us(media_time, track_timescale)
|
track_time_to_us(media_time, track_timescale)
|
||||||
}) {
|
}) {
|
||||||
Some(time) => time.into(),
|
Some(time) => time as i64,
|
||||||
None => return Mp4parseStatus::Invalid,
|
None => return Mp4parseStatus::Invalid,
|
||||||
};
|
};
|
||||||
let empty_duration: CheckedInteger<_> =
|
let empty_duration = match track.empty_duration.map_or(Some(0), |empty_duration| {
|
||||||
match track.empty_duration.map_or(Some(0), |empty_duration| {
|
media_time_to_us(empty_duration, context_timescale)
|
||||||
media_time_to_us(empty_duration, context_timescale)
|
}) {
|
||||||
}) {
|
Some(time) => time as i64,
|
||||||
Some(time) => time.into(),
|
|
||||||
None => return Mp4parseStatus::Invalid,
|
|
||||||
};
|
|
||||||
info.media_time = match media_time - empty_duration {
|
|
||||||
Some(difference) => difference,
|
|
||||||
None => return Mp4parseStatus::Invalid,
|
None => return Mp4parseStatus::Invalid,
|
||||||
};
|
};
|
||||||
|
info.media_time = media_time - empty_duration;
|
||||||
|
|
||||||
if let Some(track_duration) = track.duration {
|
if let Some(track_duration) = track.duration {
|
||||||
match track_time_to_us(track_duration, track_timescale) {
|
match track_time_to_us(track_duration, track_timescale) {
|
||||||
|
@ -1244,28 +1135,23 @@ fn get_indice_table(
|
||||||
}
|
}
|
||||||
|
|
||||||
let media_time = match (&track.media_time, &track.timescale) {
|
let media_time = match (&track.media_time, &track.timescale) {
|
||||||
(&Some(t), &Some(s)) => track_time_to_us(t, s)
|
(&Some(t), &Some(s)) => track_time_to_us(t, s).map(|v| v as i64),
|
||||||
.and_then(|v| i64::try_from(v).ok())
|
|
||||||
.map(Into::into),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let empty_duration: Option<CheckedInteger<_>> =
|
let empty_duration = match (&track.empty_duration, &context.timescale) {
|
||||||
match (&track.empty_duration, &context.timescale) {
|
(&Some(e), &Some(s)) => media_time_to_us(e, s).map(|v| v as i64),
|
||||||
(&Some(e), &Some(s)) => media_time_to_us(e, s)
|
_ => None,
|
||||||
.and_then(|v| i64::try_from(v).ok())
|
};
|
||||||
.map(Into::into),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find the track start offset time from 'elst'.
|
// Find the track start offset time from 'elst'.
|
||||||
// 'media_time' maps start time onward, 'empty_duration' adds time offset
|
// 'media_time' maps start time onward, 'empty_duration' adds time offset
|
||||||
// before first frame is displayed.
|
// before first frame is displayed.
|
||||||
let offset_time = match (empty_duration, media_time) {
|
let offset_time = match (empty_duration, media_time) {
|
||||||
(Some(e), Some(m)) => (e - m).ok_or(Err(Mp4parseStatus::Invalid))?,
|
(Some(e), Some(m)) => e - m,
|
||||||
(Some(e), None) => e,
|
(Some(e), None) => e,
|
||||||
(None, Some(m)) => m,
|
(None, Some(m)) => m,
|
||||||
_ => 0.into(),
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(v) = create_sample_table(track, offset_time) {
|
if let Some(v) = create_sample_table(track, offset_time) {
|
||||||
|
@ -1292,7 +1178,6 @@ struct TimeOffsetIterator<'a> {
|
||||||
impl<'a> Iterator for TimeOffsetIterator<'a> {
|
impl<'a> Iterator for TimeOffsetIterator<'a> {
|
||||||
type Item = i64;
|
type Item = i64;
|
||||||
|
|
||||||
#[allow(clippy::reversed_empty_ranges)]
|
|
||||||
fn next(&mut self) -> Option<i64> {
|
fn next(&mut self) -> Option<i64> {
|
||||||
let has_sample = self.cur_sample_range.next().or_else(|| {
|
let has_sample = self.cur_sample_range.next().or_else(|| {
|
||||||
// At end of current TimeOffset, find the next TimeOffset.
|
// At end of current TimeOffset, find the next TimeOffset.
|
||||||
|
@ -1349,7 +1234,6 @@ struct TimeToSampleIterator<'a> {
|
||||||
impl<'a> Iterator for TimeToSampleIterator<'a> {
|
impl<'a> Iterator for TimeToSampleIterator<'a> {
|
||||||
type Item = u32;
|
type Item = u32;
|
||||||
|
|
||||||
#[allow(clippy::reversed_empty_ranges)]
|
|
||||||
fn next(&mut self) -> Option<u32> {
|
fn next(&mut self) -> Option<u32> {
|
||||||
let has_sample = self.cur_sample_count.next().or_else(|| {
|
let has_sample = self.cur_sample_count.next().or_else(|| {
|
||||||
self.cur_sample_count = match self.stts_iter.next() {
|
self.cur_sample_count = match self.stts_iter.next() {
|
||||||
|
@ -1387,21 +1271,6 @@ impl<'a> TimeToSampleIterator<'a> {
|
||||||
// For example:
|
// For example:
|
||||||
// (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10),
|
// (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10),
|
||||||
// (7, 10), (8, 10), (9, 2)
|
// (7, 10), (8, 10), (9, 2)
|
||||||
fn sample_to_chunk_iter<'a>(
|
|
||||||
stsc_samples: &'a TryVec<mp4parse::SampleToChunk>,
|
|
||||||
stco_offsets: &'a TryVec<u64>,
|
|
||||||
) -> SampleToChunkIterator<'a> {
|
|
||||||
SampleToChunkIterator {
|
|
||||||
chunks: (0..0),
|
|
||||||
sample_count: 0,
|
|
||||||
stsc_peek_iter: stsc_samples.as_slice().iter().peekable(),
|
|
||||||
remain_chunk_count: stco_offsets
|
|
||||||
.len()
|
|
||||||
.try_into()
|
|
||||||
.expect("stco.entry_count is u32"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SampleToChunkIterator<'a> {
|
struct SampleToChunkIterator<'a> {
|
||||||
chunks: std::ops::Range<u32>,
|
chunks: std::ops::Range<u32>,
|
||||||
sample_count: u32,
|
sample_count: u32,
|
||||||
|
@ -1416,12 +1285,7 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
|
||||||
let has_chunk = self.chunks.next().or_else(|| {
|
let has_chunk = self.chunks.next().or_else(|| {
|
||||||
self.chunks = self.locate();
|
self.chunks = self.locate();
|
||||||
self.remain_chunk_count
|
self.remain_chunk_count
|
||||||
.checked_sub(
|
.checked_sub(self.chunks.len() as u32)
|
||||||
self.chunks
|
|
||||||
.len()
|
|
||||||
.try_into()
|
|
||||||
.expect("len() of a Range<u32> must fit in u32"),
|
|
||||||
)
|
|
||||||
.and_then(|res| {
|
.and_then(|res| {
|
||||||
self.remain_chunk_count = res;
|
self.remain_chunk_count = res;
|
||||||
self.chunks.next()
|
self.chunks.next()
|
||||||
|
@ -1433,7 +1297,6 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SampleToChunkIterator<'a> {
|
impl<'a> SampleToChunkIterator<'a> {
|
||||||
#[allow(clippy::reversed_empty_ranges)]
|
|
||||||
fn locate(&mut self) -> std::ops::Range<u32> {
|
fn locate(&mut self) -> std::ops::Range<u32> {
|
||||||
loop {
|
loop {
|
||||||
return match (self.stsc_peek_iter.next(), self.stsc_peek_iter.peek()) {
|
return match (self.stsc_peek_iter.next(), self.stsc_peek_iter.peek()) {
|
||||||
|
@ -1461,11 +1324,7 @@ impl<'a> SampleToChunkIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::reversed_empty_ranges)]
|
fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<TryVec<Mp4parseIndice>> {
|
||||||
fn create_sample_table(
|
|
||||||
track: &Track,
|
|
||||||
track_offset_time: CheckedInteger<i64>,
|
|
||||||
) -> Option<TryVec<Mp4parseIndice>> {
|
|
||||||
let timescale = match track.timescale {
|
let timescale = match track.timescale {
|
||||||
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
|
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
@ -1482,32 +1341,31 @@ fn create_sample_table(
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut sample_table = TryVec::new();
|
||||||
let mut sample_size_iter = stsz.sample_sizes.iter();
|
let mut sample_size_iter = stsz.sample_sizes.iter();
|
||||||
|
|
||||||
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
|
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
|
||||||
// offset address.
|
// offset address.
|
||||||
|
let stsc_iter = SampleToChunkIterator {
|
||||||
|
chunks: (0..0),
|
||||||
|
sample_count: 0,
|
||||||
|
stsc_peek_iter: stsc.samples.as_slice().iter().peekable(),
|
||||||
|
remain_chunk_count: stco.offsets.len() as u32,
|
||||||
|
};
|
||||||
|
|
||||||
// With large numbers of samples, the cost of many allocations dominates,
|
for i in stsc_iter {
|
||||||
// so it's worth iterating twice to allocate sample_table just once.
|
|
||||||
let total_sample_count = sample_to_chunk_iter(&stsc.samples, &stco.offsets)
|
|
||||||
.by_ref()
|
|
||||||
.map(|(_, sample_counts)| sample_counts.to_usize())
|
|
||||||
.sum();
|
|
||||||
let mut sample_table = TryVec::with_capacity(total_sample_count).ok()?;
|
|
||||||
|
|
||||||
for i in sample_to_chunk_iter(&stsc.samples, &stco.offsets) {
|
|
||||||
let chunk_id = i.0 as usize;
|
let chunk_id = i.0 as usize;
|
||||||
let sample_counts = i.1;
|
let sample_counts = i.1;
|
||||||
let mut cur_position = match stco.offsets.get(chunk_id) {
|
let mut cur_position = match stco.offsets.get(chunk_id) {
|
||||||
Some(&i) => i.into(),
|
Some(&i) => i,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
for _ in 0..sample_counts {
|
for _ in 0..sample_counts {
|
||||||
let start_offset = cur_position;
|
let start_offset = cur_position;
|
||||||
let end_offset = match (stsz.sample_size, sample_size_iter.next()) {
|
let end_offset = match (stsz.sample_size, sample_size_iter.next()) {
|
||||||
(_, Some(t)) => (start_offset + *t)?,
|
(_, Some(t)) => start_offset + u64::from(*t),
|
||||||
(t, _) if t > 0 => (start_offset + t)?,
|
(t, _) if t > 0 => start_offset + u64::from(t),
|
||||||
_ => 0.into(),
|
_ => 0,
|
||||||
};
|
};
|
||||||
if end_offset == 0 {
|
if end_offset == 0 {
|
||||||
return None;
|
return None;
|
||||||
|
@ -1518,8 +1376,10 @@ fn create_sample_table(
|
||||||
.push(Mp4parseIndice {
|
.push(Mp4parseIndice {
|
||||||
start_offset,
|
start_offset,
|
||||||
end_offset,
|
end_offset,
|
||||||
|
start_composition: 0,
|
||||||
|
end_composition: 0,
|
||||||
|
start_decode: 0,
|
||||||
sync: !has_sync_table,
|
sync: !has_sync_table,
|
||||||
..Default::default()
|
|
||||||
})
|
})
|
||||||
.ok()?;
|
.ok()?;
|
||||||
}
|
}
|
||||||
|
@ -1529,7 +1389,7 @@ fn create_sample_table(
|
||||||
if let Some(ref v) = track.stss {
|
if let Some(ref v) = track.stss {
|
||||||
for iter in &v.samples {
|
for iter in &v.samples {
|
||||||
match iter
|
match iter
|
||||||
.checked_sub(&1)
|
.checked_sub(1)
|
||||||
.and_then(|idx| sample_table.get_mut(idx as usize))
|
.and_then(|idx| sample_table.get_mut(idx as usize))
|
||||||
{
|
{
|
||||||
Some(elem) => elem.sync = true,
|
Some(elem) => elem.sync = true,
|
||||||
|
@ -1566,20 +1426,25 @@ fn create_sample_table(
|
||||||
let mut sum_delta = TrackScaledTime::<i64>(0, track.id);
|
let mut sum_delta = TrackScaledTime::<i64>(0, track.id);
|
||||||
for sample in sample_table.as_mut_slice() {
|
for sample in sample_table.as_mut_slice() {
|
||||||
let decode_time = sum_delta;
|
let decode_time = sum_delta;
|
||||||
sum_delta = (sum_delta + stts_iter.next_delta())?;
|
sum_delta = sum_delta + stts_iter.next_delta();
|
||||||
|
|
||||||
// ctts_offset is the current sample offset time.
|
// ctts_offset is the current sample offset time.
|
||||||
let ctts_offset = ctts_offset_iter.next_offset_time();
|
let ctts_offset = ctts_offset_iter.next_offset_time();
|
||||||
|
|
||||||
let start_composition = track_time_to_us((decode_time + ctts_offset)?, timescale)?;
|
let start_composition = track_time_to_us(decode_time + ctts_offset, timescale);
|
||||||
|
|
||||||
let end_composition = track_time_to_us((sum_delta + ctts_offset)?, timescale)?;
|
let end_composition = track_time_to_us(sum_delta + ctts_offset, timescale);
|
||||||
|
|
||||||
let start_decode = track_time_to_us(decode_time, timescale)?;
|
let start_decode = track_time_to_us(decode_time, timescale);
|
||||||
|
|
||||||
sample.start_composition = (track_offset_time + start_composition)?;
|
match (start_composition, end_composition, start_decode) {
|
||||||
sample.end_composition = (track_offset_time + end_composition)?;
|
(Some(s_c), Some(e_c), Some(s_d)) => {
|
||||||
sample.start_decode = start_decode.into();
|
sample.start_composition = s_c + track_offset_time;
|
||||||
|
sample.end_composition = e_c + track_offset_time;
|
||||||
|
sample.start_decode = s_d;
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Correct composition end time due to 'ctts' causes composition time re-ordering.
|
// Correct composition end time due to 'ctts' causes composition time re-ordering.
|
||||||
|
@ -1588,15 +1453,14 @@ fn create_sample_table(
|
||||||
// calculate to correct the composition end time.
|
// calculate to correct the composition end time.
|
||||||
if !sample_table.is_empty() {
|
if !sample_table.is_empty() {
|
||||||
// Create an index table refers to sample_table and sorted by start_composisiton time.
|
// Create an index table refers to sample_table and sorted by start_composisiton time.
|
||||||
let mut sort_table = TryVec::with_capacity(sample_table.len()).ok()?;
|
let mut sort_table = TryVec::new();
|
||||||
|
|
||||||
for i in 0..sample_table.len() {
|
for i in 0..sample_table.len() {
|
||||||
sort_table.push(i).ok()?;
|
sort_table.push(i).ok()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
sort_table.sort_by_key(|i| match sample_table.get(*i) {
|
sort_table.sort_by_key(|i| match sample_table.get(*i) {
|
||||||
Some(v) => v.start_composition,
|
Some(v) => v.start_composition,
|
||||||
_ => 0.into(),
|
_ => 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
for indices in sort_table.windows(2) {
|
for indices in sort_table.windows(2) {
|
||||||
|
@ -1736,14 +1600,13 @@ fn get_pssh_info(
|
||||||
|
|
||||||
pssh_data.clear();
|
pssh_data.clear();
|
||||||
for pssh in &context.psshs {
|
for pssh in &context.psshs {
|
||||||
let content_len = pssh
|
let content_len = pssh.box_content.len();
|
||||||
.box_content
|
if content_len > std::u32::MAX as usize {
|
||||||
.len()
|
return Err(Mp4parseStatus::Invalid);
|
||||||
.try_into()
|
}
|
||||||
.map_err(|_| Mp4parseStatus::Invalid)?;
|
|
||||||
let mut data_len = TryVec::new();
|
let mut data_len = TryVec::new();
|
||||||
if data_len
|
if data_len
|
||||||
.write_u32::<byteorder::NativeEndian>(content_len)
|
.write_u32::<byteorder::NativeEndian>(content_len as u32)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
return Err(Mp4parseStatus::Io);
|
return Err(Mp4parseStatus::Io);
|
||||||
|
@ -1821,7 +1684,9 @@ fn arg_validation() {
|
||||||
|
|
||||||
let mut dummy_info = Mp4parseTrackInfo {
|
let mut dummy_info = Mp4parseTrackInfo {
|
||||||
track_type: Mp4parseTrackType::Video,
|
track_type: Mp4parseTrackType::Video,
|
||||||
..Default::default()
|
track_id: 0,
|
||||||
|
duration: 0,
|
||||||
|
media_time: 0,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Mp4parseStatus::BadArg,
|
Mp4parseStatus::BadArg,
|
||||||
|
@ -1889,7 +1754,9 @@ fn arg_validation_with_parser() {
|
||||||
|
|
||||||
let mut dummy_info = Mp4parseTrackInfo {
|
let mut dummy_info = Mp4parseTrackInfo {
|
||||||
track_type: Mp4parseTrackType::Video,
|
track_type: Mp4parseTrackType::Video,
|
||||||
..Default::default()
|
track_id: 0,
|
||||||
|
duration: 0,
|
||||||
|
media_time: 0,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Mp4parseStatus::BadArg,
|
Mp4parseStatus::BadArg,
|
||||||
|
@ -1961,7 +1828,9 @@ fn minimal_mp4_get_track_info() {
|
||||||
|
|
||||||
let mut info = Mp4parseTrackInfo {
|
let mut info = Mp4parseTrackInfo {
|
||||||
track_type: Mp4parseTrackType::Video,
|
track_type: Mp4parseTrackType::Video,
|
||||||
..Default::default()
|
track_id: 0,
|
||||||
|
duration: 0,
|
||||||
|
media_time: 0,
|
||||||
};
|
};
|
||||||
assert_eq!(Mp4parseStatus::Ok, unsafe {
|
assert_eq!(Mp4parseStatus::Ok, unsafe {
|
||||||
mp4parse_get_track_info(parser, 0, &mut info)
|
mp4parse_get_track_info(parser, 0, &mut info)
|
||||||
|
@ -2033,7 +1902,9 @@ fn minimal_mp4_get_track_info_invalid_track_number() {
|
||||||
|
|
||||||
let mut info = Mp4parseTrackInfo {
|
let mut info = Mp4parseTrackInfo {
|
||||||
track_type: Mp4parseTrackType::Video,
|
track_type: Mp4parseTrackType::Video,
|
||||||
..Default::default()
|
track_id: 0,
|
||||||
|
duration: 0,
|
||||||
|
media_time: 0,
|
||||||
};
|
};
|
||||||
assert_eq!(Mp4parseStatus::BadArg, unsafe {
|
assert_eq!(Mp4parseStatus::BadArg, unsafe {
|
||||||
mp4parse_get_track_info(parser, 3, &mut info)
|
mp4parse_get_track_info(parser, 3, &mut info)
|
||||||
|
|
|
@ -48,19 +48,19 @@ fn parse_sample_table() {
|
||||||
|
|
||||||
// Compare the value from stagefright.
|
// Compare the value from stagefright.
|
||||||
let audio_indice_0 = Mp4parseIndice {
|
let audio_indice_0 = Mp4parseIndice {
|
||||||
start_offset: 27_046.into(),
|
start_offset: 27_046,
|
||||||
end_offset: 27_052.into(),
|
end_offset: 27_052,
|
||||||
start_composition: 0.into(),
|
start_composition: 0,
|
||||||
end_composition: 46_439.into(),
|
end_composition: 46_439,
|
||||||
start_decode: 0.into(),
|
start_decode: 0,
|
||||||
sync: true,
|
sync: true,
|
||||||
};
|
};
|
||||||
let audio_indice_215 = Mp4parseIndice {
|
let audio_indice_215 = Mp4parseIndice {
|
||||||
start_offset: 283_550.into(),
|
start_offset: 283_550,
|
||||||
end_offset: 283_556.into(),
|
end_offset: 283_556,
|
||||||
start_composition: 9_984_580.into(),
|
start_composition: 9_984_580,
|
||||||
end_composition: 10_031_020.into(),
|
end_composition: 10_031_020,
|
||||||
start_decode: 9_984_580.into(),
|
start_decode: 9_984_580,
|
||||||
sync: true,
|
sync: true,
|
||||||
};
|
};
|
||||||
assert_eq!(indice.length, 216);
|
assert_eq!(indice.length, 216);
|
||||||
|
@ -83,19 +83,19 @@ fn parse_sample_table() {
|
||||||
|
|
||||||
// Compare the last few data from stagefright.
|
// Compare the last few data from stagefright.
|
||||||
let video_indice_291 = Mp4parseIndice {
|
let video_indice_291 = Mp4parseIndice {
|
||||||
start_offset: 280_226.into(),
|
start_offset: 280_226,
|
||||||
end_offset: 280_855.into(),
|
end_offset: 280_855,
|
||||||
start_composition: 9_838_333.into(),
|
start_composition: 9_838_333,
|
||||||
end_composition: 9_871_677.into(),
|
end_composition: 9_871_677,
|
||||||
start_decode: 9_710_000.into(),
|
start_decode: 9_710_000,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
let video_indice_292 = Mp4parseIndice {
|
let video_indice_292 = Mp4parseIndice {
|
||||||
start_offset: 280_855.into(),
|
start_offset: 280_855,
|
||||||
end_offset: 281_297.into(),
|
end_offset: 281_297,
|
||||||
start_composition: 9_805_011.into(),
|
start_composition: 9_805_011,
|
||||||
end_composition: 9_838_333.into(),
|
end_composition: 9_838_333,
|
||||||
start_decode: 9_710_011.into(),
|
start_decode: 9_710_011,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
// TODO: start_composition time in stagefright is 9905000, but it is 9904999 in parser, it
|
// TODO: start_composition time in stagefright is 9905000, but it is 9904999 in parser, it
|
||||||
|
@ -103,19 +103,19 @@ fn parse_sample_table() {
|
||||||
//let video_indice_293 = Mp4parseIndice { start_offset: 281_297, end_offset: 281_919, start_composition: 9_905_000, end_composition: 9_938_344, start_decode: 9_776_666, sync: false };
|
//let video_indice_293 = Mp4parseIndice { start_offset: 281_297, end_offset: 281_919, start_composition: 9_905_000, end_composition: 9_938_344, start_decode: 9_776_666, sync: false };
|
||||||
//let video_indice_294 = Mp4parseIndice { start_offset: 281_919, end_offset: 282_391, start_composition: 9_871_677, end_composition: 9_905_000, start_decode: 9_776_677, sync: false };
|
//let video_indice_294 = Mp4parseIndice { start_offset: 281_919, end_offset: 282_391, start_composition: 9_871_677, end_composition: 9_905_000, start_decode: 9_776_677, sync: false };
|
||||||
let video_indice_295 = Mp4parseIndice {
|
let video_indice_295 = Mp4parseIndice {
|
||||||
start_offset: 282_391.into(),
|
start_offset: 282_391,
|
||||||
end_offset: 283_032.into(),
|
end_offset: 283_032,
|
||||||
start_composition: 9_971_666.into(),
|
start_composition: 9_971_666,
|
||||||
end_composition: 9_971_677.into(),
|
end_composition: 9_971_677,
|
||||||
start_decode: 9_843_333.into(),
|
start_decode: 9_843_333,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
let video_indice_296 = Mp4parseIndice {
|
let video_indice_296 = Mp4parseIndice {
|
||||||
start_offset: 283_092.into(),
|
start_offset: 283_092,
|
||||||
end_offset: 283_526.into(),
|
end_offset: 283_526,
|
||||||
start_composition: 9_938_344.into(),
|
start_composition: 9_938_344,
|
||||||
end_composition: 9_971_666.into(),
|
end_composition: 9_971_666,
|
||||||
start_decode: 9_843_344.into(),
|
start_decode: 9_843_344,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,27 +169,27 @@ fn parse_sample_table_with_elst() {
|
||||||
// Due to 'elst', the start_composition and end_composition are negative
|
// Due to 'elst', the start_composition and end_composition are negative
|
||||||
// at first two samples.
|
// at first two samples.
|
||||||
let audio_indice_0 = Mp4parseIndice {
|
let audio_indice_0 = Mp4parseIndice {
|
||||||
start_offset: 6992.into(),
|
start_offset: 6992,
|
||||||
end_offset: 7363.into(),
|
end_offset: 7363,
|
||||||
start_composition: (-36281).into(),
|
start_composition: -36281,
|
||||||
end_composition: (-13062).into(),
|
end_composition: -13062,
|
||||||
start_decode: 0.into(),
|
start_decode: 0,
|
||||||
sync: true,
|
sync: true,
|
||||||
};
|
};
|
||||||
let audio_indice_1 = Mp4parseIndice {
|
let audio_indice_1 = Mp4parseIndice {
|
||||||
start_offset: 7363.into(),
|
start_offset: 7363,
|
||||||
end_offset: 7735.into(),
|
end_offset: 7735,
|
||||||
start_composition: (-13062).into(),
|
start_composition: -13062,
|
||||||
end_composition: 10158.into(),
|
end_composition: 10158,
|
||||||
start_decode: 23219.into(),
|
start_decode: 23219,
|
||||||
sync: true,
|
sync: true,
|
||||||
};
|
};
|
||||||
let audio_indice_2 = Mp4parseIndice {
|
let audio_indice_2 = Mp4parseIndice {
|
||||||
start_offset: 7735.into(),
|
start_offset: 7735,
|
||||||
end_offset: 8106.into(),
|
end_offset: 8106,
|
||||||
start_composition: 10158.into(),
|
start_composition: 10158,
|
||||||
end_composition: 33378.into(),
|
end_composition: 33378,
|
||||||
start_decode: 46439.into(),
|
start_decode: 46439,
|
||||||
sync: true,
|
sync: true,
|
||||||
};
|
};
|
||||||
assert_eq!(indice.length, 21);
|
assert_eq!(indice.length, 21);
|
||||||
|
@ -236,35 +236,35 @@ fn parse_sample_table_with_negative_ctts() {
|
||||||
|
|
||||||
// There are negative value in 'ctts' table.
|
// There are negative value in 'ctts' table.
|
||||||
let video_indice_0 = Mp4parseIndice {
|
let video_indice_0 = Mp4parseIndice {
|
||||||
start_offset: 48.into(),
|
start_offset: 48,
|
||||||
end_offset: 890.into(),
|
end_offset: 890,
|
||||||
start_composition: 0.into(),
|
start_composition: 0,
|
||||||
end_composition: 33_333.into(),
|
end_composition: 33_333,
|
||||||
start_decode: 0.into(),
|
start_decode: 0,
|
||||||
sync: true,
|
sync: true,
|
||||||
};
|
};
|
||||||
let video_indice_1 = Mp4parseIndice {
|
let video_indice_1 = Mp4parseIndice {
|
||||||
start_offset: 890.into(),
|
start_offset: 890,
|
||||||
end_offset: 913.into(),
|
end_offset: 913,
|
||||||
start_composition: 133_333.into(),
|
start_composition: 133_333,
|
||||||
end_composition: 166_666.into(),
|
end_composition: 166_666,
|
||||||
start_decode: 33_333.into(),
|
start_decode: 33_333,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
let video_indice_2 = Mp4parseIndice {
|
let video_indice_2 = Mp4parseIndice {
|
||||||
start_offset: 913.into(),
|
start_offset: 913,
|
||||||
end_offset: 934.into(),
|
end_offset: 934,
|
||||||
start_composition: 66_666.into(),
|
start_composition: 66_666,
|
||||||
end_composition: 100_000.into(),
|
end_composition: 100_000,
|
||||||
start_decode: 66_666.into(),
|
start_decode: 66_666,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
let video_indice_3 = Mp4parseIndice {
|
let video_indice_3 = Mp4parseIndice {
|
||||||
start_offset: 934.into(),
|
start_offset: 934,
|
||||||
end_offset: 955.into(),
|
end_offset: 955,
|
||||||
start_composition: 33_333.into(),
|
start_composition: 33_333,
|
||||||
end_composition: 66_666.into(),
|
end_composition: 66_666,
|
||||||
start_decode: 100_000.into(),
|
start_decode: 100_000,
|
||||||
sync: false,
|
sync: false,
|
||||||
};
|
};
|
||||||
assert_eq!(indice.length, 300);
|
assert_eq!(indice.length, 300);
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"files":{"Cargo.toml":"ba1041ccca008388ab7d7432ae63b811d8e744c8fa9e50f371bfbeb78acd1995","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"25f684f15b0ed6ea216c3831e567a9b5dc02b78ff7e579e0d7323305db75218c","RELEASES.md":"5a3045437dc1850ae4e39acd14f2660ed7bace9b0c4d7dae3950f049dbfd4d65","benches/bigint.rs":"252c0dc1f220a6fbdc151e729069260c2f5909516467ceb873e412e5691d7042","benches/factorial.rs":"d536f5584987847f10321b94175a0d8fd2beb14b7c814ec28eef1f96ca081fbe","benches/gcd.rs":"7ec5ce7174e1d31bd08ccc5670f5a32a5c084f258d7980cd6d02e0a8bb5562c4","benches/roots.rs":"3f87db894c379122aee5cd8520c7c759c26d8a9649ac47f45d1bf4d560e1cb07","benches/shootout-pidigits.rs":"985b76d6dba05c396efe4da136c6a0bb2c02bcf5b05cbb346f0f802a891629bb","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"56d4fbb7a55750e61d2074df2735a31995c1decbd988c0e722926235e0fed487","ci/rustup.sh":"c976bb2756da3876363b01fdbf06c13de20df421e5add45e4017c4df42ed06a6","ci/test_full.sh":"a0ac26b85809eb43edd813c9dc88f34a1a8227b7618f4bede89c8f2ac9a4c05a","src/algorithms.rs":"8827c46df051214d1d0e7670680ca9f4834eae678ed340c86b5ea32fddbc7c3c","src/bigint.rs":"7f113fdc034c566bc8475ff0a7d136aa8250cae047b4356084e6797a15f968e1","src/bigrand.rs":"d2f72b8833f367dd8990b4b026f302d838144c5a4de942135d39a3a9932f137d","src/biguint.rs":"b95bfcf84e3f831fb07982aa4b058cd16a524eaa493946eed8e8c5fb8d65797a","src/lib.rs":"d5cc50306f73f07555e7d3413edd2ca5c7d54cbc80a2e83844d77fb8750ae314","src/macros.rs":"2e763517922d960c06e3ac4d319b1d81e66dffadfde8fdf300ff8b8bb95bd8cd","src/monty.rs":"6a867846b7f6af9115add2fd59fccd0651c71dd7f2316e8fb9c812ff3c27da12","tests/bigint.rs":"f7df454f085a862ad5a98e3a802303a3fdf06275a7a1b92074b40b76a715bed2","tests/bigint_bitwise.rs":"dc9436c8f200f2b0ac08cefb23bb8e39c4e688e9026a506a678416c3d573128b","tests/bigint_scalar.rs":"aa176ed102cafd425a215a93460806914d8f3ac288c98ec3e56772fa17379838","tests/biguint.rs":"9ae79f96d1a3beca5be95dffe9d79dc3436f886edc6cae51faf4203c3e0c4681","tests/biguint_scalar.rs":"9cc6f2bf2fe77f34b09eb2266c23aded3b27a60dc1859eb60d3013164292467e","tests/consts/mod.rs":"f9ea5f40733e2f5f432803d830be9db929d91e5e5efd8510b07c6ced2fe554be","tests/macros/mod.rs":"2789b680dd14a770d5ceef430018be0ada85098d69e218c61c17214084c4f763","tests/modpow.rs":"f14cdea11e355a371b314cc866dfa13281a3226706ab2cf01c1485273afde300","tests/quickcheck.rs":"6d6c1ec244b2384a8b34e989870aef8bcedccf6cc46e2626b29a032703bef03c","tests/rand.rs":"08370135bd78432660cfcd708a9ea852022d555bc92c1f3c482fabd17faa64a0","tests/roots.rs":"9ec1bdb0cd1c72402a41e5470325a5276af75979b7fc0f0b63e7bbbb9f3505b2","tests/serde.rs":"79d7a0347207b3a3666af67d2ed97fa34f2922732121a3cb8f5b9f990846acfa","tests/torture.rs":"9fe4897580c0ebe2b7062f5b0b890b4b03510daa45c9236f0edba7144f9eb6f8"},"package":"f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"}
|
|
|
@ -1,81 +0,0 @@
|
||||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
|
||||||
#
|
|
||||||
# When uploading crates to the registry Cargo will automatically
|
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
|
||||||
# to registry (e.g., crates.io) dependencies
|
|
||||||
#
|
|
||||||
# If you believe there's an error in this file please file an
|
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
|
||||||
# editing this file be aware that the upstream Cargo.toml
|
|
||||||
# will likely look very different (and much more reasonable)
|
|
||||||
|
|
||||||
[package]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.2.3"
|
|
||||||
authors = ["The Rust Project Developers"]
|
|
||||||
build = "build.rs"
|
|
||||||
description = "Big integer implementation for Rust"
|
|
||||||
homepage = "https://github.com/rust-num/num-bigint"
|
|
||||||
documentation = "https://docs.rs/num-bigint"
|
|
||||||
readme = "README.md"
|
|
||||||
keywords = ["mathematics", "numerics", "bignum"]
|
|
||||||
categories = ["algorithms", "data-structures", "science"]
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
repository = "https://github.com/rust-num/num-bigint"
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
features = ["std", "serde", "rand", "quickcheck"]
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "bigint"
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "factorial"
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "gcd"
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "roots"
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "shootout-pidigits"
|
|
||||||
harness = false
|
|
||||||
[dependencies.num-integer]
|
|
||||||
version = "0.1.39"
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.num-traits]
|
|
||||||
version = "0.2.7"
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.quickcheck]
|
|
||||||
version = "0.8"
|
|
||||||
optional = true
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.quickcheck_macros]
|
|
||||||
version = "0.8"
|
|
||||||
optional = true
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.rand]
|
|
||||||
version = "0.5"
|
|
||||||
features = ["std"]
|
|
||||||
optional = true
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.serde]
|
|
||||||
version = "1.0"
|
|
||||||
features = ["std"]
|
|
||||||
optional = true
|
|
||||||
default-features = false
|
|
||||||
[dev-dependencies.serde_test]
|
|
||||||
version = "1.0"
|
|
||||||
[build-dependencies.autocfg]
|
|
||||||
version = "0.1.2"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["std"]
|
|
||||||
i128 = ["num-integer/i128", "num-traits/i128"]
|
|
||||||
std = ["num-integer/std", "num-traits/std"]
|
|
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,25 +0,0 @@
|
||||||
Copyright (c) 2014 The Rust Project Developers
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
|
||||||
person obtaining a copy of this software and associated
|
|
||||||
documentation files (the "Software"), to deal in the
|
|
||||||
Software without restriction, including without
|
|
||||||
limitation the rights to use, copy, modify, merge,
|
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software
|
|
||||||
is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
|
||||||
shall be included in all copies or substantial portions
|
|
||||||
of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,63 +0,0 @@
|
||||||
# num-bigint
|
|
||||||
|
|
||||||
[![crate](https://img.shields.io/crates/v/num-bigint.svg)](https://crates.io/crates/num-bigint)
|
|
||||||
[![documentation](https://docs.rs/num-bigint/badge.svg)](https://docs.rs/num-bigint)
|
|
||||||
![minimum rustc 1.15](https://img.shields.io/badge/rustc-1.15+-red.svg)
|
|
||||||
[![Travis status](https://travis-ci.org/rust-num/num-bigint.svg?branch=master)](https://travis-ci.org/rust-num/num-bigint)
|
|
||||||
|
|
||||||
Big integer types for Rust, `BigInt` and `BigUint`.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add this to your `Cargo.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
num-bigint = "0.2"
|
|
||||||
```
|
|
||||||
|
|
||||||
and this to your crate root:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
extern crate num_bigint;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
The `std` crate feature is mandatory and enabled by default. If you depend on
|
|
||||||
`num-bigint` with `default-features = false`, you must manually enable the
|
|
||||||
`std` feature yourself. In the future, we hope to support `#![no_std]` with
|
|
||||||
the `alloc` crate when `std` is not enabled.
|
|
||||||
|
|
||||||
Implementations for `i128` and `u128` are only available with Rust 1.26 and
|
|
||||||
later. The build script automatically detects this, but you can make it
|
|
||||||
mandatory by enabling the `i128` crate feature.
|
|
||||||
|
|
||||||
## Releases
|
|
||||||
|
|
||||||
Release notes are available in [RELEASES.md](RELEASES.md).
|
|
||||||
|
|
||||||
## Compatibility
|
|
||||||
|
|
||||||
The `num-bigint` crate is tested for rustc 1.15 and greater.
|
|
||||||
|
|
||||||
## Alternatives
|
|
||||||
|
|
||||||
While `num-bigint` strives for good performance in pure Rust code, other
|
|
||||||
crates may offer better performance with different trade-offs. The following
|
|
||||||
table offers a brief comparison to a few alternatives.
|
|
||||||
|
|
||||||
| Crate | License | Min rustc | Implementation |
|
|
||||||
| :--------------- | :------------- | :-------- | :------------- |
|
|
||||||
| **`num-bigint`** | MIT/Apache-2.0 | 1.15 | pure rust |
|
|
||||||
| [`ramp`] | Apache-2.0 | nightly | rust and inline assembly |
|
|
||||||
| [`rug`] | LGPL-3.0+ | 1.31 | bundles [GMP] via [`gmp-mpfr-sys`] |
|
|
||||||
| [`rust-gmp`] | MIT | stable? | links to [GMP] |
|
|
||||||
| [`apint`] | MIT/Apache-2.0 | 1.26 | pure rust (unfinished) |
|
|
||||||
|
|
||||||
[GMP]: https://gmplib.org/
|
|
||||||
[`gmp-mpfr-sys`]: https://crates.io/crates/gmp-mpfr-sys
|
|
||||||
[`rug`]: https://crates.io/crates/rug
|
|
||||||
[`rust-gmp`]: https://crates.io/crates/rust-gmp
|
|
||||||
[`ramp`]: https://crates.io/crates/ramp
|
|
||||||
[`apint`]: https://crates.io/crates/apint
|
|
|
@ -1,134 +0,0 @@
|
||||||
# Release 0.2.3 (2019-09-03)
|
|
||||||
|
|
||||||
- [`Pow` is now implemented for `BigUint` exponents][77].
|
|
||||||
- [The optional `quickcheck` feature enables implementations of `Arbitrary`][99].
|
|
||||||
- See the [full comparison][compare-0.2.3] for performance enhancements and more!
|
|
||||||
|
|
||||||
[77]: https://github.com/rust-num/num-bigint/pull/77
|
|
||||||
[99]: https://github.com/rust-num/num-bigint/pull/99
|
|
||||||
[compare-0.2.3]: https://github.com/rust-num/num-bigint/compare/num-bigint-0.2.2...num-bigint-0.2.3
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @lcnr, @maxbla, @mikelodder7, @mikong,
|
|
||||||
@TheLetterTheta, @tspiteri, @XAMPPRocky, @youknowone
|
|
||||||
|
|
||||||
# Release 0.2.2 (2018-12-14)
|
|
||||||
|
|
||||||
- [The `Roots` implementations now use better initial guesses][71].
|
|
||||||
- [Fixed `to_signed_bytes_*` for some positive numbers][72], where the
|
|
||||||
most-significant byte is `0x80` and the rest are `0`.
|
|
||||||
|
|
||||||
[71]: https://github.com/rust-num/num-bigint/pull/71
|
|
||||||
[72]: https://github.com/rust-num/num-bigint/pull/72
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @leodasvacas
|
|
||||||
|
|
||||||
# Release 0.2.1 (2018-11-02)
|
|
||||||
|
|
||||||
- [`RandBigInt` now uses `Rng::fill_bytes`][53] to improve performance, instead
|
|
||||||
of repeated `gen::<u32>` calls. The also affects the implementations of the
|
|
||||||
other `rand` traits. This may potentially change the values produced by some
|
|
||||||
seeded RNGs on previous versions, but the values were tested to be stable
|
|
||||||
with `ChaChaRng`, `IsaacRng`, and `XorShiftRng`.
|
|
||||||
- [`BigInt` and `BigUint` now implement `num_integer::Roots`][56].
|
|
||||||
- [`BigInt` and `BigUint` now implement `num_traits::Pow`][54].
|
|
||||||
- [`BigInt` and `BigUint` now implement operators with 128-bit integers][64].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @dignifiedquire, @mancabizjak, @Robbepop,
|
|
||||||
@TheIronBorn, @thomwiggers
|
|
||||||
|
|
||||||
[53]: https://github.com/rust-num/num-bigint/pull/53
|
|
||||||
[54]: https://github.com/rust-num/num-bigint/pull/54
|
|
||||||
[56]: https://github.com/rust-num/num-bigint/pull/56
|
|
||||||
[64]: https://github.com/rust-num/num-bigint/pull/64
|
|
||||||
|
|
||||||
# Release 0.2.0 (2018-05-25)
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- [`BigInt` and `BigUint` now implement `Product` and `Sum`][22] for iterators
|
|
||||||
of any item that we can `Mul` and `Add`, respectively. For example, a
|
|
||||||
factorial can now be simply: `let f: BigUint = (1u32..1000).product();`
|
|
||||||
- [`BigInt` now supports two's-complement logic operations][26], namely
|
|
||||||
`BitAnd`, `BitOr`, `BitXor`, and `Not`. These act conceptually as if each
|
|
||||||
number had an infinite prefix of `0` or `1` bits for positive or negative.
|
|
||||||
- [`BigInt` now supports assignment operators][41] like `AddAssign`.
|
|
||||||
- [`BigInt` and `BigUint` now support conversions with `i128` and `u128`][44],
|
|
||||||
if sufficient compiler support is detected.
|
|
||||||
- [`BigInt` and `BigUint` now implement rand's `SampleUniform` trait][48], and
|
|
||||||
[a custom `RandomBits` distribution samples by bit size][49].
|
|
||||||
- The release also includes other miscellaneous improvements to performance.
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
- [`num-bigint` now requires rustc 1.15 or greater][23].
|
|
||||||
- [The crate now has a `std` feature, and won't build without it][46]. This is
|
|
||||||
in preparation for someday supporting `#![no_std]` with `alloc`.
|
|
||||||
- [The `serde` dependency has been updated to 1.0][24], still disabled by
|
|
||||||
default. The `rustc-serialize` crate is no longer supported by `num-bigint`.
|
|
||||||
- [The `rand` dependency has been updated to 0.5][48], now disabled by default.
|
|
||||||
This requires rustc 1.22 or greater for `rand`'s own requirement.
|
|
||||||
- [`Shr for BigInt` now rounds down][8] rather than toward zero, matching the
|
|
||||||
behavior of the primitive integers for negative values.
|
|
||||||
- [`ParseBigIntError` is now an opaque type][37].
|
|
||||||
- [The `big_digit` module is no longer public][38], nor are the `BigDigit` and
|
|
||||||
`DoubleBigDigit` types and `ZERO_BIG_DIGIT` constant that were re-exported in
|
|
||||||
the crate root. Public APIs which deal in digits, like `BigUint::from_slice`,
|
|
||||||
will now always be base-`u32`.
|
|
||||||
|
|
||||||
**Contributors**: @clarcharr, @cuviper, @dodomorandi, @tiehuis, @tspiteri
|
|
||||||
|
|
||||||
[8]: https://github.com/rust-num/num-bigint/pull/8
|
|
||||||
[22]: https://github.com/rust-num/num-bigint/pull/22
|
|
||||||
[23]: https://github.com/rust-num/num-bigint/pull/23
|
|
||||||
[24]: https://github.com/rust-num/num-bigint/pull/24
|
|
||||||
[26]: https://github.com/rust-num/num-bigint/pull/26
|
|
||||||
[37]: https://github.com/rust-num/num-bigint/pull/37
|
|
||||||
[38]: https://github.com/rust-num/num-bigint/pull/38
|
|
||||||
[41]: https://github.com/rust-num/num-bigint/pull/41
|
|
||||||
[44]: https://github.com/rust-num/num-bigint/pull/44
|
|
||||||
[46]: https://github.com/rust-num/num-bigint/pull/46
|
|
||||||
[48]: https://github.com/rust-num/num-bigint/pull/48
|
|
||||||
[49]: https://github.com/rust-num/num-bigint/pull/49
|
|
||||||
|
|
||||||
# Release 0.1.44 (2018-05-14)
|
|
||||||
|
|
||||||
- [Division with single-digit divisors is now much faster.][42]
|
|
||||||
- The README now compares [`ramp`, `rug`, `rust-gmp`][20], and [`apint`][21].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @Robbepop
|
|
||||||
|
|
||||||
[20]: https://github.com/rust-num/num-bigint/pull/20
|
|
||||||
[21]: https://github.com/rust-num/num-bigint/pull/21
|
|
||||||
[42]: https://github.com/rust-num/num-bigint/pull/42
|
|
||||||
|
|
||||||
# Release 0.1.43 (2018-02-08)
|
|
||||||
|
|
||||||
- [The new `BigInt::modpow`][18] performs signed modular exponentiation, using
|
|
||||||
the existing `BigUint::modpow` and rounding negatives similar to `mod_floor`.
|
|
||||||
|
|
||||||
**Contributors**: @cuviper
|
|
||||||
|
|
||||||
[18]: https://github.com/rust-num/num-bigint/pull/18
|
|
||||||
|
|
||||||
|
|
||||||
# Release 0.1.42 (2018-02-07)
|
|
||||||
|
|
||||||
- [num-bigint now has its own source repository][num-356] at [rust-num/num-bigint][home].
|
|
||||||
- [`lcm` now avoids creating a large intermediate product][num-350].
|
|
||||||
- [`gcd` now uses Stein's algorithm][15] with faster shifts instead of division.
|
|
||||||
- [`rand` support is now extended to 0.4][11] (while still allowing 0.3).
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @Emerentius, @ignatenkobrain, @mhogrefe
|
|
||||||
|
|
||||||
[home]: https://github.com/rust-num/num-bigint
|
|
||||||
[num-350]: https://github.com/rust-num/num/pull/350
|
|
||||||
[num-356]: https://github.com/rust-num/num/pull/356
|
|
||||||
[11]: https://github.com/rust-num/num-bigint/pull/11
|
|
||||||
[15]: https://github.com/rust-num/num-bigint/pull/15
|
|
||||||
|
|
||||||
|
|
||||||
# Prior releases
|
|
||||||
|
|
||||||
No prior release notes were kept. Thanks all the same to the many
|
|
||||||
contributors that have made this crate what it is!
|
|
||||||
|
|
|
@ -1,368 +0,0 @@
|
||||||
#![feature(test)]
|
|
||||||
#![cfg(feature = "rand")]
|
|
||||||
|
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
extern crate rand;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use num_bigint::{BigInt, BigUint, RandBigInt};
|
|
||||||
use num_traits::{FromPrimitive, Num, One, Pow, Zero};
|
|
||||||
use rand::{SeedableRng, StdRng};
|
|
||||||
use std::mem::replace;
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
fn get_rng() -> StdRng {
|
|
||||||
let mut seed = [0; 32];
|
|
||||||
for i in 1..32 {
|
|
||||||
seed[usize::from(i)] = i;
|
|
||||||
}
|
|
||||||
SeedableRng::from_seed(seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let x = rng.gen_bigint(xbits);
|
|
||||||
let y = rng.gen_bigint(ybits);
|
|
||||||
|
|
||||||
b.iter(|| &x * &y);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let x = rng.gen_bigint(xbits);
|
|
||||||
let y = rng.gen_bigint(ybits);
|
|
||||||
|
|
||||||
b.iter(|| &x / &y);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remainder_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let x = rng.gen_bigint(xbits);
|
|
||||||
let y = rng.gen_bigint(ybits);
|
|
||||||
|
|
||||||
b.iter(|| &x % &y);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn factorial(n: usize) -> BigUint {
|
|
||||||
let mut f: BigUint = One::one();
|
|
||||||
for i in 1..(n + 1) {
|
|
||||||
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
|
||||||
f = f * bu;
|
|
||||||
}
|
|
||||||
f
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute Fibonacci numbers
|
|
||||||
fn fib(n: usize) -> BigUint {
|
|
||||||
let mut f0: BigUint = Zero::zero();
|
|
||||||
let mut f1: BigUint = One::one();
|
|
||||||
for _ in 0..n {
|
|
||||||
let f2 = f0 + &f1;
|
|
||||||
f0 = replace(&mut f1, f2);
|
|
||||||
}
|
|
||||||
f0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute Fibonacci numbers with two ops per iteration
|
|
||||||
/// (add and subtract, like issue #200)
|
|
||||||
fn fib2(n: usize) -> BigUint {
|
|
||||||
let mut f0: BigUint = Zero::zero();
|
|
||||||
let mut f1: BigUint = One::one();
|
|
||||||
for _ in 0..n {
|
|
||||||
f1 = f1 + &f0;
|
|
||||||
f0 = &f1 - f0;
|
|
||||||
}
|
|
||||||
f0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn multiply_0(b: &mut Bencher) {
|
|
||||||
multiply_bench(b, 1 << 8, 1 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn multiply_1(b: &mut Bencher) {
|
|
||||||
multiply_bench(b, 1 << 8, 1 << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn multiply_2(b: &mut Bencher) {
|
|
||||||
multiply_bench(b, 1 << 16, 1 << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn multiply_3(b: &mut Bencher) {
|
|
||||||
multiply_bench(b, 1 << 16, 1 << 17);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn divide_0(b: &mut Bencher) {
|
|
||||||
divide_bench(b, 1 << 8, 1 << 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn divide_1(b: &mut Bencher) {
|
|
||||||
divide_bench(b, 1 << 12, 1 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn divide_2(b: &mut Bencher) {
|
|
||||||
divide_bench(b, 1 << 16, 1 << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn remainder_0(b: &mut Bencher) {
|
|
||||||
remainder_bench(b, 1 << 8, 1 << 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn remainder_1(b: &mut Bencher) {
|
|
||||||
remainder_bench(b, 1 << 12, 1 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn remainder_2(b: &mut Bencher) {
|
|
||||||
remainder_bench(b, 1 << 16, 1 << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn factorial_100(b: &mut Bencher) {
|
|
||||||
b.iter(|| factorial(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib_100(b: &mut Bencher) {
|
|
||||||
b.iter(|| fib(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib_1000(b: &mut Bencher) {
|
|
||||||
b.iter(|| fib(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib_10000(b: &mut Bencher) {
|
|
||||||
b.iter(|| fib(10000));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib2_100(b: &mut Bencher) {
|
|
||||||
b.iter(|| fib2(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib2_1000(b: &mut Bencher) {
|
|
||||||
b.iter(|| fib2(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib2_10000(b: &mut Bencher) {
|
|
||||||
b.iter(|| fib2(10000));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fac_to_string(b: &mut Bencher) {
|
|
||||||
let fac = factorial(100);
|
|
||||||
b.iter(|| fac.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn fib_to_string(b: &mut Bencher) {
|
|
||||||
let fib = fib(100);
|
|
||||||
b.iter(|| fib.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_str_radix_bench(b: &mut Bencher, radix: u32) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let x = rng.gen_bigint(1009);
|
|
||||||
b.iter(|| x.to_str_radix(radix));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn to_str_radix_02(b: &mut Bencher) {
|
|
||||||
to_str_radix_bench(b, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn to_str_radix_08(b: &mut Bencher) {
|
|
||||||
to_str_radix_bench(b, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn to_str_radix_10(b: &mut Bencher) {
|
|
||||||
to_str_radix_bench(b, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn to_str_radix_16(b: &mut Bencher) {
|
|
||||||
to_str_radix_bench(b, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn to_str_radix_36(b: &mut Bencher) {
|
|
||||||
to_str_radix_bench(b, 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_str_radix_bench(b: &mut Bencher, radix: u32) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let x = rng.gen_bigint(1009);
|
|
||||||
let s = x.to_str_radix(radix);
|
|
||||||
assert_eq!(x, BigInt::from_str_radix(&s, radix).unwrap());
|
|
||||||
b.iter(|| BigInt::from_str_radix(&s, radix));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn from_str_radix_02(b: &mut Bencher) {
|
|
||||||
from_str_radix_bench(b, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn from_str_radix_08(b: &mut Bencher) {
|
|
||||||
from_str_radix_bench(b, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn from_str_radix_10(b: &mut Bencher) {
|
|
||||||
from_str_radix_bench(b, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn from_str_radix_16(b: &mut Bencher) {
|
|
||||||
from_str_radix_bench(b, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn from_str_radix_36(b: &mut Bencher) {
|
|
||||||
from_str_radix_bench(b, 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rand_bench(b: &mut Bencher, bits: usize) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
|
|
||||||
b.iter(|| rng.gen_bigint(bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_64(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_256(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_1009(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1009);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_2048(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 11);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_4096(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_8192(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 13);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_65536(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn rand_131072(b: &mut Bencher) {
|
|
||||||
rand_bench(b, 1 << 17);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn shl(b: &mut Bencher) {
|
|
||||||
let n = BigUint::one() << 1000;
|
|
||||||
b.iter(|| {
|
|
||||||
let mut m = n.clone();
|
|
||||||
for i in 0..50 {
|
|
||||||
m = m << i;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn shr(b: &mut Bencher) {
|
|
||||||
let n = BigUint::one() << 2000;
|
|
||||||
b.iter(|| {
|
|
||||||
let mut m = n.clone();
|
|
||||||
for i in 0..50 {
|
|
||||||
m = m >> i;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn hash(b: &mut Bencher) {
|
|
||||||
use std::collections::HashSet;
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let v: Vec<BigInt> = (1000..2000).map(|bits| rng.gen_bigint(bits)).collect();
|
|
||||||
b.iter(|| {
|
|
||||||
let h: HashSet<&BigInt> = v.iter().collect();
|
|
||||||
assert_eq!(h.len(), v.len());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn pow_bench(b: &mut Bencher) {
|
|
||||||
b.iter(|| {
|
|
||||||
let upper = 100_usize;
|
|
||||||
for i in 2..upper + 1 {
|
|
||||||
for j in 2..upper + 1 {
|
|
||||||
let i_big = BigUint::from_usize(i).unwrap();
|
|
||||||
i_big.pow(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This modulus is the prime from the 2048-bit MODP DH group:
|
|
||||||
/// https://tools.ietf.org/html/rfc3526#section-3
|
|
||||||
const RFC3526_2048BIT_MODP_GROUP: &'static str =
|
|
||||||
"\
|
|
||||||
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
|
||||||
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
|
||||||
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
|
||||||
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
|
||||||
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
|
||||||
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
|
||||||
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
|
||||||
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
|
||||||
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
|
||||||
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
|
||||||
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modpow(b: &mut Bencher) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let base = rng.gen_biguint(2048);
|
|
||||||
let e = rng.gen_biguint(2048);
|
|
||||||
let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap();
|
|
||||||
|
|
||||||
b.iter(|| base.modpow(&e, &m));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modpow_even(b: &mut Bencher) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let base = rng.gen_biguint(2048);
|
|
||||||
let e = rng.gen_biguint(2048);
|
|
||||||
// Make the modulus even, so monty (base-2^32) doesn't apply.
|
|
||||||
let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap() - 1u32;
|
|
||||||
|
|
||||||
b.iter(|| base.modpow(&e, &m));
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_traits;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use num_bigint::BigUint;
|
|
||||||
use num_traits::One;
|
|
||||||
use std::ops::{Div, Mul};
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn factorial_mul_biguint(b: &mut Bencher) {
|
|
||||||
b.iter(|| {
|
|
||||||
(1u32..1000)
|
|
||||||
.map(BigUint::from)
|
|
||||||
.fold(BigUint::one(), Mul::mul)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn factorial_mul_u32(b: &mut Bencher) {
|
|
||||||
b.iter(|| (1u32..1000).fold(BigUint::one(), Mul::mul));
|
|
||||||
}
|
|
||||||
|
|
||||||
// The division test is inspired by this blog comparison:
|
|
||||||
// <https://tiehuis.github.io/big-integers-in-zig#division-test-single-limb>
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn factorial_div_biguint(b: &mut Bencher) {
|
|
||||||
let n: BigUint = (1u32..1000).fold(BigUint::one(), Mul::mul);
|
|
||||||
b.iter(|| {
|
|
||||||
(1u32..1000)
|
|
||||||
.rev()
|
|
||||||
.map(BigUint::from)
|
|
||||||
.fold(n.clone(), Div::div)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn factorial_div_u32(b: &mut Bencher) {
|
|
||||||
let n: BigUint = (1u32..1000).fold(BigUint::one(), Mul::mul);
|
|
||||||
b.iter(|| (1u32..1000).rev().fold(n.clone(), Div::div));
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
#![feature(test)]
|
|
||||||
#![cfg(feature = "rand")]
|
|
||||||
|
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
extern crate rand;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use num_bigint::{BigUint, RandBigInt};
|
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::Zero;
|
|
||||||
use rand::{SeedableRng, StdRng};
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
fn get_rng() -> StdRng {
|
|
||||||
let mut seed = [0; 32];
|
|
||||||
for i in 1..32 {
|
|
||||||
seed[usize::from(i)] = i;
|
|
||||||
}
|
|
||||||
SeedableRng::from_seed(seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
|
|
||||||
let mut rng = get_rng();
|
|
||||||
let x = rng.gen_biguint(bits);
|
|
||||||
let y = rng.gen_biguint(bits);
|
|
||||||
|
|
||||||
assert_eq!(euclid(&x, &y), x.gcd(&y));
|
|
||||||
|
|
||||||
b.iter(|| gcd(&x, &y));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
|
|
||||||
// Use Euclid's algorithm
|
|
||||||
let mut m = x.clone();
|
|
||||||
let mut n = y.clone();
|
|
||||||
while !m.is_zero() {
|
|
||||||
let temp = m;
|
|
||||||
m = n % &temp;
|
|
||||||
n = temp;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_euclid_0064(b: &mut Bencher) {
|
|
||||||
bench(b, 64, euclid);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_euclid_0256(b: &mut Bencher) {
|
|
||||||
bench(b, 256, euclid);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_euclid_1024(b: &mut Bencher) {
|
|
||||||
bench(b, 1024, euclid);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_euclid_4096(b: &mut Bencher) {
|
|
||||||
bench(b, 4096, euclid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Integer for BigUint now uses Stein for gcd
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_stein_0064(b: &mut Bencher) {
|
|
||||||
bench(b, 64, BigUint::gcd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_stein_0256(b: &mut Bencher) {
|
|
||||||
bench(b, 256, BigUint::gcd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_stein_1024(b: &mut Bencher) {
|
|
||||||
bench(b, 1024, BigUint::gcd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn gcd_stein_4096(b: &mut Bencher) {
|
|
||||||
bench(b, 4096, BigUint::gcd);
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
#![feature(test)]
|
|
||||||
#![cfg(feature = "rand")]
|
|
||||||
|
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_traits;
|
|
||||||
extern crate rand;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use num_bigint::{BigUint, RandBigInt};
|
|
||||||
use num_traits::Pow;
|
|
||||||
use rand::{SeedableRng, StdRng};
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
// The `big64` cases demonstrate the speed of cases where the value
|
|
||||||
// can be converted to a `u64` primitive for faster calculation.
|
|
||||||
//
|
|
||||||
// The `big1k` cases demonstrate those that can convert to `f64` for
|
|
||||||
// a better initial guess of the actual value.
|
|
||||||
//
|
|
||||||
// The `big2k` and `big4k` cases are too big for `f64`, and use a simpler guess.
|
|
||||||
|
|
||||||
fn get_rng() -> StdRng {
|
|
||||||
let mut seed = [0; 32];
|
|
||||||
for i in 1..32 {
|
|
||||||
seed[usize::from(i)] = i;
|
|
||||||
}
|
|
||||||
SeedableRng::from_seed(seed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check(x: &BigUint, n: u32) {
|
|
||||||
let root = x.nth_root(n);
|
|
||||||
if n == 2 {
|
|
||||||
assert_eq!(root, x.sqrt())
|
|
||||||
} else if n == 3 {
|
|
||||||
assert_eq!(root, x.cbrt())
|
|
||||||
}
|
|
||||||
|
|
||||||
let lo = root.pow(n);
|
|
||||||
assert!(lo <= *x);
|
|
||||||
assert_eq!(lo.nth_root(n), root);
|
|
||||||
assert_eq!((&lo - 1u32).nth_root(n), &root - 1u32);
|
|
||||||
|
|
||||||
let hi = (&root + 1u32).pow(n);
|
|
||||||
assert!(hi > *x);
|
|
||||||
assert_eq!(hi.nth_root(n), &root + 1u32);
|
|
||||||
assert_eq!((&hi - 1u32).nth_root(n), root);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_sqrt(b: &mut Bencher, bits: usize) {
|
|
||||||
let x = get_rng().gen_biguint(bits);
|
|
||||||
eprintln!("bench_sqrt({})", x);
|
|
||||||
|
|
||||||
check(&x, 2);
|
|
||||||
b.iter(|| x.sqrt());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big64_sqrt(b: &mut Bencher) {
|
|
||||||
bench_sqrt(b, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big1k_sqrt(b: &mut Bencher) {
|
|
||||||
bench_sqrt(b, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big2k_sqrt(b: &mut Bencher) {
|
|
||||||
bench_sqrt(b, 2048);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big4k_sqrt(b: &mut Bencher) {
|
|
||||||
bench_sqrt(b, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_cbrt(b: &mut Bencher, bits: usize) {
|
|
||||||
let x = get_rng().gen_biguint(bits);
|
|
||||||
eprintln!("bench_cbrt({})", x);
|
|
||||||
|
|
||||||
check(&x, 3);
|
|
||||||
b.iter(|| x.cbrt());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big64_cbrt(b: &mut Bencher) {
|
|
||||||
bench_cbrt(b, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big1k_cbrt(b: &mut Bencher) {
|
|
||||||
bench_cbrt(b, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big2k_cbrt(b: &mut Bencher) {
|
|
||||||
bench_cbrt(b, 2048);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big4k_cbrt(b: &mut Bencher) {
|
|
||||||
bench_cbrt(b, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_nth_root(b: &mut Bencher, bits: usize, n: u32) {
|
|
||||||
let x = get_rng().gen_biguint(bits);
|
|
||||||
eprintln!("bench_{}th_root({})", n, x);
|
|
||||||
|
|
||||||
check(&x, n);
|
|
||||||
b.iter(|| x.nth_root(n));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big64_nth_10(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 64, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big1k_nth_10(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 1024, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big1k_nth_100(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 1024, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big1k_nth_1000(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 1024, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big1k_nth_10000(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 1024, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big2k_nth_10(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 2048, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big2k_nth_100(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 2048, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big2k_nth_1000(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 2048, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big2k_nth_10000(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 2048, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big4k_nth_10(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 4096, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big4k_nth_100(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 4096, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big4k_nth_1000(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 4096, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn big4k_nth_10000(b: &mut Bencher) {
|
|
||||||
bench_nth_root(b, 4096, 10000);
|
|
||||||
}
|
|
|
@ -1,142 +0,0 @@
|
||||||
// The Computer Language Benchmarks Game
|
|
||||||
// http://benchmarksgame.alioth.debian.org/
|
|
||||||
//
|
|
||||||
// contributed by the Rust Project Developers
|
|
||||||
|
|
||||||
// Copyright (c) 2013-2014 The Rust Project Developers
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions
|
|
||||||
// are met:
|
|
||||||
//
|
|
||||||
// - Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// - Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in
|
|
||||||
// the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
//
|
|
||||||
// - Neither the name of "The Computer Language Benchmarks Game" nor
|
|
||||||
// the name of "The Computer Language Shootout Benchmarks" nor the
|
|
||||||
// names of its contributors may be used to endorse or promote
|
|
||||||
// products derived from this software without specific prior
|
|
||||||
// written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
use std::io;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
|
|
||||||
|
|
||||||
struct Context {
|
|
||||||
numer: BigInt,
|
|
||||||
accum: BigInt,
|
|
||||||
denom: BigInt,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context {
|
|
||||||
fn new() -> Context {
|
|
||||||
Context {
|
|
||||||
numer: One::one(),
|
|
||||||
accum: Zero::zero(),
|
|
||||||
denom: One::one(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_i32(i: i32) -> BigInt {
|
|
||||||
FromPrimitive::from_i32(i).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_digit(&self) -> i32 {
|
|
||||||
if self.numer > self.accum {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
let (q, r) = (&self.numer * Context::from_i32(3) + &self.accum).div_rem(&self.denom);
|
|
||||||
if r + &self.numer >= self.denom {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
q.to_i32().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_term(&mut self, k: i32) {
|
|
||||||
let y2 = Context::from_i32(k * 2 + 1);
|
|
||||||
self.accum = (&self.accum + (&self.numer << 1)) * &y2;
|
|
||||||
self.numer = &self.numer * Context::from_i32(k);
|
|
||||||
self.denom = &self.denom * y2;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eliminate_digit(&mut self, d: i32) {
|
|
||||||
let d = Context::from_i32(d);
|
|
||||||
let ten = Context::from_i32(10);
|
|
||||||
self.accum = (&self.accum - &self.denom * d) * &ten;
|
|
||||||
self.numer = &self.numer * ten;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pidigits(n: isize, out: &mut dyn io::Write) -> io::Result<()> {
|
|
||||||
let mut k = 0;
|
|
||||||
let mut context = Context::new();
|
|
||||||
|
|
||||||
for i in 1..(n + 1) {
|
|
||||||
let mut d;
|
|
||||||
loop {
|
|
||||||
k += 1;
|
|
||||||
context.next_term(k);
|
|
||||||
d = context.extract_digit();
|
|
||||||
if d != -1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(out, "{}", d)?;
|
|
||||||
if i % 10 == 0 {
|
|
||||||
write!(out, "\t:{}\n", i)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.eliminate_digit(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
let m = n % 10;
|
|
||||||
if m != 0 {
|
|
||||||
for _ in m..10 {
|
|
||||||
write!(out, " ")?;
|
|
||||||
}
|
|
||||||
write!(out, "\t:{}\n", n)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_DIGITS: isize = 512;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args = std::env::args().collect::<Vec<_>>();
|
|
||||||
let n = if args.len() < 2 {
|
|
||||||
DEFAULT_DIGITS
|
|
||||||
} else if args[1] == "--bench" {
|
|
||||||
return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap();
|
|
||||||
} else {
|
|
||||||
FromStr::from_str(&args[1]).unwrap()
|
|
||||||
};
|
|
||||||
pidigits(n, &mut std::io::stdout()).unwrap();
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
extern crate autocfg;
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let ac = autocfg::new();
|
|
||||||
if ac.probe_type("i128") {
|
|
||||||
println!("cargo:rustc-cfg=has_i128");
|
|
||||||
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
|
||||||
panic!("i128 support was not detected!");
|
|
||||||
}
|
|
||||||
|
|
||||||
autocfg::rerun_path(file!());
|
|
||||||
}
|
|
|
@ -1,789 +0,0 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::cmp;
|
|
||||||
use std::cmp::Ordering::{self, Equal, Greater, Less};
|
|
||||||
use std::iter::repeat;
|
|
||||||
use std::mem;
|
|
||||||
use traits;
|
|
||||||
use traits::{One, Zero};
|
|
||||||
|
|
||||||
use biguint::BigUint;
|
|
||||||
|
|
||||||
use bigint::BigInt;
|
|
||||||
use bigint::Sign;
|
|
||||||
use bigint::Sign::{Minus, NoSign, Plus};
|
|
||||||
|
|
||||||
use big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit};
|
|
||||||
|
|
||||||
// Generic functions for add/subtract/multiply with carry/borrow:
|
|
||||||
|
|
||||||
// Add with carry:
|
|
||||||
#[inline]
|
|
||||||
fn adc(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
|
|
||||||
*acc += DoubleBigDigit::from(a);
|
|
||||||
*acc += DoubleBigDigit::from(b);
|
|
||||||
let lo = *acc as BigDigit;
|
|
||||||
*acc >>= big_digit::BITS;
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtract with borrow:
|
|
||||||
#[inline]
|
|
||||||
fn sbb(a: BigDigit, b: BigDigit, acc: &mut SignedDoubleBigDigit) -> BigDigit {
|
|
||||||
*acc += SignedDoubleBigDigit::from(a);
|
|
||||||
*acc -= SignedDoubleBigDigit::from(b);
|
|
||||||
let lo = *acc as BigDigit;
|
|
||||||
*acc >>= big_digit::BITS;
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mac_with_carry(a: BigDigit, b: BigDigit, c: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
|
|
||||||
*acc += DoubleBigDigit::from(a);
|
|
||||||
*acc += DoubleBigDigit::from(b) * DoubleBigDigit::from(c);
|
|
||||||
let lo = *acc as BigDigit;
|
|
||||||
*acc >>= big_digit::BITS;
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mul_with_carry(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
|
|
||||||
*acc += DoubleBigDigit::from(a) * DoubleBigDigit::from(b);
|
|
||||||
let lo = *acc as BigDigit;
|
|
||||||
*acc >>= big_digit::BITS;
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Divide a two digit numerator by a one digit divisor, returns quotient and remainder:
|
|
||||||
///
|
|
||||||
/// Note: the caller must ensure that both the quotient and remainder will fit into a single digit.
|
|
||||||
/// This is _not_ true for an arbitrary numerator/denominator.
|
|
||||||
///
|
|
||||||
/// (This function also matches what the x86 divide instruction does).
|
|
||||||
#[inline]
|
|
||||||
fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigit) {
|
|
||||||
debug_assert!(hi < divisor);
|
|
||||||
|
|
||||||
let lhs = big_digit::to_doublebigdigit(hi, lo);
|
|
||||||
let rhs = DoubleBigDigit::from(divisor);
|
|
||||||
((lhs / rhs) as BigDigit, (lhs % rhs) as BigDigit)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
|
|
||||||
let mut rem = 0;
|
|
||||||
|
|
||||||
for d in a.data.iter_mut().rev() {
|
|
||||||
let (q, r) = div_wide(rem, *d, b);
|
|
||||||
*d = q;
|
|
||||||
rem = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
(a.normalized(), rem)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
|
|
||||||
let mut rem: DoubleBigDigit = 0;
|
|
||||||
for &digit in a.data.iter().rev() {
|
|
||||||
rem = (rem << big_digit::BITS) + DoubleBigDigit::from(digit);
|
|
||||||
rem %= DoubleBigDigit::from(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
rem as BigDigit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only for the Add impl:
|
|
||||||
#[inline]
|
|
||||||
pub fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
|
||||||
debug_assert!(a.len() >= b.len());
|
|
||||||
|
|
||||||
let mut carry = 0;
|
|
||||||
let (a_lo, a_hi) = a.split_at_mut(b.len());
|
|
||||||
|
|
||||||
for (a, b) in a_lo.iter_mut().zip(b) {
|
|
||||||
*a = adc(*a, *b, &mut carry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if carry != 0 {
|
|
||||||
for a in a_hi {
|
|
||||||
*a = adc(*a, 0, &mut carry);
|
|
||||||
if carry == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
carry as BigDigit
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Two argument addition of raw slices:
|
|
||||||
/// a += b
|
|
||||||
///
|
|
||||||
/// The caller _must_ ensure that a is big enough to store the result - typically this means
|
|
||||||
/// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry.
|
|
||||||
pub fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
|
|
||||||
let carry = __add2(a, b);
|
|
||||||
|
|
||||||
debug_assert!(carry == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
|
||||||
let mut borrow = 0;
|
|
||||||
|
|
||||||
let len = cmp::min(a.len(), b.len());
|
|
||||||
let (a_lo, a_hi) = a.split_at_mut(len);
|
|
||||||
let (b_lo, b_hi) = b.split_at(len);
|
|
||||||
|
|
||||||
for (a, b) in a_lo.iter_mut().zip(b_lo) {
|
|
||||||
*a = sbb(*a, *b, &mut borrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if borrow != 0 {
|
|
||||||
for a in a_hi {
|
|
||||||
*a = sbb(*a, 0, &mut borrow);
|
|
||||||
if borrow == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: we're _required_ to fail on underflow
|
|
||||||
assert!(
|
|
||||||
borrow == 0 && b_hi.iter().all(|x| *x == 0),
|
|
||||||
"Cannot subtract b from a because b is larger than a."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only for the Sub impl. `a` and `b` must have same length.
|
|
||||||
#[inline]
|
|
||||||
pub fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> BigDigit {
|
|
||||||
debug_assert!(b.len() == a.len());
|
|
||||||
|
|
||||||
let mut borrow = 0;
|
|
||||||
|
|
||||||
for (ai, bi) in a.iter().zip(b) {
|
|
||||||
*bi = sbb(*ai, *bi, &mut borrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
borrow as BigDigit
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
|
|
||||||
debug_assert!(b.len() >= a.len());
|
|
||||||
|
|
||||||
let len = cmp::min(a.len(), b.len());
|
|
||||||
let (a_lo, a_hi) = a.split_at(len);
|
|
||||||
let (b_lo, b_hi) = b.split_at_mut(len);
|
|
||||||
|
|
||||||
let borrow = __sub2rev(a_lo, b_lo);
|
|
||||||
|
|
||||||
assert!(a_hi.is_empty());
|
|
||||||
|
|
||||||
// note: we're _required_ to fail on underflow
|
|
||||||
assert!(
|
|
||||||
borrow == 0 && b_hi.iter().all(|x| *x == 0),
|
|
||||||
"Cannot subtract b from a because b is larger than a."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
|
||||||
// Normalize:
|
|
||||||
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
|
||||||
let b = &b[..b.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
|
||||||
|
|
||||||
match cmp_slice(a, b) {
|
|
||||||
Greater => {
|
|
||||||
let mut a = a.to_vec();
|
|
||||||
sub2(&mut a, b);
|
|
||||||
(Plus, BigUint::new(a))
|
|
||||||
}
|
|
||||||
Less => {
|
|
||||||
let mut b = b.to_vec();
|
|
||||||
sub2(&mut b, a);
|
|
||||||
(Minus, BigUint::new(b))
|
|
||||||
}
|
|
||||||
_ => (NoSign, Zero::zero()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Three argument multiply accumulate:
|
|
||||||
/// acc += b * c
|
|
||||||
pub fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
|
|
||||||
if c == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut carry = 0;
|
|
||||||
let (a_lo, a_hi) = acc.split_at_mut(b.len());
|
|
||||||
|
|
||||||
for (a, &b) in a_lo.iter_mut().zip(b) {
|
|
||||||
*a = mac_with_carry(*a, b, c, &mut carry);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut a = a_hi.iter_mut();
|
|
||||||
while carry != 0 {
|
|
||||||
let a = a.next().expect("carry overflow during multiplication!");
|
|
||||||
*a = adc(*a, 0, &mut carry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Three argument multiply accumulate:
|
|
||||||
/// acc += b * c
|
|
||||||
fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|
||||||
let (x, y) = if b.len() < c.len() { (b, c) } else { (c, b) };
|
|
||||||
|
|
||||||
// We use three algorithms for different input sizes.
|
|
||||||
//
|
|
||||||
// - For small inputs, long multiplication is fastest.
|
|
||||||
// - Next we use Karatsuba multiplication (Toom-2), which we have optimized
|
|
||||||
// to avoid unnecessary allocations for intermediate values.
|
|
||||||
// - For the largest inputs we use Toom-3, which better optimizes the
|
|
||||||
// number of operations, but uses more temporary allocations.
|
|
||||||
//
|
|
||||||
// The thresholds are somewhat arbitrary, chosen by evaluating the results
|
|
||||||
// of `cargo bench --bench bigint multiply`.
|
|
||||||
|
|
||||||
if x.len() <= 32 {
|
|
||||||
// Long multiplication:
|
|
||||||
for (i, xi) in x.iter().enumerate() {
|
|
||||||
mac_digit(&mut acc[i..], y, *xi);
|
|
||||||
}
|
|
||||||
} else if x.len() <= 256 {
|
|
||||||
/*
|
|
||||||
* Karatsuba multiplication:
|
|
||||||
*
|
|
||||||
* The idea is that we break x and y up into two smaller numbers that each have about half
|
|
||||||
* as many digits, like so (note that multiplying by b is just a shift):
|
|
||||||
*
|
|
||||||
* x = x0 + x1 * b
|
|
||||||
* y = y0 + y1 * b
|
|
||||||
*
|
|
||||||
* With some algebra, we can compute x * y with three smaller products, where the inputs to
|
|
||||||
* each of the smaller products have only about half as many digits as x and y:
|
|
||||||
*
|
|
||||||
* x * y = (x0 + x1 * b) * (y0 + y1 * b)
|
|
||||||
*
|
|
||||||
* x * y = x0 * y0
|
|
||||||
* + x0 * y1 * b
|
|
||||||
* + x1 * y0 * b
|
|
||||||
* + x1 * y1 * b^2
|
|
||||||
*
|
|
||||||
* Let p0 = x0 * y0 and p2 = x1 * y1:
|
|
||||||
*
|
|
||||||
* x * y = p0
|
|
||||||
* + (x0 * y1 + x1 * y0) * b
|
|
||||||
* + p2 * b^2
|
|
||||||
*
|
|
||||||
* The real trick is that middle term:
|
|
||||||
*
|
|
||||||
* x0 * y1 + x1 * y0
|
|
||||||
*
|
|
||||||
* = x0 * y1 + x1 * y0 - p0 + p0 - p2 + p2
|
|
||||||
*
|
|
||||||
* = x0 * y1 + x1 * y0 - x0 * y0 - x1 * y1 + p0 + p2
|
|
||||||
*
|
|
||||||
* Now we complete the square:
|
|
||||||
*
|
|
||||||
* = -(x0 * y0 - x0 * y1 - x1 * y0 + x1 * y1) + p0 + p2
|
|
||||||
*
|
|
||||||
* = -((x1 - x0) * (y1 - y0)) + p0 + p2
|
|
||||||
*
|
|
||||||
* Let p1 = (x1 - x0) * (y1 - y0), and substitute back into our original formula:
|
|
||||||
*
|
|
||||||
* x * y = p0
|
|
||||||
* + (p0 + p2 - p1) * b
|
|
||||||
* + p2 * b^2
|
|
||||||
*
|
|
||||||
* Where the three intermediate products are:
|
|
||||||
*
|
|
||||||
* p0 = x0 * y0
|
|
||||||
* p1 = (x1 - x0) * (y1 - y0)
|
|
||||||
* p2 = x1 * y1
|
|
||||||
*
|
|
||||||
* In doing the computation, we take great care to avoid unnecessary temporary variables
|
|
||||||
* (since creating a BigUint requires a heap allocation): thus, we rearrange the formula a
|
|
||||||
* bit so we can use the same temporary variable for all the intermediate products:
|
|
||||||
*
|
|
||||||
* x * y = p2 * b^2 + p2 * b
|
|
||||||
* + p0 * b + p0
|
|
||||||
* - p1 * b
|
|
||||||
*
|
|
||||||
* The other trick we use is instead of doing explicit shifts, we slice acc at the
|
|
||||||
* appropriate offset when doing the add.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When x is smaller than y, it's significantly faster to pick b such that x is split in
|
|
||||||
* half, not y:
|
|
||||||
*/
|
|
||||||
let b = x.len() / 2;
|
|
||||||
let (x0, x1) = x.split_at(b);
|
|
||||||
let (y0, y1) = y.split_at(b);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We reuse the same BigUint for all the intermediate multiplies and have to size p
|
|
||||||
* appropriately here: x1.len() >= x0.len and y1.len() >= y0.len():
|
|
||||||
*/
|
|
||||||
let len = x1.len() + y1.len() + 1;
|
|
||||||
let mut p = BigUint { data: vec![0; len] };
|
|
||||||
|
|
||||||
// p2 = x1 * y1
|
|
||||||
mac3(&mut p.data[..], x1, y1);
|
|
||||||
|
|
||||||
// Not required, but the adds go faster if we drop any unneeded 0s from the end:
|
|
||||||
p.normalize();
|
|
||||||
|
|
||||||
add2(&mut acc[b..], &p.data[..]);
|
|
||||||
add2(&mut acc[b * 2..], &p.data[..]);
|
|
||||||
|
|
||||||
// Zero out p before the next multiply:
|
|
||||||
p.data.truncate(0);
|
|
||||||
p.data.extend(repeat(0).take(len));
|
|
||||||
|
|
||||||
// p0 = x0 * y0
|
|
||||||
mac3(&mut p.data[..], x0, y0);
|
|
||||||
p.normalize();
|
|
||||||
|
|
||||||
add2(&mut acc[..], &p.data[..]);
|
|
||||||
add2(&mut acc[b..], &p.data[..]);
|
|
||||||
|
|
||||||
// p1 = (x1 - x0) * (y1 - y0)
|
|
||||||
// We do this one last, since it may be negative and acc can't ever be negative:
|
|
||||||
let (j0_sign, j0) = sub_sign(x1, x0);
|
|
||||||
let (j1_sign, j1) = sub_sign(y1, y0);
|
|
||||||
|
|
||||||
match j0_sign * j1_sign {
|
|
||||||
Plus => {
|
|
||||||
p.data.truncate(0);
|
|
||||||
p.data.extend(repeat(0).take(len));
|
|
||||||
|
|
||||||
mac3(&mut p.data[..], &j0.data[..], &j1.data[..]);
|
|
||||||
p.normalize();
|
|
||||||
|
|
||||||
sub2(&mut acc[b..], &p.data[..]);
|
|
||||||
}
|
|
||||||
Minus => {
|
|
||||||
mac3(&mut acc[b..], &j0.data[..], &j1.data[..]);
|
|
||||||
}
|
|
||||||
NoSign => (),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Toom-3 multiplication:
|
|
||||||
//
|
|
||||||
// Toom-3 is like Karatsuba above, but dividing the inputs into three parts.
|
|
||||||
// Both are instances of Toom-Cook, using `k=3` and `k=2` respectively.
|
|
||||||
//
|
|
||||||
// The general idea is to treat the large integers digits as
|
|
||||||
// polynomials of a certain degree and determine the coefficients/digits
|
|
||||||
// of the product of the two via interpolation of the polynomial product.
|
|
||||||
let i = y.len() / 3 + 1;
|
|
||||||
|
|
||||||
let x0_len = cmp::min(x.len(), i);
|
|
||||||
let x1_len = cmp::min(x.len() - x0_len, i);
|
|
||||||
|
|
||||||
let y0_len = i;
|
|
||||||
let y1_len = cmp::min(y.len() - y0_len, i);
|
|
||||||
|
|
||||||
// Break x and y into three parts, representating an order two polynomial.
|
|
||||||
// t is chosen to be the size of a digit so we can use faster shifts
|
|
||||||
// in place of multiplications.
|
|
||||||
//
|
|
||||||
// x(t) = x2*t^2 + x1*t + x0
|
|
||||||
let x0 = BigInt::from_slice(Plus, &x[..x0_len]);
|
|
||||||
let x1 = BigInt::from_slice(Plus, &x[x0_len..x0_len + x1_len]);
|
|
||||||
let x2 = BigInt::from_slice(Plus, &x[x0_len + x1_len..]);
|
|
||||||
|
|
||||||
// y(t) = y2*t^2 + y1*t + y0
|
|
||||||
let y0 = BigInt::from_slice(Plus, &y[..y0_len]);
|
|
||||||
let y1 = BigInt::from_slice(Plus, &y[y0_len..y0_len + y1_len]);
|
|
||||||
let y2 = BigInt::from_slice(Plus, &y[y0_len + y1_len..]);
|
|
||||||
|
|
||||||
// Let w(t) = x(t) * y(t)
|
|
||||||
//
|
|
||||||
// This gives us the following order-4 polynomial.
|
|
||||||
//
|
|
||||||
// w(t) = w4*t^4 + w3*t^3 + w2*t^2 + w1*t + w0
|
|
||||||
//
|
|
||||||
// We need to find the coefficients w4, w3, w2, w1 and w0. Instead
|
|
||||||
// of simply multiplying the x and y in total, we can evaluate w
|
|
||||||
// at 5 points. An n-degree polynomial is uniquely identified by (n + 1)
|
|
||||||
// points.
|
|
||||||
//
|
|
||||||
// It is arbitrary as to what points we evaluate w at but we use the
|
|
||||||
// following.
|
|
||||||
//
|
|
||||||
// w(t) at t = 0, 1, -1, -2 and inf
|
|
||||||
//
|
|
||||||
// The values for w(t) in terms of x(t)*y(t) at these points are:
|
|
||||||
//
|
|
||||||
// let a = w(0) = x0 * y0
|
|
||||||
// let b = w(1) = (x2 + x1 + x0) * (y2 + y1 + y0)
|
|
||||||
// let c = w(-1) = (x2 - x1 + x0) * (y2 - y1 + y0)
|
|
||||||
// let d = w(-2) = (4*x2 - 2*x1 + x0) * (4*y2 - 2*y1 + y0)
|
|
||||||
// let e = w(inf) = x2 * y2 as t -> inf
|
|
||||||
|
|
||||||
// x0 + x2, avoiding temporaries
|
|
||||||
let p = &x0 + &x2;
|
|
||||||
|
|
||||||
// y0 + y2, avoiding temporaries
|
|
||||||
let q = &y0 + &y2;
|
|
||||||
|
|
||||||
// x2 - x1 + x0, avoiding temporaries
|
|
||||||
let p2 = &p - &x1;
|
|
||||||
|
|
||||||
// y2 - y1 + y0, avoiding temporaries
|
|
||||||
let q2 = &q - &y1;
|
|
||||||
|
|
||||||
// w(0)
|
|
||||||
let r0 = &x0 * &y0;
|
|
||||||
|
|
||||||
// w(inf)
|
|
||||||
let r4 = &x2 * &y2;
|
|
||||||
|
|
||||||
// w(1)
|
|
||||||
let r1 = (p + x1) * (q + y1);
|
|
||||||
|
|
||||||
// w(-1)
|
|
||||||
let r2 = &p2 * &q2;
|
|
||||||
|
|
||||||
// w(-2)
|
|
||||||
let r3 = ((p2 + x2) * 2 - x0) * ((q2 + y2) * 2 - y0);
|
|
||||||
|
|
||||||
// Evaluating these points gives us the following system of linear equations.
|
|
||||||
//
|
|
||||||
// 0 0 0 0 1 | a
|
|
||||||
// 1 1 1 1 1 | b
|
|
||||||
// 1 -1 1 -1 1 | c
|
|
||||||
// 16 -8 4 -2 1 | d
|
|
||||||
// 1 0 0 0 0 | e
|
|
||||||
//
|
|
||||||
// The solved equation (after gaussian elimination or similar)
|
|
||||||
// in terms of its coefficients:
|
|
||||||
//
|
|
||||||
// w0 = w(0)
|
|
||||||
// w1 = w(0)/2 + w(1)/3 - w(-1) + w(2)/6 - 2*w(inf)
|
|
||||||
// w2 = -w(0) + w(1)/2 + w(-1)/2 - w(inf)
|
|
||||||
// w3 = -w(0)/2 + w(1)/6 + w(-1)/2 - w(1)/6
|
|
||||||
// w4 = w(inf)
|
|
||||||
//
|
|
||||||
// This particular sequence is given by Bodrato and is an interpolation
|
|
||||||
// of the above equations.
|
|
||||||
let mut comp3: BigInt = (r3 - &r1) / 3;
|
|
||||||
let mut comp1: BigInt = (r1 - &r2) / 2;
|
|
||||||
let mut comp2: BigInt = r2 - &r0;
|
|
||||||
comp3 = (&comp2 - comp3) / 2 + &r4 * 2;
|
|
||||||
comp2 = comp2 + &comp1 - &r4;
|
|
||||||
comp1 = comp1 - &comp3;
|
|
||||||
|
|
||||||
// Recomposition. The coefficients of the polynomial are now known.
|
|
||||||
//
|
|
||||||
// Evaluate at w(t) where t is our given base to get the result.
|
|
||||||
let result = r0
|
|
||||||
+ (comp1 << 32 * i)
|
|
||||||
+ (comp2 << 2 * 32 * i)
|
|
||||||
+ (comp3 << 3 * 32 * i)
|
|
||||||
+ (r4 << 4 * 32 * i);
|
|
||||||
let result_pos = result.to_biguint().unwrap();
|
|
||||||
add2(&mut acc[..], &result_pos.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
|
||||||
let len = x.len() + y.len() + 1;
|
|
||||||
let mut prod = BigUint { data: vec![0; len] };
|
|
||||||
|
|
||||||
mac3(&mut prod.data[..], x, y);
|
|
||||||
prod.normalized()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
|
|
||||||
let mut carry = 0;
|
|
||||||
for a in a.iter_mut() {
|
|
||||||
*a = mul_with_carry(*a, b, &mut carry);
|
|
||||||
}
|
|
||||||
carry as BigDigit
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn div_rem(mut u: BigUint, mut d: BigUint) -> (BigUint, BigUint) {
|
|
||||||
if d.is_zero() {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
if u.is_zero() {
|
|
||||||
return (Zero::zero(), Zero::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.data.len() == 1 {
|
|
||||||
if d.data == [1] {
|
|
||||||
return (u, Zero::zero());
|
|
||||||
}
|
|
||||||
let (div, rem) = div_rem_digit(u, d.data[0]);
|
|
||||||
// reuse d
|
|
||||||
d.data.clear();
|
|
||||||
d += rem;
|
|
||||||
return (div, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required or the q_len calculation below can underflow:
|
|
||||||
match u.cmp(&d) {
|
|
||||||
Less => return (Zero::zero(), u),
|
|
||||||
Equal => {
|
|
||||||
u.set_one();
|
|
||||||
return (u, Zero::zero());
|
|
||||||
}
|
|
||||||
Greater => {} // Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// This algorithm is from Knuth, TAOCP vol 2 section 4.3, algorithm D:
|
|
||||||
//
|
|
||||||
// First, normalize the arguments so the highest bit in the highest digit of the divisor is
|
|
||||||
// set: the main loop uses the highest digit of the divisor for generating guesses, so we
|
|
||||||
// want it to be the largest number we can efficiently divide by.
|
|
||||||
//
|
|
||||||
let shift = d.data.last().unwrap().leading_zeros() as usize;
|
|
||||||
let (q, r) = if shift == 0 {
|
|
||||||
// no need to clone d
|
|
||||||
div_rem_core(u, &d)
|
|
||||||
} else {
|
|
||||||
div_rem_core(u << shift, &(d << shift))
|
|
||||||
};
|
|
||||||
// renormalize the remainder
|
|
||||||
(q, r >> shift)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn div_rem_ref(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
|
||||||
if d.is_zero() {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
if u.is_zero() {
|
|
||||||
return (Zero::zero(), Zero::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.data.len() == 1 {
|
|
||||||
if d.data == [1] {
|
|
||||||
return (u.clone(), Zero::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (div, rem) = div_rem_digit(u.clone(), d.data[0]);
|
|
||||||
return (div, rem.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required or the q_len calculation below can underflow:
|
|
||||||
match u.cmp(d) {
|
|
||||||
Less => return (Zero::zero(), u.clone()),
|
|
||||||
Equal => return (One::one(), Zero::zero()),
|
|
||||||
Greater => {} // Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// This algorithm is from Knuth, TAOCP vol 2 section 4.3, algorithm D:
|
|
||||||
//
|
|
||||||
// First, normalize the arguments so the highest bit in the highest digit of the divisor is
|
|
||||||
// set: the main loop uses the highest digit of the divisor for generating guesses, so we
|
|
||||||
// want it to be the largest number we can efficiently divide by.
|
|
||||||
//
|
|
||||||
let shift = d.data.last().unwrap().leading_zeros() as usize;
|
|
||||||
|
|
||||||
let (q, r) = if shift == 0 {
|
|
||||||
// no need to clone d
|
|
||||||
div_rem_core(u.clone(), d)
|
|
||||||
} else {
|
|
||||||
div_rem_core(u << shift, &(d << shift))
|
|
||||||
};
|
|
||||||
// renormalize the remainder
|
|
||||||
(q, r >> shift)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// an implementation of Knuth, TAOCP vol 2 section 4.3, algorithm D
|
|
||||||
///
|
|
||||||
/// # Correctness
|
|
||||||
///
|
|
||||||
/// This function requires the following conditions to run correctly and/or effectively
|
|
||||||
///
|
|
||||||
/// - `a > b`
|
|
||||||
/// - `d.data.len() > 1`
|
|
||||||
/// - `d.data.last().unwrap().leading_zeros() == 0`
|
|
||||||
fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
|
|
||||||
// The algorithm works by incrementally calculating "guesses", q0, for part of the
|
|
||||||
// remainder. Once we have any number q0 such that q0 * b <= a, we can set
|
|
||||||
//
|
|
||||||
// q += q0
|
|
||||||
// a -= q0 * b
|
|
||||||
//
|
|
||||||
// and then iterate until a < b. Then, (q, a) will be our desired quotient and remainder.
|
|
||||||
//
|
|
||||||
// q0, our guess, is calculated by dividing the last few digits of a by the last digit of b
|
|
||||||
// - this should give us a guess that is "close" to the actual quotient, but is possibly
|
|
||||||
// greater than the actual quotient. If q0 * b > a, we simply use iterated subtraction
|
|
||||||
// until we have a guess such that q0 * b <= a.
|
|
||||||
//
|
|
||||||
|
|
||||||
let bn = *b.data.last().unwrap();
|
|
||||||
let q_len = a.data.len() - b.data.len() + 1;
|
|
||||||
let mut q = BigUint {
|
|
||||||
data: vec![0; q_len],
|
|
||||||
};
|
|
||||||
|
|
||||||
// We reuse the same temporary to avoid hitting the allocator in our inner loop - this is
|
|
||||||
// sized to hold a0 (in the common case; if a particular digit of the quotient is zero a0
|
|
||||||
// can be bigger).
|
|
||||||
//
|
|
||||||
let mut tmp = BigUint {
|
|
||||||
data: Vec::with_capacity(2),
|
|
||||||
};
|
|
||||||
|
|
||||||
for j in (0..q_len).rev() {
|
|
||||||
/*
|
|
||||||
* When calculating our next guess q0, we don't need to consider the digits below j
|
|
||||||
* + b.data.len() - 1: we're guessing digit j of the quotient (i.e. q0 << j) from
|
|
||||||
* digit bn of the divisor (i.e. bn << (b.data.len() - 1) - so the product of those
|
|
||||||
* two numbers will be zero in all digits up to (j + b.data.len() - 1).
|
|
||||||
*/
|
|
||||||
let offset = j + b.data.len() - 1;
|
|
||||||
if offset >= a.data.len() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* just avoiding a heap allocation: */
|
|
||||||
let mut a0 = tmp;
|
|
||||||
a0.data.truncate(0);
|
|
||||||
a0.data.extend(a.data[offset..].iter().cloned());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* q0 << j * big_digit::BITS is our actual quotient estimate - we do the shifts
|
|
||||||
* implicitly at the end, when adding and subtracting to a and q. Not only do we
|
|
||||||
* save the cost of the shifts, the rest of the arithmetic gets to work with
|
|
||||||
* smaller numbers.
|
|
||||||
*/
|
|
||||||
let (mut q0, _) = div_rem_digit(a0, bn);
|
|
||||||
let mut prod = b * &q0;
|
|
||||||
|
|
||||||
while cmp_slice(&prod.data[..], &a.data[j..]) == Greater {
|
|
||||||
let one: BigUint = One::one();
|
|
||||||
q0 = q0 - one;
|
|
||||||
prod = prod - b;
|
|
||||||
}
|
|
||||||
|
|
||||||
add2(&mut q.data[j..], &q0.data[..]);
|
|
||||||
sub2(&mut a.data[j..], &prod.data[..]);
|
|
||||||
a.normalize();
|
|
||||||
|
|
||||||
tmp = q0;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert!(&a < b);
|
|
||||||
|
|
||||||
(q.normalized(), a)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find last set bit
|
|
||||||
/// fls(0) == 0, fls(u32::MAX) == 32
|
|
||||||
pub fn fls<T: traits::PrimInt>(v: T) -> usize {
|
|
||||||
mem::size_of::<T>() * 8 - v.leading_zeros() as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ilog2<T: traits::PrimInt>(v: T) -> usize {
|
|
||||||
fls(v) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn biguint_shl(n: Cow<BigUint>, bits: usize) -> BigUint {
|
|
||||||
let n_unit = bits / big_digit::BITS;
|
|
||||||
let mut data = match n_unit {
|
|
||||||
0 => n.into_owned().data,
|
|
||||||
_ => {
|
|
||||||
let len = n_unit + n.data.len() + 1;
|
|
||||||
let mut data = Vec::with_capacity(len);
|
|
||||||
data.extend(repeat(0).take(n_unit));
|
|
||||||
data.extend(n.data.iter().cloned());
|
|
||||||
data
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let n_bits = bits % big_digit::BITS;
|
|
||||||
if n_bits > 0 {
|
|
||||||
let mut carry = 0;
|
|
||||||
for elem in data[n_unit..].iter_mut() {
|
|
||||||
let new_carry = *elem >> (big_digit::BITS - n_bits);
|
|
||||||
*elem = (*elem << n_bits) | carry;
|
|
||||||
carry = new_carry;
|
|
||||||
}
|
|
||||||
if carry != 0 {
|
|
||||||
data.push(carry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BigUint::new(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn biguint_shr(n: Cow<BigUint>, bits: usize) -> BigUint {
|
|
||||||
let n_unit = bits / big_digit::BITS;
|
|
||||||
if n_unit >= n.data.len() {
|
|
||||||
return Zero::zero();
|
|
||||||
}
|
|
||||||
let mut data = match n {
|
|
||||||
Cow::Borrowed(n) => n.data[n_unit..].to_vec(),
|
|
||||||
Cow::Owned(mut n) => {
|
|
||||||
n.data.drain(..n_unit);
|
|
||||||
n.data
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let n_bits = bits % big_digit::BITS;
|
|
||||||
if n_bits > 0 {
|
|
||||||
let mut borrow = 0;
|
|
||||||
for elem in data.iter_mut().rev() {
|
|
||||||
let new_borrow = *elem << (big_digit::BITS - n_bits);
|
|
||||||
*elem = (*elem >> n_bits) | borrow;
|
|
||||||
borrow = new_borrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BigUint::new(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
|
|
||||||
debug_assert!(a.last() != Some(&0));
|
|
||||||
debug_assert!(b.last() != Some(&0));
|
|
||||||
|
|
||||||
let (a_len, b_len) = (a.len(), b.len());
|
|
||||||
if a_len < b_len {
|
|
||||||
return Less;
|
|
||||||
}
|
|
||||||
if a_len > b_len {
|
|
||||||
return Greater;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (&ai, &bi) in a.iter().rev().zip(b.iter().rev()) {
|
|
||||||
if ai < bi {
|
|
||||||
return Less;
|
|
||||||
}
|
|
||||||
if ai > bi {
|
|
||||||
return Greater;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Equal;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod algorithm_tests {
|
|
||||||
use big_digit::BigDigit;
|
|
||||||
use traits::Num;
|
|
||||||
use Sign::Plus;
|
|
||||||
use {BigInt, BigUint};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sub_sign() {
|
|
||||||
use super::sub_sign;
|
|
||||||
|
|
||||||
fn sub_sign_i(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
|
|
||||||
let (sign, val) = sub_sign(a, b);
|
|
||||||
BigInt::from_biguint(sign, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap();
|
|
||||||
let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap();
|
|
||||||
let a_i = BigInt::from_biguint(Plus, a.clone());
|
|
||||||
let b_i = BigInt::from_biguint(Plus, b.clone());
|
|
||||||
|
|
||||||
assert_eq!(sub_sign_i(&a.data[..], &b.data[..]), &a_i - &b_i);
|
|
||||||
assert_eq!(sub_sign_i(&b.data[..], &a.data[..]), &b_i - &a_i);
|
|
||||||
}
|
|
||||||
}
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,218 +0,0 @@
|
||||||
//! Randomization of big integers
|
|
||||||
|
|
||||||
use rand::distributions::uniform::{SampleUniform, UniformSampler};
|
|
||||||
use rand::prelude::*;
|
|
||||||
use rand::AsByteSliceMut;
|
|
||||||
|
|
||||||
use BigInt;
|
|
||||||
use BigUint;
|
|
||||||
use Sign::*;
|
|
||||||
|
|
||||||
use big_digit::BigDigit;
|
|
||||||
use bigint::{into_magnitude, magnitude};
|
|
||||||
|
|
||||||
use integer::Integer;
|
|
||||||
use traits::Zero;
|
|
||||||
|
|
||||||
pub trait RandBigInt {
|
|
||||||
/// Generate a random `BigUint` of the given bit size.
|
|
||||||
fn gen_biguint(&mut self, bit_size: usize) -> BigUint;
|
|
||||||
|
|
||||||
/// Generate a random BigInt of the given bit size.
|
|
||||||
fn gen_bigint(&mut self, bit_size: usize) -> BigInt;
|
|
||||||
|
|
||||||
/// Generate a random `BigUint` less than the given bound. Fails
|
|
||||||
/// when the bound is zero.
|
|
||||||
fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;
|
|
||||||
|
|
||||||
/// Generate a random `BigUint` within the given range. The lower
|
|
||||||
/// bound is inclusive; the upper bound is exclusive. Fails when
|
|
||||||
/// the upper bound is not greater than the lower bound.
|
|
||||||
fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;
|
|
||||||
|
|
||||||
/// Generate a random `BigInt` within the given range. The lower
|
|
||||||
/// bound is inclusive; the upper bound is exclusive. Fails when
|
|
||||||
/// the upper bound is not greater than the lower bound.
|
|
||||||
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Rng + ?Sized> RandBigInt for R {
|
|
||||||
fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
|
|
||||||
use super::big_digit::BITS;
|
|
||||||
let (digits, rem) = bit_size.div_rem(&BITS);
|
|
||||||
let mut data = vec![BigDigit::default(); digits + (rem > 0) as usize];
|
|
||||||
// `fill_bytes` is faster than many `gen::<u32>` calls
|
|
||||||
self.fill_bytes(data[..].as_byte_slice_mut());
|
|
||||||
// Swap bytes per the `Rng::fill` source. This might be
|
|
||||||
// unnecessary if reproducibility across architectures is not
|
|
||||||
// desired.
|
|
||||||
data.to_le();
|
|
||||||
if rem > 0 {
|
|
||||||
data[digits] >>= BITS - rem;
|
|
||||||
}
|
|
||||||
BigUint::new(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
|
|
||||||
loop {
|
|
||||||
// Generate a random BigUint...
|
|
||||||
let biguint = self.gen_biguint(bit_size);
|
|
||||||
// ...and then randomly assign it a Sign...
|
|
||||||
let sign = if biguint.is_zero() {
|
|
||||||
// ...except that if the BigUint is zero, we need to try
|
|
||||||
// again with probability 0.5. This is because otherwise,
|
|
||||||
// the probability of generating a zero BigInt would be
|
|
||||||
// double that of any other number.
|
|
||||||
if self.gen() {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
NoSign
|
|
||||||
}
|
|
||||||
} else if self.gen() {
|
|
||||||
Plus
|
|
||||||
} else {
|
|
||||||
Minus
|
|
||||||
};
|
|
||||||
return BigInt::from_biguint(sign, biguint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
|
|
||||||
assert!(!bound.is_zero());
|
|
||||||
let bits = bound.bits();
|
|
||||||
loop {
|
|
||||||
let n = self.gen_biguint(bits);
|
|
||||||
if n < *bound {
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint {
|
|
||||||
assert!(*lbound < *ubound);
|
|
||||||
if lbound.is_zero() {
|
|
||||||
self.gen_biguint_below(ubound)
|
|
||||||
} else {
|
|
||||||
lbound + self.gen_biguint_below(&(ubound - lbound))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt {
|
|
||||||
assert!(*lbound < *ubound);
|
|
||||||
if lbound.is_zero() {
|
|
||||||
BigInt::from(self.gen_biguint_below(magnitude(&ubound)))
|
|
||||||
} else if ubound.is_zero() {
|
|
||||||
lbound + BigInt::from(self.gen_biguint_below(magnitude(&lbound)))
|
|
||||||
} else {
|
|
||||||
let delta = ubound - lbound;
|
|
||||||
lbound + BigInt::from(self.gen_biguint_below(magnitude(&delta)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The back-end implementing rand's `UniformSampler` for `BigUint`.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct UniformBigUint {
|
|
||||||
base: BigUint,
|
|
||||||
len: BigUint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UniformSampler for UniformBigUint {
|
|
||||||
type X = BigUint;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn new(low: Self::X, high: Self::X) -> Self {
|
|
||||||
assert!(low < high);
|
|
||||||
UniformBigUint {
|
|
||||||
len: high - &low,
|
|
||||||
base: low,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
|
|
||||||
assert!(low <= high);
|
|
||||||
Self::new(low, high + 1u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
|
|
||||||
&self.base + rng.gen_biguint_below(&self.len)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
|
|
||||||
rng.gen_biguint_range(&low, &high)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SampleUniform for BigUint {
|
|
||||||
type Sampler = UniformBigUint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The back-end implementing rand's `UniformSampler` for `BigInt`.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct UniformBigInt {
|
|
||||||
base: BigInt,
|
|
||||||
len: BigUint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UniformSampler for UniformBigInt {
|
|
||||||
type X = BigInt;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn new(low: Self::X, high: Self::X) -> Self {
|
|
||||||
assert!(low < high);
|
|
||||||
UniformBigInt {
|
|
||||||
len: into_magnitude(high - &low),
|
|
||||||
base: low,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
|
|
||||||
assert!(low <= high);
|
|
||||||
Self::new(low, high + 1u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
|
|
||||||
&self.base + BigInt::from(rng.gen_biguint_below(&self.len))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
|
|
||||||
rng.gen_bigint_range(&low, &high)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SampleUniform for BigInt {
|
|
||||||
type Sampler = UniformBigInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A random distribution for `BigUint` and `BigInt` values of a particular bit size.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct RandomBits {
|
|
||||||
bits: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RandomBits {
|
|
||||||
#[inline]
|
|
||||||
pub fn new(bits: usize) -> RandomBits {
|
|
||||||
RandomBits { bits }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Distribution<BigUint> for RandomBits {
|
|
||||||
#[inline]
|
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigUint {
|
|
||||||
rng.gen_biguint(self.bits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Distribution<BigInt> for RandomBits {
|
|
||||||
#[inline]
|
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BigInt {
|
|
||||||
rng.gen_bigint(self.bits)
|
|
||||||
}
|
|
||||||
}
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,206 +0,0 @@
|
||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
//! A Big integer (signed version: `BigInt`, unsigned version: `BigUint`).
|
|
||||||
//!
|
|
||||||
//! A `BigUint` is represented as a vector of `BigDigit`s.
|
|
||||||
//! A `BigInt` is a combination of `BigUint` and `Sign`.
|
|
||||||
//!
|
|
||||||
//! Common numerical operations are overloaded, so we can treat them
|
|
||||||
//! the same way we treat other numbers.
|
|
||||||
//!
|
|
||||||
//! ## Example
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! extern crate num_bigint;
|
|
||||||
//! extern crate num_traits;
|
|
||||||
//!
|
|
||||||
//! # fn main() {
|
|
||||||
//! use num_bigint::BigUint;
|
|
||||||
//! use num_traits::{Zero, One};
|
|
||||||
//! use std::mem::replace;
|
|
||||||
//!
|
|
||||||
//! // Calculate large fibonacci numbers.
|
|
||||||
//! fn fib(n: usize) -> BigUint {
|
|
||||||
//! let mut f0: BigUint = Zero::zero();
|
|
||||||
//! let mut f1: BigUint = One::one();
|
|
||||||
//! for _ in 0..n {
|
|
||||||
//! let f2 = f0 + &f1;
|
|
||||||
//! // This is a low cost way of swapping f0 with f1 and f1 with f2.
|
|
||||||
//! f0 = replace(&mut f1, f2);
|
|
||||||
//! }
|
|
||||||
//! f0
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // This is a very large number.
|
|
||||||
//! println!("fib(1000) = {}", fib(1000));
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! It's easy to generate large random numbers:
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! # #[cfg(feature = "rand")]
|
|
||||||
//! extern crate rand;
|
|
||||||
//! extern crate num_bigint as bigint;
|
|
||||||
//!
|
|
||||||
//! # #[cfg(feature = "rand")]
|
|
||||||
//! # fn main() {
|
|
||||||
//! use bigint::{ToBigInt, RandBigInt};
|
|
||||||
//!
|
|
||||||
//! let mut rng = rand::thread_rng();
|
|
||||||
//! let a = rng.gen_bigint(1000);
|
|
||||||
//!
|
|
||||||
//! let low = -10000.to_bigint().unwrap();
|
|
||||||
//! let high = 10000.to_bigint().unwrap();
|
|
||||||
//! let b = rng.gen_bigint_range(&low, &high);
|
|
||||||
//!
|
|
||||||
//! // Probably an even larger number.
|
|
||||||
//! println!("{}", a * b);
|
|
||||||
//! # }
|
|
||||||
//!
|
|
||||||
//! # #[cfg(not(feature = "rand"))]
|
|
||||||
//! # fn main() {
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! ## Compatibility
|
|
||||||
//!
|
|
||||||
//! The `num-bigint` crate is tested for rustc 1.15 and greater.
|
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/num-bigint/0.2")]
|
|
||||||
// We don't actually support `no_std` yet, and probably won't until `alloc` is stable. We're just
|
|
||||||
// reserving this ability with the "std" feature now, and compilation will fail without.
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
|
||||||
|
|
||||||
#[cfg(feature = "rand")]
|
|
||||||
extern crate rand;
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
extern crate num_integer as integer;
|
|
||||||
extern crate num_traits as traits;
|
|
||||||
#[cfg(feature = "quickcheck")]
|
|
||||||
extern crate quickcheck;
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
mod bigint;
|
|
||||||
mod biguint;
|
|
||||||
|
|
||||||
#[cfg(feature = "rand")]
|
|
||||||
mod bigrand;
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
type UsizePromotion = u32;
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
type UsizePromotion = u64;
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
type IsizePromotion = i32;
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
type IsizePromotion = i64;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct ParseBigIntError {
|
|
||||||
kind: BigIntErrorKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
enum BigIntErrorKind {
|
|
||||||
Empty,
|
|
||||||
InvalidDigit,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParseBigIntError {
|
|
||||||
fn __description(&self) -> &str {
|
|
||||||
use BigIntErrorKind::*;
|
|
||||||
match self.kind {
|
|
||||||
Empty => "cannot parse integer from empty string",
|
|
||||||
InvalidDigit => "invalid digit found in string",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn empty() -> Self {
|
|
||||||
ParseBigIntError {
|
|
||||||
kind: BigIntErrorKind::Empty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invalid() -> Self {
|
|
||||||
ParseBigIntError {
|
|
||||||
kind: BigIntErrorKind::InvalidDigit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ParseBigIntError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.__description().fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for ParseBigIntError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
self.__description()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use biguint::BigUint;
|
|
||||||
pub use biguint::ToBigUint;
|
|
||||||
|
|
||||||
pub use bigint::BigInt;
|
|
||||||
pub use bigint::Sign;
|
|
||||||
pub use bigint::ToBigInt;
|
|
||||||
|
|
||||||
#[cfg(feature = "rand")]
|
|
||||||
pub use bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint};
|
|
||||||
|
|
||||||
mod big_digit {
|
|
||||||
/// A `BigDigit` is a `BigUint`'s composing element.
|
|
||||||
pub type BigDigit = u32;
|
|
||||||
|
|
||||||
/// A `DoubleBigDigit` is the internal type used to do the computations. Its
|
|
||||||
/// size is the double of the size of `BigDigit`.
|
|
||||||
pub type DoubleBigDigit = u64;
|
|
||||||
|
|
||||||
/// A `SignedDoubleBigDigit` is the signed version of `DoubleBigDigit`.
|
|
||||||
pub type SignedDoubleBigDigit = i64;
|
|
||||||
|
|
||||||
// `DoubleBigDigit` size dependent
|
|
||||||
pub const BITS: usize = 32;
|
|
||||||
|
|
||||||
const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_hi(n: DoubleBigDigit) -> BigDigit {
|
|
||||||
(n >> BITS) as BigDigit
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn get_lo(n: DoubleBigDigit) -> BigDigit {
|
|
||||||
(n & LO_MASK) as BigDigit
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Split one `DoubleBigDigit` into two `BigDigit`s.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
|
|
||||||
(get_hi(n), get_lo(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Join two `BigDigit`s into one `DoubleBigDigit`
|
|
||||||
#[inline]
|
|
||||||
pub fn to_doublebigdigit(hi: BigDigit, lo: BigDigit) -> DoubleBigDigit {
|
|
||||||
DoubleBigDigit::from(lo) | (DoubleBigDigit::from(hi) << BITS)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,445 +0,0 @@
|
||||||
#![allow(unknown_lints)] // older rustc doesn't know `unused_macros`
|
|
||||||
#![allow(unused_macros)]
|
|
||||||
|
|
||||||
macro_rules! forward_val_val_binop {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl $imp<$res> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
// forward to val-ref
|
|
||||||
$imp::$method(self, &other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_val_val_binop_commutative {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl $imp<$res> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
// forward to val-ref, with the larger capacity as val
|
|
||||||
if self.capacity() >= other.capacity() {
|
|
||||||
$imp::$method(self, &other)
|
|
||||||
} else {
|
|
||||||
$imp::$method(other, &self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_ref_val_binop {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl<'a> $imp<$res> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
// forward to ref-ref
|
|
||||||
$imp::$method(self, &other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_ref_val_binop_commutative {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl<'a> $imp<$res> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
// reverse, forward to val-ref
|
|
||||||
$imp::$method(other, self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_val_ref_binop {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl<'a> $imp<&'a $res> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$res) -> $res {
|
|
||||||
// forward to ref-ref
|
|
||||||
$imp::$method(&self, other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_ref_ref_binop {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl<'a, 'b> $imp<&'b $res> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$res) -> $res {
|
|
||||||
// forward to val-ref
|
|
||||||
$imp::$method(self.clone(), other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_ref_ref_binop_commutative {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl<'a, 'b> $imp<&'b $res> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$res) -> $res {
|
|
||||||
// forward to val-ref, choosing the larger to clone
|
|
||||||
if self.len() >= other.len() {
|
|
||||||
$imp::$method(self.clone(), other)
|
|
||||||
} else {
|
|
||||||
$imp::$method(other.clone(), self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_val_assign {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
impl $imp<$res> for $res {
|
|
||||||
#[inline]
|
|
||||||
fn $method(&mut self, other: $res) {
|
|
||||||
self.$method(&other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_val_assign_scalar {
|
|
||||||
(impl $imp:ident for $res:ty, $scalar:ty, $method:ident) => {
|
|
||||||
impl $imp<$res> for $scalar {
|
|
||||||
#[inline]
|
|
||||||
fn $method(&mut self, other: $res) {
|
|
||||||
self.$method(&other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// use this if val_val_binop is already implemented and the reversed order is required
|
|
||||||
macro_rules! forward_scalar_val_val_binop_commutative {
|
|
||||||
(impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => {
|
|
||||||
impl $imp<$res> for $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
$imp::$method(other, self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward scalar to ref-val, when reusing storage is not helpful
|
|
||||||
macro_rules! forward_scalar_val_val_binop_to_ref_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
impl $imp<$scalar> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $scalar) -> $res {
|
|
||||||
$imp::$method(&self, other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $imp<$res> for $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
$imp::$method(self, &other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_scalar_ref_ref_binop_to_ref_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
impl<'a, 'b> $imp<&'b $scalar> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$scalar) -> $res {
|
|
||||||
$imp::$method(self, *other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> $imp<&'a $res> for &'b $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$res) -> $res {
|
|
||||||
$imp::$method(*self, other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_scalar_val_ref_binop_to_ref_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
impl<'a> $imp<&'a $scalar> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$scalar) -> $res {
|
|
||||||
$imp::$method(&self, *other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> $imp<$res> for &'a $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
$imp::$method(*self, &other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_scalar_val_ref_binop_to_val_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
impl<'a> $imp<&'a $scalar> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$scalar) -> $res {
|
|
||||||
$imp::$method(self, *other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> $imp<$res> for &'a $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
$imp::$method(*self, other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_scalar_ref_val_binop_to_val_val {
|
|
||||||
(impl $imp:ident < $scalar:ty > for $res:ty, $method:ident) => {
|
|
||||||
impl<'a> $imp<$scalar> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $scalar) -> $res {
|
|
||||||
$imp::$method(self.clone(), other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> $imp<&'a $res> for $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$res) -> $res {
|
|
||||||
$imp::$method(self, other.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_scalar_ref_ref_binop_to_val_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
impl<'a, 'b> $imp<&'b $scalar> for &'a $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$scalar) -> $res {
|
|
||||||
$imp::$method(self.clone(), *other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> $imp<&'a $res> for &'b $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: &$res) -> $res {
|
|
||||||
$imp::$method(*self, other.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_scalars {
|
|
||||||
(impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
|
|
||||||
$(
|
|
||||||
forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
|
|
||||||
impl $imp<$scalar> for $res {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $scalar) -> $res {
|
|
||||||
$imp::$method(self, other as $promo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $imp<$res> for $scalar {
|
|
||||||
type Output = $res;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
|
||||||
#[inline]
|
|
||||||
fn $method(self, other: $res) -> $res {
|
|
||||||
$imp::$method(self as $promo, other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
macro_rules! promote_scalars_assign {
|
|
||||||
(impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
|
|
||||||
$(
|
|
||||||
impl $imp<$scalar> for $res {
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
|
||||||
#[inline]
|
|
||||||
fn $method(&mut self, other: $scalar) {
|
|
||||||
self.$method(other as $promo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_unsigned_scalars {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
promote_scalars!(impl $imp<u32> for $res, $method, u8, u16);
|
|
||||||
promote_scalars!(impl $imp<UsizePromotion> for $res, $method, usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_unsigned_scalars_assign {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
promote_scalars_assign!(impl $imp<u32> for $res, $method, u8, u16);
|
|
||||||
promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_signed_scalars {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
promote_scalars!(impl $imp<i32> for $res, $method, i8, i16);
|
|
||||||
promote_scalars!(impl $imp<IsizePromotion> for $res, $method, isize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_signed_scalars_assign {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
promote_scalars_assign!(impl $imp<i32> for $res, $method, i8, i16);
|
|
||||||
promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, isize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward everything to ref-ref, when reusing storage is not helpful
|
|
||||||
macro_rules! forward_all_binop_to_ref_ref {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
forward_val_val_binop!(impl $imp for $res, $method);
|
|
||||||
forward_val_ref_binop!(impl $imp for $res, $method);
|
|
||||||
forward_ref_val_binop!(impl $imp for $res, $method);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward everything to val-ref, so LHS storage can be reused
|
|
||||||
macro_rules! forward_all_binop_to_val_ref {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
forward_val_val_binop!(impl $imp for $res, $method);
|
|
||||||
forward_ref_val_binop!(impl $imp for $res, $method);
|
|
||||||
forward_ref_ref_binop!(impl $imp for $res, $method);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward everything to val-ref, commutatively, so either LHS or RHS storage can be reused
|
|
||||||
macro_rules! forward_all_binop_to_val_ref_commutative {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
forward_val_val_binop_commutative!(impl $imp for $res, $method);
|
|
||||||
forward_ref_val_binop_commutative!(impl $imp for $res, $method);
|
|
||||||
forward_ref_ref_binop_commutative!(impl $imp for $res, $method);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_all_scalar_binop_to_ref_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
forward_scalar_val_val_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
forward_scalar_val_ref_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
forward_scalar_ref_ref_binop_to_ref_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_all_scalar_binop_to_val_val {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
forward_scalar_val_ref_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
forward_scalar_ref_val_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
forward_scalar_ref_ref_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_all_scalar_binop_to_val_val_commutative {
|
|
||||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
|
||||||
forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method);
|
|
||||||
forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_all_scalars {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
promote_unsigned_scalars!(impl $imp for $res, $method);
|
|
||||||
promote_signed_scalars!(impl $imp for $res, $method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! promote_all_scalars_assign {
|
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
|
||||||
promote_unsigned_scalars_assign!(impl $imp for $res, $method);
|
|
||||||
promote_signed_scalars_assign!(impl $imp for $res, $method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_sum_iter_type {
|
|
||||||
($res:ty) => {
|
|
||||||
impl<T> Sum<T> for $res
|
|
||||||
where
|
|
||||||
$res: Add<T, Output = $res>,
|
|
||||||
{
|
|
||||||
fn sum<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: Iterator<Item = T>,
|
|
||||||
{
|
|
||||||
iter.fold(Zero::zero(), <$res>::add)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_product_iter_type {
|
|
||||||
($res:ty) => {
|
|
||||||
impl<T> Product<T> for $res
|
|
||||||
where
|
|
||||||
$res: Mul<T, Output = $res>,
|
|
||||||
{
|
|
||||||
fn product<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: Iterator<Item = T>,
|
|
||||||
{
|
|
||||||
iter.fold(One::one(), <$res>::mul)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
use integer::Integer;
|
|
||||||
use traits::Zero;
|
|
||||||
|
|
||||||
use biguint::BigUint;
|
|
||||||
|
|
||||||
struct MontyReducer<'a> {
|
|
||||||
n: &'a BigUint,
|
|
||||||
n0inv: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the modular inverse of `num`, using Extended GCD.
|
|
||||||
//
|
|
||||||
// Reference:
|
|
||||||
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 1.20
|
|
||||||
fn inv_mod_u32(num: u32) -> u32 {
|
|
||||||
// num needs to be relatively prime to 2**32 -- i.e. it must be odd.
|
|
||||||
assert!(num % 2 != 0);
|
|
||||||
|
|
||||||
let mut a: i64 = i64::from(num);
|
|
||||||
let mut b: i64 = i64::from(u32::max_value()) + 1;
|
|
||||||
|
|
||||||
// ExtendedGcd
|
|
||||||
// Input: positive integers a and b
|
|
||||||
// Output: integers (g, u, v) such that g = gcd(a, b) = ua + vb
|
|
||||||
// As we don't need v for modular inverse, we don't calculate it.
|
|
||||||
|
|
||||||
// 1: (u, w) <- (1, 0)
|
|
||||||
let mut u = 1;
|
|
||||||
let mut w = 0;
|
|
||||||
// 3: while b != 0
|
|
||||||
while b != 0 {
|
|
||||||
// 4: (q, r) <- DivRem(a, b)
|
|
||||||
let q = a / b;
|
|
||||||
let r = a % b;
|
|
||||||
// 5: (a, b) <- (b, r)
|
|
||||||
a = b;
|
|
||||||
b = r;
|
|
||||||
// 6: (u, w) <- (w, u - qw)
|
|
||||||
let m = u - w * q;
|
|
||||||
u = w;
|
|
||||||
w = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(a == 1);
|
|
||||||
// Downcasting acts like a mod 2^32 too.
|
|
||||||
u as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> MontyReducer<'a> {
|
|
||||||
fn new(n: &'a BigUint) -> Self {
|
|
||||||
let n0inv = inv_mod_u32(n.data[0]);
|
|
||||||
MontyReducer { n: n, n0inv: n0inv }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Montgomery Reduction
|
|
||||||
//
|
|
||||||
// Reference:
|
|
||||||
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 2.6
|
|
||||||
fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint {
|
|
||||||
let mut c = a.data;
|
|
||||||
let n = &mr.n.data;
|
|
||||||
let n_size = n.len();
|
|
||||||
|
|
||||||
// Allocate sufficient work space
|
|
||||||
c.resize(2 * n_size + 2, 0);
|
|
||||||
|
|
||||||
// β is the size of a word, in this case 32 bits. So "a mod β" is
|
|
||||||
// equivalent to masking a to 32 bits.
|
|
||||||
// mu <- -N^(-1) mod β
|
|
||||||
let mu = 0u32.wrapping_sub(mr.n0inv);
|
|
||||||
|
|
||||||
// 1: for i = 0 to (n-1)
|
|
||||||
for i in 0..n_size {
|
|
||||||
// 2: q_i <- mu*c_i mod β
|
|
||||||
let q_i = c[i].wrapping_mul(mu);
|
|
||||||
|
|
||||||
// 3: C <- C + q_i * N * β^i
|
|
||||||
super::algorithms::mac_digit(&mut c[i..], n, q_i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4: R <- C * β^(-n)
|
|
||||||
// This is an n-word bitshift, equivalent to skipping n words.
|
|
||||||
let ret = BigUint::new(c[n_size..].to_vec());
|
|
||||||
|
|
||||||
// 5: if R >= β^n then return R-N else return R.
|
|
||||||
if &ret < mr.n {
|
|
||||||
ret
|
|
||||||
} else {
|
|
||||||
ret - mr.n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Montgomery Multiplication
|
|
||||||
fn monty_mult(a: BigUint, b: &BigUint, mr: &MontyReducer) -> BigUint {
|
|
||||||
monty_redc(a * b, mr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Montgomery Squaring
|
|
||||||
fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint {
|
|
||||||
// TODO: Replace with an optimised squaring function
|
|
||||||
monty_redc(&a * &a, mr)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
|
|
||||||
let mr = MontyReducer::new(modulus);
|
|
||||||
|
|
||||||
// Calculate the Montgomery parameter
|
|
||||||
let mut v = vec![0; modulus.data.len()];
|
|
||||||
v.push(1);
|
|
||||||
let r = BigUint::new(v);
|
|
||||||
|
|
||||||
// Map the base to the Montgomery domain
|
|
||||||
let mut apri = a * &r % modulus;
|
|
||||||
|
|
||||||
// Binary exponentiation
|
|
||||||
let mut ans = &r % modulus;
|
|
||||||
let mut e = exp.clone();
|
|
||||||
while !e.is_zero() {
|
|
||||||
if e.is_odd() {
|
|
||||||
ans = monty_mult(ans, &apri, &mr);
|
|
||||||
}
|
|
||||||
apri = monty_sqr(apri, &mr);
|
|
||||||
e = e >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map the result back to the residues domain
|
|
||||||
monty_redc(ans, &mr)
|
|
||||||
}
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,181 +0,0 @@
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
use num_bigint::{BigInt, Sign, ToBigInt};
|
|
||||||
use num_traits::ToPrimitive;
|
|
||||||
use std::{i32, i64, u32};
|
|
||||||
|
|
||||||
enum ValueVec {
|
|
||||||
N,
|
|
||||||
P(&'static [u32]),
|
|
||||||
M(&'static [u32]),
|
|
||||||
}
|
|
||||||
|
|
||||||
use ValueVec::*;
|
|
||||||
|
|
||||||
impl ToBigInt for ValueVec {
|
|
||||||
fn to_bigint(&self) -> Option<BigInt> {
|
|
||||||
match self {
|
|
||||||
&N => Some(BigInt::from_slice(Sign::NoSign, &[])),
|
|
||||||
&P(s) => Some(BigInt::from_slice(Sign::Plus, s)),
|
|
||||||
&M(s) => Some(BigInt::from_slice(Sign::Minus, s)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// a, !a
|
|
||||||
const NOT_VALUES: &'static [(ValueVec, ValueVec)] = &[
|
|
||||||
(N, M(&[1])),
|
|
||||||
(P(&[1]), M(&[2])),
|
|
||||||
(P(&[2]), M(&[3])),
|
|
||||||
(P(&[!0 - 2]), M(&[!0 - 1])),
|
|
||||||
(P(&[!0 - 1]), M(&[!0])),
|
|
||||||
(P(&[!0]), M(&[0, 1])),
|
|
||||||
(P(&[0, 1]), M(&[1, 1])),
|
|
||||||
(P(&[1, 1]), M(&[2, 1])),
|
|
||||||
];
|
|
||||||
|
|
||||||
// a, b, a & b, a | b, a ^ b
|
|
||||||
const BITWISE_VALUES: &'static [(ValueVec, ValueVec, ValueVec, ValueVec, ValueVec)] = &[
|
|
||||||
(N, N, N, N, N),
|
|
||||||
(N, P(&[1]), N, P(&[1]), P(&[1])),
|
|
||||||
(N, P(&[!0]), N, P(&[!0]), P(&[!0])),
|
|
||||||
(N, P(&[0, 1]), N, P(&[0, 1]), P(&[0, 1])),
|
|
||||||
(N, M(&[1]), N, M(&[1]), M(&[1])),
|
|
||||||
(N, M(&[!0]), N, M(&[!0]), M(&[!0])),
|
|
||||||
(N, M(&[0, 1]), N, M(&[0, 1]), M(&[0, 1])),
|
|
||||||
(P(&[1]), P(&[!0]), P(&[1]), P(&[!0]), P(&[!0 - 1])),
|
|
||||||
(P(&[!0]), P(&[!0]), P(&[!0]), P(&[!0]), N),
|
|
||||||
(P(&[!0]), P(&[1, 1]), P(&[1]), P(&[!0, 1]), P(&[!0 - 1, 1])),
|
|
||||||
(P(&[1]), M(&[!0]), P(&[1]), M(&[!0]), M(&[0, 1])),
|
|
||||||
(P(&[!0]), M(&[1]), P(&[!0]), M(&[1]), M(&[0, 1])),
|
|
||||||
(P(&[!0]), M(&[!0]), P(&[1]), M(&[1]), M(&[2])),
|
|
||||||
(P(&[!0]), M(&[1, 1]), P(&[!0]), M(&[1, 1]), M(&[0, 2])),
|
|
||||||
(P(&[1, 1]), M(&[!0]), P(&[1, 1]), M(&[!0]), M(&[0, 2])),
|
|
||||||
(M(&[1]), M(&[!0]), M(&[!0]), M(&[1]), P(&[!0 - 1])),
|
|
||||||
(M(&[!0]), M(&[!0]), M(&[!0]), M(&[!0]), N),
|
|
||||||
(M(&[!0]), M(&[1, 1]), M(&[!0, 1]), M(&[1]), P(&[!0 - 1, 1])),
|
|
||||||
];
|
|
||||||
|
|
||||||
const I32_MIN: i64 = i32::MIN as i64;
|
|
||||||
const I32_MAX: i64 = i32::MAX as i64;
|
|
||||||
const U32_MAX: i64 = u32::MAX as i64;
|
|
||||||
|
|
||||||
// some corner cases
|
|
||||||
const I64_VALUES: &'static [i64] = &[
|
|
||||||
i64::MIN,
|
|
||||||
i64::MIN + 1,
|
|
||||||
i64::MIN + 2,
|
|
||||||
i64::MIN + 3,
|
|
||||||
-U32_MAX - 3,
|
|
||||||
-U32_MAX - 2,
|
|
||||||
-U32_MAX - 1,
|
|
||||||
-U32_MAX,
|
|
||||||
-U32_MAX + 1,
|
|
||||||
-U32_MAX + 2,
|
|
||||||
-U32_MAX + 3,
|
|
||||||
I32_MIN - 3,
|
|
||||||
I32_MIN - 2,
|
|
||||||
I32_MIN - 1,
|
|
||||||
I32_MIN,
|
|
||||||
I32_MIN + 1,
|
|
||||||
I32_MIN + 2,
|
|
||||||
I32_MIN + 3,
|
|
||||||
-3,
|
|
||||||
-2,
|
|
||||||
-1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
I32_MAX - 3,
|
|
||||||
I32_MAX - 2,
|
|
||||||
I32_MAX - 1,
|
|
||||||
I32_MAX,
|
|
||||||
I32_MAX + 1,
|
|
||||||
I32_MAX + 2,
|
|
||||||
I32_MAX + 3,
|
|
||||||
U32_MAX - 3,
|
|
||||||
U32_MAX - 2,
|
|
||||||
U32_MAX - 1,
|
|
||||||
U32_MAX,
|
|
||||||
U32_MAX + 1,
|
|
||||||
U32_MAX + 2,
|
|
||||||
U32_MAX + 3,
|
|
||||||
i64::MAX - 3,
|
|
||||||
i64::MAX - 2,
|
|
||||||
i64::MAX - 1,
|
|
||||||
i64::MAX,
|
|
||||||
];
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_not() {
|
|
||||||
for &(ref a, ref not) in NOT_VALUES.iter() {
|
|
||||||
let a = a.to_bigint().unwrap();
|
|
||||||
let not = not.to_bigint().unwrap();
|
|
||||||
|
|
||||||
// sanity check for tests that fit in i64
|
|
||||||
if let (Some(prim_a), Some(prim_not)) = (a.to_i64(), not.to_i64()) {
|
|
||||||
assert_eq!(!prim_a, prim_not);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(!a.clone(), not, "!{:x}", a);
|
|
||||||
assert_eq!(!not.clone(), a, "!{:x}", not);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_not_i64() {
|
|
||||||
for &prim_a in I64_VALUES.iter() {
|
|
||||||
let a = prim_a.to_bigint().unwrap();
|
|
||||||
let not = (!prim_a).to_bigint().unwrap();
|
|
||||||
assert_eq!(!a.clone(), not, "!{:x}", a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bitwise() {
|
|
||||||
for &(ref a, ref b, ref and, ref or, ref xor) in BITWISE_VALUES.iter() {
|
|
||||||
let a = a.to_bigint().unwrap();
|
|
||||||
let b = b.to_bigint().unwrap();
|
|
||||||
let and = and.to_bigint().unwrap();
|
|
||||||
let or = or.to_bigint().unwrap();
|
|
||||||
let xor = xor.to_bigint().unwrap();
|
|
||||||
|
|
||||||
// sanity check for tests that fit in i64
|
|
||||||
if let (Some(prim_a), Some(prim_b)) = (a.to_i64(), b.to_i64()) {
|
|
||||||
if let Some(prim_and) = and.to_i64() {
|
|
||||||
assert_eq!(prim_a & prim_b, prim_and);
|
|
||||||
}
|
|
||||||
if let Some(prim_or) = or.to_i64() {
|
|
||||||
assert_eq!(prim_a | prim_b, prim_or);
|
|
||||||
}
|
|
||||||
if let Some(prim_xor) = xor.to_i64() {
|
|
||||||
assert_eq!(prim_a ^ prim_b, prim_xor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(a.clone() & &b, and, "{:x} & {:x}", a, b);
|
|
||||||
assert_eq!(b.clone() & &a, and, "{:x} & {:x}", b, a);
|
|
||||||
assert_eq!(a.clone() | &b, or, "{:x} | {:x}", a, b);
|
|
||||||
assert_eq!(b.clone() | &a, or, "{:x} | {:x}", b, a);
|
|
||||||
assert_eq!(a.clone() ^ &b, xor, "{:x} ^ {:x}", a, b);
|
|
||||||
assert_eq!(b.clone() ^ &a, xor, "{:x} ^ {:x}", b, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bitwise_i64() {
|
|
||||||
for &prim_a in I64_VALUES.iter() {
|
|
||||||
let a = prim_a.to_bigint().unwrap();
|
|
||||||
for &prim_b in I64_VALUES.iter() {
|
|
||||||
let b = prim_b.to_bigint().unwrap();
|
|
||||||
let and = (prim_a & prim_b).to_bigint().unwrap();
|
|
||||||
let or = (prim_a | prim_b).to_bigint().unwrap();
|
|
||||||
let xor = (prim_a ^ prim_b).to_bigint().unwrap();
|
|
||||||
assert_eq!(a.clone() & &b, and, "{:x} & {:x}", a, b);
|
|
||||||
assert_eq!(a.clone() | &b, or, "{:x} | {:x}", a, b);
|
|
||||||
assert_eq!(a.clone() ^ &b, xor, "{:x} ^ {:x}", a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
|
||||||
use num_bigint::Sign::Plus;
|
|
||||||
use num_traits::{Signed, ToPrimitive, Zero};
|
|
||||||
|
|
||||||
use std::ops::Neg;
|
|
||||||
|
|
||||||
mod consts;
|
|
||||||
use consts::*;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_add() {
|
|
||||||
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
|
||||||
assert_signed_scalar_op!(x + y == z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let b = BigInt::from_slice(Plus, b_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
let (na, nb, nc) = (-&a, -&b, -&c);
|
|
||||||
|
|
||||||
check(&a, &b, &c);
|
|
||||||
check(&b, &a, &c);
|
|
||||||
check(&c, &na, &b);
|
|
||||||
check(&c, &nb, &a);
|
|
||||||
check(&a, &nc, &nb);
|
|
||||||
check(&b, &nc, &na);
|
|
||||||
check(&na, &nb, &nc);
|
|
||||||
check(&a, &na, &Zero::zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_sub() {
|
|
||||||
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
|
||||||
assert_signed_scalar_op!(x - y == z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let b = BigInt::from_slice(Plus, b_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
let (na, nb, nc) = (-&a, -&b, -&c);
|
|
||||||
|
|
||||||
check(&c, &a, &b);
|
|
||||||
check(&c, &b, &a);
|
|
||||||
check(&nb, &a, &nc);
|
|
||||||
check(&na, &b, &nc);
|
|
||||||
check(&b, &na, &c);
|
|
||||||
check(&a, &nb, &c);
|
|
||||||
check(&nc, &na, &nb);
|
|
||||||
check(&a, &a, &Zero::zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_mul() {
|
|
||||||
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
|
||||||
assert_signed_scalar_op!(x * y == z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let b = BigInt::from_slice(Plus, b_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
let (na, nb, nc) = (-&a, -&b, -&c);
|
|
||||||
|
|
||||||
check(&a, &b, &c);
|
|
||||||
check(&b, &a, &c);
|
|
||||||
check(&na, &nb, &c);
|
|
||||||
|
|
||||||
check(&na, &b, &nc);
|
|
||||||
check(&nb, &a, &nc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_div_rem() {
|
|
||||||
fn check_sub(a: &BigInt, b: u32, ans_q: &BigInt, ans_r: &BigInt) {
|
|
||||||
let (q, r) = (a / b, a % b);
|
|
||||||
if !r.is_zero() {
|
|
||||||
assert_eq!(r.sign(), a.sign());
|
|
||||||
}
|
|
||||||
assert!(r.abs() <= From::from(b));
|
|
||||||
assert!(*a == b * &q + &r);
|
|
||||||
assert!(q == *ans_q);
|
|
||||||
assert!(r == *ans_r);
|
|
||||||
|
|
||||||
let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone());
|
|
||||||
assert_op!(a / b == ans_q);
|
|
||||||
assert_op!(a % b == ans_r);
|
|
||||||
|
|
||||||
if b <= i32::max_value() as u32 {
|
|
||||||
let nb = -(b as i32);
|
|
||||||
assert_op!(a / nb == -ans_q.clone());
|
|
||||||
assert_op!(a % nb == ans_r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {
|
|
||||||
check_sub(a, b, q, r);
|
|
||||||
check_sub(&a.neg(), b, &q.neg(), &r.neg());
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let b = BigInt::from_slice(Plus, b_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
|
|
||||||
if a_vec.len() == 1 && a_vec[0] != 0 {
|
|
||||||
let a = a_vec[0];
|
|
||||||
check(&c, a, &b, &Zero::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
if b_vec.len() == 1 && b_vec[0] != 0 {
|
|
||||||
let b = b_vec[0];
|
|
||||||
check(&c, b, &a, &Zero::zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in DIV_REM_QUADRUPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec, d_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
let d = BigInt::from_slice(Plus, d_vec);
|
|
||||||
|
|
||||||
if b_vec.len() == 1 && b_vec[0] != 0 {
|
|
||||||
let b = b_vec[0];
|
|
||||||
check(&a, b, &c, &d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,109 +0,0 @@
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
use num_bigint::BigUint;
|
|
||||||
use num_traits::{ToPrimitive, Zero};
|
|
||||||
|
|
||||||
mod consts;
|
|
||||||
use consts::*;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod macros;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_add() {
|
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
|
||||||
assert_unsigned_scalar_op!(x + y == z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
|
|
||||||
check(&a, &b, &c);
|
|
||||||
check(&b, &a, &c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_sub() {
|
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
|
||||||
assert_unsigned_scalar_op!(x - y == z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
|
|
||||||
check(&c, &a, &b);
|
|
||||||
check(&c, &b, &a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_mul() {
|
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
|
||||||
assert_unsigned_scalar_op!(x * y == z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
|
|
||||||
check(&a, &b, &c);
|
|
||||||
check(&b, &a, &c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_rem_noncommutative() {
|
|
||||||
assert_eq!(5u8 % BigUint::from(7u8), 5u8.into());
|
|
||||||
assert_eq!(BigUint::from(5u8) % 7u8, 5u8.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar_div_rem() {
|
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint, r: &BigUint) {
|
|
||||||
let (x, y, z, r) = (x.clone(), y.clone(), z.clone(), r.clone());
|
|
||||||
assert_unsigned_scalar_op!(x / y == z);
|
|
||||||
assert_unsigned_scalar_op!(x % y == r);
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
|
|
||||||
if !a.is_zero() {
|
|
||||||
check(&c, &a, &b, &Zero::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !b.is_zero() {
|
|
||||||
check(&c, &b, &a, &Zero::zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in DIV_REM_QUADRUPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec, d_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
let d = BigUint::from_slice(d_vec);
|
|
||||||
|
|
||||||
if !b.is_zero() {
|
|
||||||
check(&a, &b, &c, &d);
|
|
||||||
assert_unsigned_scalar_op!(a / b == c);
|
|
||||||
assert_unsigned_scalar_op!(a % b == d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
#![allow(unused)]
|
|
||||||
|
|
||||||
pub const N1: u32 = -1i32 as u32;
|
|
||||||
pub const N2: u32 = -2i32 as u32;
|
|
||||||
|
|
||||||
pub const SUM_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32])] = &[
|
|
||||||
(&[], &[], &[]),
|
|
||||||
(&[], &[1], &[1]),
|
|
||||||
(&[1], &[1], &[2]),
|
|
||||||
(&[1], &[1, 1], &[2, 1]),
|
|
||||||
(&[1], &[N1], &[0, 1]),
|
|
||||||
(&[1], &[N1, N1], &[0, 0, 1]),
|
|
||||||
(&[N1, N1], &[N1, N1], &[N2, N1, 1]),
|
|
||||||
(&[1, 1, 1], &[N1, N1], &[0, 1, 2]),
|
|
||||||
(&[2, 2, 1], &[N1, N2], &[1, 1, 2]),
|
|
||||||
(&[1, 2, 2, 1], &[N1, N2], &[0, 1, 3, 1]),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const M: u32 = ::std::u32::MAX;
|
|
||||||
pub const MUL_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32])] = &[
|
|
||||||
(&[], &[], &[]),
|
|
||||||
(&[], &[1], &[]),
|
|
||||||
(&[2], &[], &[]),
|
|
||||||
(&[1], &[1], &[1]),
|
|
||||||
(&[2], &[3], &[6]),
|
|
||||||
(&[1], &[1, 1, 1], &[1, 1, 1]),
|
|
||||||
(&[1, 2, 3], &[3], &[3, 6, 9]),
|
|
||||||
(&[1, 1, 1], &[N1], &[N1, N1, N1]),
|
|
||||||
(&[1, 2, 3], &[N1], &[N1, N2, N2, 2]),
|
|
||||||
(&[1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]),
|
|
||||||
(&[N1], &[N1], &[1, N2]),
|
|
||||||
(&[N1, N1], &[N1], &[1, N1, N2]),
|
|
||||||
(&[N1, N1, N1], &[N1], &[1, N1, N1, N2]),
|
|
||||||
(&[N1, N1, N1, N1], &[N1], &[1, N1, N1, N1, N2]),
|
|
||||||
(&[M / 2 + 1], &[2], &[0, 1]),
|
|
||||||
(&[0, M / 2 + 1], &[2], &[0, 0, 1]),
|
|
||||||
(&[1, 2], &[1, 2, 3], &[1, 4, 7, 6]),
|
|
||||||
(&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]),
|
|
||||||
(&[N1, N1, N1], &[N1, N1, N1, N1], &[1, 0, 0, N1, N2, N1, N1]),
|
|
||||||
(&[0, 0, 1], &[1, 2, 3], &[0, 0, 1, 2, 3]),
|
|
||||||
(&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const DIV_REM_QUADRUPLES: &'static [(
|
|
||||||
&'static [u32],
|
|
||||||
&'static [u32],
|
|
||||||
&'static [u32],
|
|
||||||
&'static [u32],
|
|
||||||
)] = &[
|
|
||||||
(&[1], &[2], &[], &[1]),
|
|
||||||
(&[3], &[2], &[1], &[1]),
|
|
||||||
(&[1, 1], &[2], &[M / 2 + 1], &[1]),
|
|
||||||
(&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]),
|
|
||||||
(&[0, 1], &[N1], &[1], &[1]),
|
|
||||||
(&[N1, N1], &[N2], &[2, 1], &[3]),
|
|
||||||
];
|
|
|
@ -1,70 +0,0 @@
|
||||||
#![allow(unused)]
|
|
||||||
|
|
||||||
/// Assert that an op works for all val/ref combinations
|
|
||||||
macro_rules! assert_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_eq!((&$left) $op (&$right), $expected);
|
|
||||||
assert_eq!((&$left) $op $right.clone(), $expected);
|
|
||||||
assert_eq!($left.clone() $op (&$right), $expected);
|
|
||||||
assert_eq!($left.clone() $op $right.clone(), $expected);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assert that an assign-op works for all val/ref combinations
|
|
||||||
macro_rules! assert_assign_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {{
|
|
||||||
let mut left = $left.clone();
|
|
||||||
assert_eq!({ left $op &$right; left}, $expected);
|
|
||||||
|
|
||||||
let mut left = $left.clone();
|
|
||||||
assert_eq!({ left $op $right.clone(); left}, $expected);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assert that an op works for scalar left or right
|
|
||||||
macro_rules! assert_scalar_op {
|
|
||||||
(($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
$(
|
|
||||||
if let Some(left) = $left.$to() {
|
|
||||||
assert_op!(left $op $right == $expected);
|
|
||||||
}
|
|
||||||
if let Some(right) = $right.$to() {
|
|
||||||
assert_op!($left $op right == $expected);
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(has_i128))]
|
|
||||||
macro_rules! assert_unsigned_scalar_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize)
|
|
||||||
$left $op $right == $expected);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_i128)]
|
|
||||||
macro_rules! assert_unsigned_scalar_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128)
|
|
||||||
$left $op $right == $expected);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(has_i128))]
|
|
||||||
macro_rules! assert_signed_scalar_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize,
|
|
||||||
to_i8, to_i16, to_i32, to_i64, to_isize)
|
|
||||||
$left $op $right == $expected);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_i128)]
|
|
||||||
macro_rules! assert_signed_scalar_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128,
|
|
||||||
to_i8, to_i16, to_i32, to_i64, to_isize, to_i128)
|
|
||||||
$left $op $right == $expected);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
static BIG_B: &'static str = "\
|
|
||||||
efac3c0a_0de55551_fee0bfe4_67fa017a_1a898fa1_6ca57cb1\
|
|
||||||
ca9e3248_cacc09a9_b99d6abc_38418d0f_82ae4238_d9a68832\
|
|
||||||
aadec7c1_ac5fed48_7a56a71b_67ac59d5_afb28022_20d9592d\
|
|
||||||
247c4efc_abbd9b75_586088ee_1dc00dc4_232a8e15_6e8191dd\
|
|
||||||
675b6ae0_c80f5164_752940bc_284b7cee_885c1e10_e495345b\
|
|
||||||
8fbe9cfd_e5233fe1_19459d0b_d64be53c_27de5a02_a829976b\
|
|
||||||
33096862_82dad291_bd38b6a9_be396646_ddaf8039_a2573c39\
|
|
||||||
1b14e8bc_2cb53e48_298c047e_d9879e9c_5a521076_f0e27df3\
|
|
||||||
990e1659_d3d8205b_6443ebc0_9918ebee_6764f668_9f2b2be3\
|
|
||||||
b59cbc76_d76d0dfc_d737c3ec_0ccf9c00_ad0554bf_17e776ad\
|
|
||||||
b4edf9cc_6ce540be_76229093_5c53893b";
|
|
||||||
|
|
||||||
static BIG_E: &'static str = "\
|
|
||||||
be0e6ea6_08746133_e0fbc1bf_82dba91e_e2b56231_a81888d2\
|
|
||||||
a833a1fc_f7ff002a_3c486a13_4f420bf3_a5435be9_1a5c8391\
|
|
||||||
774d6e6c_085d8357_b0c97d4d_2bb33f7c_34c68059_f78d2541\
|
|
||||||
eacc8832_426f1816_d3be001e_b69f9242_51c7708e_e10efe98\
|
|
||||||
449c9a4a_b55a0f23_9d797410_515da00d_3ea07970_4478a2ca\
|
|
||||||
c3d5043c_bd9be1b4_6dce479d_4302d344_84a939e6_0ab5ada7\
|
|
||||||
12ae34b2_30cc473c_9f8ee69d_2cac5970_29f5bf18_bc8203e4\
|
|
||||||
f3e895a2_13c94f1e_24c73d77_e517e801_53661fdd_a2ce9e47\
|
|
||||||
a73dd7f8_2f2adb1e_3f136bf7_8ae5f3b8_08730de1_a4eff678\
|
|
||||||
e77a06d0_19a522eb_cbefba2a_9caf7736_b157c5c6_2d192591\
|
|
||||||
17946850_2ddb1822_117b68a0_32f7db88";
|
|
||||||
|
|
||||||
// This modulus is the prime from the 2048-bit MODP DH group:
|
|
||||||
// https://tools.ietf.org/html/rfc3526#section-3
|
|
||||||
static BIG_M: &'static str = "\
|
|
||||||
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
|
||||||
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
|
||||||
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
|
||||||
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
|
||||||
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
|
||||||
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
|
||||||
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
|
||||||
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
|
||||||
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
|
||||||
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
|
||||||
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
|
||||||
|
|
||||||
static BIG_R: &'static str = "\
|
|
||||||
a1468311_6e56edc9_7a98228b_5e924776_0dd7836e_caabac13\
|
|
||||||
eda5373b_4752aa65_a1454850_40dc770e_30aa8675_6be7d3a8\
|
|
||||||
9d3085e4_da5155cf_b451ef62_54d0da61_cf2b2c87_f495e096\
|
|
||||||
055309f7_77802bbb_37271ba8_1313f1b5_075c75d1_024b6c77\
|
|
||||||
fdb56f17_b05bce61_e527ebfd_2ee86860_e9907066_edd526e7\
|
|
||||||
93d289bf_6726b293_41b0de24_eff82424_8dfd374b_4ec59542\
|
|
||||||
35ced2b2_6b195c90_10042ffb_8f58ce21_bc10ec42_64fda779\
|
|
||||||
d352d234_3d4eaea6_a86111ad_a37e9555_43ca78ce_2885bed7\
|
|
||||||
5a30d182_f1cf6834_dc5b6e27_1a41ac34_a2e91e11_33363ff0\
|
|
||||||
f88a7b04_900227c9_f6e6d06b_7856b4bb_4e354d61_060db6c8\
|
|
||||||
109c4735_6e7db425_7b5d74c7_0b709508";
|
|
||||||
|
|
||||||
mod biguint {
|
|
||||||
use num_bigint::BigUint;
|
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::Num;
|
|
||||||
|
|
||||||
fn check_modpow<T: Into<BigUint>>(b: T, e: T, m: T, r: T) {
|
|
||||||
let b: BigUint = b.into();
|
|
||||||
let e: BigUint = e.into();
|
|
||||||
let m: BigUint = m.into();
|
|
||||||
let r: BigUint = r.into();
|
|
||||||
|
|
||||||
assert_eq!(b.modpow(&e, &m), r);
|
|
||||||
|
|
||||||
let even_m = &m << 1;
|
|
||||||
let even_modpow = b.modpow(&e, &even_m);
|
|
||||||
assert!(even_modpow < even_m);
|
|
||||||
assert_eq!(even_modpow.mod_floor(&m), r);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_modpow() {
|
|
||||||
check_modpow::<u32>(1, 0, 11, 1);
|
|
||||||
check_modpow::<u32>(0, 15, 11, 0);
|
|
||||||
check_modpow::<u32>(3, 7, 11, 9);
|
|
||||||
check_modpow::<u32>(5, 117, 19, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_modpow_big() {
|
|
||||||
let b = BigUint::from_str_radix(super::BIG_B, 16).unwrap();
|
|
||||||
let e = BigUint::from_str_radix(super::BIG_E, 16).unwrap();
|
|
||||||
let m = BigUint::from_str_radix(super::BIG_M, 16).unwrap();
|
|
||||||
let r = BigUint::from_str_radix(super::BIG_R, 16).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(b.modpow(&e, &m), r);
|
|
||||||
|
|
||||||
let even_m = &m << 1;
|
|
||||||
let even_modpow = b.modpow(&e, &even_m);
|
|
||||||
assert!(even_modpow < even_m);
|
|
||||||
assert_eq!(even_modpow % m, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod bigint {
|
|
||||||
use num_bigint::BigInt;
|
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::{Num, One, Signed, Zero};
|
|
||||||
|
|
||||||
fn check_modpow<T: Into<BigInt>>(b: T, e: T, m: T, r: T) {
|
|
||||||
fn check(b: &BigInt, e: &BigInt, m: &BigInt, r: &BigInt) {
|
|
||||||
assert_eq!(&b.modpow(e, m), r);
|
|
||||||
|
|
||||||
let even_m = m << 1;
|
|
||||||
let even_modpow = b.modpow(e, m);
|
|
||||||
assert!(even_modpow.abs() < even_m.abs());
|
|
||||||
assert_eq!(&even_modpow.mod_floor(&m), r);
|
|
||||||
|
|
||||||
// the sign of the result follows the modulus like `mod_floor`, not `rem`
|
|
||||||
assert_eq!(b.modpow(&BigInt::one(), m), b.mod_floor(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
let b: BigInt = b.into();
|
|
||||||
let e: BigInt = e.into();
|
|
||||||
let m: BigInt = m.into();
|
|
||||||
let r: BigInt = r.into();
|
|
||||||
|
|
||||||
let neg_r = if r.is_zero() { BigInt::zero() } else { &m - &r };
|
|
||||||
|
|
||||||
check(&b, &e, &m, &r);
|
|
||||||
check(&-&b, &e, &m, &neg_r);
|
|
||||||
check(&b, &e, &-&m, &-neg_r);
|
|
||||||
check(&-b, &e, &-m, &-r);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_modpow() {
|
|
||||||
check_modpow(1, 0, 11, 1);
|
|
||||||
check_modpow(0, 15, 11, 0);
|
|
||||||
check_modpow(3, 7, 11, 9);
|
|
||||||
check_modpow(5, 117, 19, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_modpow_big() {
|
|
||||||
let b = BigInt::from_str_radix(super::BIG_B, 16).unwrap();
|
|
||||||
let e = BigInt::from_str_radix(super::BIG_E, 16).unwrap();
|
|
||||||
let m = BigInt::from_str_radix(super::BIG_M, 16).unwrap();
|
|
||||||
let r = BigInt::from_str_radix(super::BIG_R, 16).unwrap();
|
|
||||||
|
|
||||||
check_modpow(b, e, m, r);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
extern crate num_bigint;
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
#[cfg(feature = "rand")]
|
|
||||||
extern crate rand;
|
|
||||||
|
|
||||||
mod biguint {
|
|
||||||
use num_bigint::BigUint;
|
|
||||||
use num_traits::{One, Pow, Zero};
|
|
||||||
use std::{i32, u32};
|
|
||||||
|
|
||||||
fn check<T: Into<BigUint>>(x: T, n: u32) {
|
|
||||||
let x: BigUint = x.into();
|
|
||||||
let root = x.nth_root(n);
|
|
||||||
println!("check {}.nth_root({}) = {}", x, n, root);
|
|
||||||
|
|
||||||
if n == 2 {
|
|
||||||
assert_eq!(root, x.sqrt())
|
|
||||||
} else if n == 3 {
|
|
||||||
assert_eq!(root, x.cbrt())
|
|
||||||
}
|
|
||||||
|
|
||||||
let lo = root.pow(n);
|
|
||||||
assert!(lo <= x);
|
|
||||||
assert_eq!(lo.nth_root(n), root);
|
|
||||||
if !lo.is_zero() {
|
|
||||||
assert_eq!((&lo - 1u32).nth_root(n), &root - 1u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
let hi = (&root + 1u32).pow(n);
|
|
||||||
assert!(hi > x);
|
|
||||||
assert_eq!(hi.nth_root(n), &root + 1u32);
|
|
||||||
assert_eq!((&hi - 1u32).nth_root(n), root);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sqrt() {
|
|
||||||
check(99u32, 2);
|
|
||||||
check(100u32, 2);
|
|
||||||
check(120u32, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cbrt() {
|
|
||||||
check(8u32, 3);
|
|
||||||
check(26u32, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nth_root() {
|
|
||||||
check(0u32, 1);
|
|
||||||
check(10u32, 1);
|
|
||||||
check(100u32, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_nth_root_n_is_zero() {
|
|
||||||
check(4u32, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nth_root_big() {
|
|
||||||
let x = BigUint::from(123_456_789_u32);
|
|
||||||
let expected = BigUint::from(6u32);
|
|
||||||
|
|
||||||
assert_eq!(x.nth_root(10), expected);
|
|
||||||
check(x, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nth_root_googol() {
|
|
||||||
let googol = BigUint::from(10u32).pow(100u32);
|
|
||||||
|
|
||||||
// perfect divisors of 100
|
|
||||||
for &n in &[2, 4, 5, 10, 20, 25, 50, 100] {
|
|
||||||
let expected = BigUint::from(10u32).pow(100u32 / n);
|
|
||||||
assert_eq!(googol.nth_root(n), expected);
|
|
||||||
check(googol.clone(), n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nth_root_twos() {
|
|
||||||
const EXP: u32 = 12;
|
|
||||||
const LOG2: usize = 1 << EXP;
|
|
||||||
let x = BigUint::one() << LOG2;
|
|
||||||
|
|
||||||
// the perfect divisors are just powers of two
|
|
||||||
for exp in 1..EXP + 1 {
|
|
||||||
let n = 2u32.pow(exp);
|
|
||||||
let expected = BigUint::one() << (LOG2 / n as usize);
|
|
||||||
assert_eq!(x.nth_root(n), expected);
|
|
||||||
check(x.clone(), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// degenerate cases should return quickly
|
|
||||||
assert!(x.nth_root(x.bits() as u32).is_one());
|
|
||||||
assert!(x.nth_root(i32::MAX as u32).is_one());
|
|
||||||
assert!(x.nth_root(u32::MAX).is_one());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "rand")]
|
|
||||||
#[test]
|
|
||||||
fn test_roots_rand() {
|
|
||||||
use num_bigint::RandBigInt;
|
|
||||||
use rand::distributions::Uniform;
|
|
||||||
use rand::{thread_rng, Rng};
|
|
||||||
|
|
||||||
let mut rng = thread_rng();
|
|
||||||
let bit_range = Uniform::new(0, 2048);
|
|
||||||
let sample_bits: Vec<_> = rng.sample_iter(&bit_range).take(100).collect();
|
|
||||||
for bits in sample_bits {
|
|
||||||
let x = rng.gen_biguint(bits);
|
|
||||||
for n in 2..11 {
|
|
||||||
check(x.clone(), n);
|
|
||||||
}
|
|
||||||
check(x.clone(), 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_roots_rand1() {
|
|
||||||
// A random input that found regressions
|
|
||||||
let s = "575981506858479247661989091587544744717244516135539456183849\
|
|
||||||
986593934723426343633698413178771587697273822147578889823552\
|
|
||||||
182702908597782734558103025298880194023243541613924361007059\
|
|
||||||
353344183590348785832467726433749431093350684849462759540710\
|
|
||||||
026019022227591412417064179299354183441181373862905039254106\
|
|
||||||
4781867";
|
|
||||||
let x: BigUint = s.parse().unwrap();
|
|
||||||
|
|
||||||
check(x.clone(), 2);
|
|
||||||
check(x.clone(), 3);
|
|
||||||
check(x.clone(), 10);
|
|
||||||
check(x.clone(), 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod bigint {
|
|
||||||
use num_bigint::BigInt;
|
|
||||||
use num_traits::{Pow, Signed};
|
|
||||||
|
|
||||||
fn check(x: i64, n: u32) {
|
|
||||||
let big_x = BigInt::from(x);
|
|
||||||
let res = big_x.nth_root(n);
|
|
||||||
|
|
||||||
if n == 2 {
|
|
||||||
assert_eq!(&res, &big_x.sqrt())
|
|
||||||
} else if n == 3 {
|
|
||||||
assert_eq!(&res, &big_x.cbrt())
|
|
||||||
}
|
|
||||||
|
|
||||||
if big_x.is_negative() {
|
|
||||||
assert!(res.pow(n) >= big_x);
|
|
||||||
assert!((res - 1u32).pow(n) < big_x);
|
|
||||||
} else {
|
|
||||||
assert!(res.pow(n) <= big_x);
|
|
||||||
assert!((res + 1u32).pow(n) > big_x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nth_root() {
|
|
||||||
check(-100, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_nth_root_x_neg_n_even() {
|
|
||||||
check(-100, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_sqrt_x_neg() {
|
|
||||||
check(-4, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cbrt() {
|
|
||||||
check(8, 3);
|
|
||||||
check(-8, 3);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"7aa575d1baa6278a46c9702151962c48ba036e0858735cb785854bc5fe0c8d45","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"80ffdcb01563610a5c0eab802eeec39cbb21054f47a9df550f8495a7e861eb40","RELEASES.md":"566c43d664f1d6a242632febb661005fda9a479882673925093a5b688159393d","benches/bigint.rs":"e0388d1880c4ff508b2f871c5b70f058999dd8c6a703c16e8ea69f0a8e1ba50d","benches/factorial.rs":"ed1d276a780e7e5fe79121b941c22a00c2854dbf92fd8a5372619853ba0c13b7","benches/gcd.rs":"2b433e5699b45e5fb23e77ab025a07e16e3eb9a49c47207b477551542fc4ff1e","benches/roots.rs":"967161d58d1977452ec7fa988a41848d575008a3e148eb048bc049c884d98f5f","benches/shootout-pidigits.rs":"c2a48133f5b679928f7e3f4e764c78aaa8c5b811f58b86fe57fae8c63cb07136","build.rs":"93c67318349abcc216b64973dfb12055e9eb2e1fb6631b2a1b3728f298f8e07c","src/algorithms.rs":"df10d5784da66ad6984fac2845a4611fbb893d384994618561804263acce3a76","src/bigint.rs":"78f8bf8fbd6c06d0a628dd560cc143428200fba7aeedb3c939ea2ce9d70ec3e6","src/bigrand.rs":"f2d16738d6811d6cc0999e4ba3e9477074115e665ac68a550106d5e926176f84","src/biguint.rs":"5c54978e84bd1344c2e1558b44ab196d52d92fc727dae3684ab2981843b804f1","src/lib.rs":"e43f5cbfa4736e71e78bb6ce72aa3da4867ceac225cc945405b2cad51d0e577e","src/macros.rs":"800239723d637c3ea1d6beb6a62b38a2300bd4c69c20dc0d50855ad6a8b31e70","src/monty.rs":"91688835e0fd409df72c3df5e07e2a114982578f03dd62721c02f36d5fc64ac6","tests/bigint.rs":"deb1e882093a0fa67d3b9a360c6e282fa45b75fb2681e60ce549ef074008c086","tests/bigint_bitwise.rs":"e6a2f76fa1eb919e7c513d7e30a8a2a963841a295a71103462fb8ab9792419b5","tests/bigint_scalar.rs":"5d6131e021f96d476f7949fa2b302581bd9254e91efde1bf2926cdd5e8dffcdb","tests/biguint.rs":"6e390bcc037b04210edb7a81ff87df705edd0afa439c44ac8cf369ca4fef55bd","tests/biguint_scalar.rs":"f16450c0dfcaf23b6fb85669b3de7c2bb6f594a65e3cdf91014b2e49c941cc95","tests/consts/mod.rs":"e20bc49a7cc95077242cbe4016b37745ea986c779d2385cb367fbfe44f15ff94","tests/macros/mod.rs":"1a8f9f015e5caaac60ce9ccff01a75ae489801c3ede6e7b9b3c5079b6efefc9c","tests/modpow.rs":"f1e4ed4fe466b544d7c4e57d0a0dc7d1c97b430b4805cae12f0915b8c40ab66f","tests/roots.rs":"a3bc2de170a0f6297cc8d8830d608db537ca102ccf204fd4fb8e2d92675622d8"},"package":"b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"}
|
{"files":{"Cargo.toml":"ba1041ccca008388ab7d7432ae63b811d8e744c8fa9e50f371bfbeb78acd1995","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"25f684f15b0ed6ea216c3831e567a9b5dc02b78ff7e579e0d7323305db75218c","RELEASES.md":"5a3045437dc1850ae4e39acd14f2660ed7bace9b0c4d7dae3950f049dbfd4d65","benches/bigint.rs":"252c0dc1f220a6fbdc151e729069260c2f5909516467ceb873e412e5691d7042","benches/factorial.rs":"d536f5584987847f10321b94175a0d8fd2beb14b7c814ec28eef1f96ca081fbe","benches/gcd.rs":"7ec5ce7174e1d31bd08ccc5670f5a32a5c084f258d7980cd6d02e0a8bb5562c4","benches/roots.rs":"3f87db894c379122aee5cd8520c7c759c26d8a9649ac47f45d1bf4d560e1cb07","benches/shootout-pidigits.rs":"985b76d6dba05c396efe4da136c6a0bb2c02bcf5b05cbb346f0f802a891629bb","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"56d4fbb7a55750e61d2074df2735a31995c1decbd988c0e722926235e0fed487","ci/rustup.sh":"c976bb2756da3876363b01fdbf06c13de20df421e5add45e4017c4df42ed06a6","ci/test_full.sh":"a0ac26b85809eb43edd813c9dc88f34a1a8227b7618f4bede89c8f2ac9a4c05a","src/algorithms.rs":"8827c46df051214d1d0e7670680ca9f4834eae678ed340c86b5ea32fddbc7c3c","src/bigint.rs":"7f113fdc034c566bc8475ff0a7d136aa8250cae047b4356084e6797a15f968e1","src/bigrand.rs":"d2f72b8833f367dd8990b4b026f302d838144c5a4de942135d39a3a9932f137d","src/biguint.rs":"b95bfcf84e3f831fb07982aa4b058cd16a524eaa493946eed8e8c5fb8d65797a","src/lib.rs":"d5cc50306f73f07555e7d3413edd2ca5c7d54cbc80a2e83844d77fb8750ae314","src/macros.rs":"2e763517922d960c06e3ac4d319b1d81e66dffadfde8fdf300ff8b8bb95bd8cd","src/monty.rs":"6a867846b7f6af9115add2fd59fccd0651c71dd7f2316e8fb9c812ff3c27da12","tests/bigint.rs":"f7df454f085a862ad5a98e3a802303a3fdf06275a7a1b92074b40b76a715bed2","tests/bigint_bitwise.rs":"dc9436c8f200f2b0ac08cefb23bb8e39c4e688e9026a506a678416c3d573128b","tests/bigint_scalar.rs":"aa176ed102cafd425a215a93460806914d8f3ac288c98ec3e56772fa17379838","tests/biguint.rs":"9ae79f96d1a3beca5be95dffe9d79dc3436f886edc6cae51faf4203c3e0c4681","tests/biguint_scalar.rs":"9cc6f2bf2fe77f34b09eb2266c23aded3b27a60dc1859eb60d3013164292467e","tests/consts/mod.rs":"f9ea5f40733e2f5f432803d830be9db929d91e5e5efd8510b07c6ced2fe554be","tests/macros/mod.rs":"2789b680dd14a770d5ceef430018be0ada85098d69e218c61c17214084c4f763","tests/modpow.rs":"f14cdea11e355a371b314cc866dfa13281a3226706ab2cf01c1485273afde300","tests/quickcheck.rs":"6d6c1ec244b2384a8b34e989870aef8bcedccf6cc46e2626b29a032703bef03c","tests/rand.rs":"08370135bd78432660cfcd708a9ea852022d555bc92c1f3c482fabd17faa64a0","tests/roots.rs":"9ec1bdb0cd1c72402a41e5470325a5276af75979b7fc0f0b63e7bbbb9f3505b2","tests/serde.rs":"79d7a0347207b3a3666af67d2ed97fa34f2922732121a3cb8f5b9f990846acfa","tests/torture.rs":"9fe4897580c0ebe2b7062f5b0b890b4b03510daa45c9236f0edba7144f9eb6f8"},"package":"f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"}
|
|
@ -11,12 +11,10 @@
|
||||||
# will likely look very different (and much more reasonable)
|
# will likely look very different (and much more reasonable)
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
edition = "2018"
|
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.3.0"
|
version = "0.2.3"
|
||||||
authors = ["The Rust Project Developers"]
|
authors = ["The Rust Project Developers"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
|
||||||
description = "Big integer implementation for Rust"
|
description = "Big integer implementation for Rust"
|
||||||
homepage = "https://github.com/rust-num/num-bigint"
|
homepage = "https://github.com/rust-num/num-bigint"
|
||||||
documentation = "https://docs.rs/num-bigint"
|
documentation = "https://docs.rs/num-bigint"
|
||||||
|
@ -44,32 +42,40 @@ name = "roots"
|
||||||
name = "shootout-pidigits"
|
name = "shootout-pidigits"
|
||||||
harness = false
|
harness = false
|
||||||
[dependencies.num-integer]
|
[dependencies.num-integer]
|
||||||
version = "0.1.42"
|
version = "0.1.39"
|
||||||
features = ["i128"]
|
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.num-traits]
|
[dependencies.num-traits]
|
||||||
version = "0.2.11"
|
version = "0.2.7"
|
||||||
features = ["i128"]
|
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.quickcheck]
|
[dependencies.quickcheck]
|
||||||
version = "0.9"
|
version = "0.8"
|
||||||
|
optional = true
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.quickcheck_macros]
|
||||||
|
version = "0.8"
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.rand]
|
[dependencies.rand]
|
||||||
version = "0.7"
|
version = "0.5"
|
||||||
|
features = ["std"]
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
features = ["std"]
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
|
[dev-dependencies.serde_test]
|
||||||
|
version = "1.0"
|
||||||
[build-dependencies.autocfg]
|
[build-dependencies.autocfg]
|
||||||
version = "1"
|
version = "0.1.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
i128 = ["num-integer/i128", "num-traits/i128"]
|
||||||
std = ["num-integer/std", "num-traits/std"]
|
std = ["num-integer/std", "num-traits/std"]
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
[![crate](https://img.shields.io/crates/v/num-bigint.svg)](https://crates.io/crates/num-bigint)
|
[![crate](https://img.shields.io/crates/v/num-bigint.svg)](https://crates.io/crates/num-bigint)
|
||||||
[![documentation](https://docs.rs/num-bigint/badge.svg)](https://docs.rs/num-bigint)
|
[![documentation](https://docs.rs/num-bigint/badge.svg)](https://docs.rs/num-bigint)
|
||||||
[![minimum rustc 1.31](https://img.shields.io/badge/rustc-1.31+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
|
![minimum rustc 1.15](https://img.shields.io/badge/rustc-1.15+-red.svg)
|
||||||
[![build status](https://github.com/rust-num/num-bigint/workflows/master/badge.svg)](https://github.com/rust-num/num-bigint/actions)
|
[![Travis status](https://travis-ci.org/rust-num/num-bigint.svg?branch=master)](https://travis-ci.org/rust-num/num-bigint)
|
||||||
|
|
||||||
Big integer types for Rust, `BigInt` and `BigUint`.
|
Big integer types for Rust, `BigInt` and `BigUint`.
|
||||||
|
|
||||||
|
@ -13,28 +13,25 @@ Add this to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num-bigint = "0.3"
|
num-bigint = "0.2"
|
||||||
|
```
|
||||||
|
|
||||||
|
and this to your crate root:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate num_bigint;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
The `std` crate feature is enabled by default, and is mandatory before Rust
|
The `std` crate feature is mandatory and enabled by default. If you depend on
|
||||||
1.36 and the stabilized `alloc` crate. If you depend on `num-bigint` with
|
`num-bigint` with `default-features = false`, you must manually enable the
|
||||||
`default-features = false`, you must manually enable the `std` feature yourself
|
`std` feature yourself. In the future, we hope to support `#![no_std]` with
|
||||||
if your compiler is not new enough.
|
the `alloc` crate when `std` is not enabled.
|
||||||
|
|
||||||
### Random Generation
|
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
|
||||||
`num-bigint` supports the generation of random big integers when the `rand`
|
mandatory by enabling the `i128` crate feature.
|
||||||
feature is enabled. To enable it include rand as
|
|
||||||
|
|
||||||
```toml
|
|
||||||
rand = "0.7"
|
|
||||||
num-bigint = { version = "0.3", features = ["rand"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that you must use the version of `rand` that `num-bigint` is compatible
|
|
||||||
with: `0.7`.
|
|
||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
|
|
||||||
|
@ -42,7 +39,7 @@ Release notes are available in [RELEASES.md](RELEASES.md).
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
The `num-bigint` crate is tested for rustc 1.31 and greater.
|
The `num-bigint` crate is tested for rustc 1.15 and greater.
|
||||||
|
|
||||||
## Alternatives
|
## Alternatives
|
||||||
|
|
||||||
|
@ -52,9 +49,9 @@ table offers a brief comparison to a few alternatives.
|
||||||
|
|
||||||
| Crate | License | Min rustc | Implementation |
|
| Crate | License | Min rustc | Implementation |
|
||||||
| :--------------- | :------------- | :-------- | :------------- |
|
| :--------------- | :------------- | :-------- | :------------- |
|
||||||
| **`num-bigint`** | MIT/Apache-2.0 | 1.31 | pure rust |
|
| **`num-bigint`** | MIT/Apache-2.0 | 1.15 | pure rust |
|
||||||
| [`ramp`] | Apache-2.0 | nightly | rust and inline assembly |
|
| [`ramp`] | Apache-2.0 | nightly | rust and inline assembly |
|
||||||
| [`rug`] | LGPL-3.0+ | 1.37 | bundles [GMP] via [`gmp-mpfr-sys`] |
|
| [`rug`] | LGPL-3.0+ | 1.31 | bundles [GMP] via [`gmp-mpfr-sys`] |
|
||||||
| [`rust-gmp`] | MIT | stable? | links to [GMP] |
|
| [`rust-gmp`] | MIT | stable? | links to [GMP] |
|
||||||
| [`apint`] | MIT/Apache-2.0 | 1.26 | pure rust (unfinished) |
|
| [`apint`] | MIT/Apache-2.0 | 1.26 | pure rust (unfinished) |
|
||||||
|
|
||||||
|
|
|
@ -1,74 +1,3 @@
|
||||||
# Release 0.3.0 (2020-06-12)
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- [The internal `BigDigit` may now be either `u32` or `u64`][62], although that
|
|
||||||
implementation detail is not exposed in the API. For now, this is chosen to
|
|
||||||
match the target pointer size, but may change in the future.
|
|
||||||
- [No-`std` is now supported with the `alloc` crate on Rust 1.36][101].
|
|
||||||
- [`Pow` is now implemented for bigint values][137], not just references.
|
|
||||||
- [`TryFrom` is now implemented on Rust 1.34 and later][123], converting signed
|
|
||||||
integers to unsigned, and narrowing big integers to primitives.
|
|
||||||
- [`Shl` and `Shr` are now implemented for a variety of shift types][142].
|
|
||||||
- A new `trailing_zeros()` returns the number of consecutive zeros from the
|
|
||||||
least significant bit.
|
|
||||||
- The new `BigInt::magnitude` and `into_parts` methods give access to its
|
|
||||||
`BigUint` part as the magnitude.
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
- `num-bigint` now requires Rust 1.31 or greater.
|
|
||||||
- The "i128" opt-in feature was removed, now always available.
|
|
||||||
- [Updated public dependences][110]:
|
|
||||||
- `rand` support has been updated to 0.7, requiring Rust 1.32.
|
|
||||||
- `quickcheck` support has been updated to 0.9, requiring Rust 1.34.
|
|
||||||
- [Removed `impl Neg for BigUint`][145], which only ever panicked.
|
|
||||||
- [Bit counts are now `u64` instead of `usize`][143].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @dignifiedquire, @hansihe,
|
|
||||||
@kpcyrd, @milesand, @tech6hutch
|
|
||||||
|
|
||||||
[62]: https://github.com/rust-num/num-bigint/pull/62
|
|
||||||
[101]: https://github.com/rust-num/num-bigint/pull/101
|
|
||||||
[110]: https://github.com/rust-num/num-bigint/pull/110
|
|
||||||
[123]: https://github.com/rust-num/num-bigint/pull/123
|
|
||||||
[137]: https://github.com/rust-num/num-bigint/pull/137
|
|
||||||
[142]: https://github.com/rust-num/num-bigint/pull/142
|
|
||||||
[143]: https://github.com/rust-num/num-bigint/pull/143
|
|
||||||
[145]: https://github.com/rust-num/num-bigint/pull/145
|
|
||||||
|
|
||||||
# Release 0.2.6 (2020-01-27)
|
|
||||||
|
|
||||||
- [Fix the promotion of negative `isize` in `BigInt` assign-ops][133].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @HactarCE
|
|
||||||
|
|
||||||
[133]: https://github.com/rust-num/num-bigint/pull/133
|
|
||||||
|
|
||||||
# Release 0.2.5 (2020-01-09)
|
|
||||||
|
|
||||||
- [Updated the `autocfg` build dependency to 1.0][126].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @tspiteri
|
|
||||||
|
|
||||||
[126]: https://github.com/rust-num/num-bigint/pull/126
|
|
||||||
|
|
||||||
# Release 0.2.4 (2020-01-01)
|
|
||||||
|
|
||||||
- [The new `BigUint::to_u32_digits` method][104] returns the number as a
|
|
||||||
little-endian vector of base-2<sup>32</sup> digits. The same method on
|
|
||||||
`BigInt` also returns the sign.
|
|
||||||
- [`BigUint::modpow` now applies a modulus even for exponent 1][113], which
|
|
||||||
also affects `BigInt::modpow`.
|
|
||||||
- [`BigInt::modpow` now returns the correct sign for negative bases with even
|
|
||||||
exponents][114].
|
|
||||||
|
|
||||||
[104]: https://github.com/rust-num/num-bigint/pull/104
|
|
||||||
[113]: https://github.com/rust-num/num-bigint/pull/113
|
|
||||||
[114]: https://github.com/rust-num/num-bigint/pull/114
|
|
||||||
|
|
||||||
**Contributors**: @alex-ozdemir, @cuviper, @dingelish, @Speedy37, @youknowone
|
|
||||||
|
|
||||||
# Release 0.2.3 (2019-09-03)
|
# Release 0.2.3 (2019-09-03)
|
||||||
|
|
||||||
- [`Pow` is now implemented for `BigUint` exponents][77].
|
- [`Pow` is now implemented for `BigUint` exponents][77].
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![cfg(feature = "rand")]
|
#![cfg(feature = "rand")]
|
||||||
|
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
extern crate rand;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use num_bigint::{BigInt, BigUint, RandBigInt};
|
use num_bigint::{BigInt, BigUint, RandBigInt};
|
||||||
use num_traits::{FromPrimitive, Num, One, Zero};
|
use num_traits::{FromPrimitive, Num, One, Pow, Zero};
|
||||||
use rand::rngs::StdRng;
|
use rand::{SeedableRng, StdRng};
|
||||||
use rand::SeedableRng;
|
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
|
@ -18,7 +21,7 @@ fn get_rng() -> StdRng {
|
||||||
SeedableRng::from_seed(seed)
|
SeedableRng::from_seed(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
||||||
let mut rng = get_rng();
|
let mut rng = get_rng();
|
||||||
let x = rng.gen_bigint(xbits);
|
let x = rng.gen_bigint(xbits);
|
||||||
let y = rng.gen_bigint(ybits);
|
let y = rng.gen_bigint(ybits);
|
||||||
|
@ -26,7 +29,7 @@ fn multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
||||||
b.iter(|| &x * &y);
|
b.iter(|| &x * &y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divide_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
||||||
let mut rng = get_rng();
|
let mut rng = get_rng();
|
||||||
let x = rng.gen_bigint(xbits);
|
let x = rng.gen_bigint(xbits);
|
||||||
let y = rng.gen_bigint(ybits);
|
let y = rng.gen_bigint(ybits);
|
||||||
|
@ -34,7 +37,7 @@ fn divide_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
||||||
b.iter(|| &x / &y);
|
b.iter(|| &x / &y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remainder_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
fn remainder_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
||||||
let mut rng = get_rng();
|
let mut rng = get_rng();
|
||||||
let x = rng.gen_bigint(xbits);
|
let x = rng.gen_bigint(xbits);
|
||||||
let y = rng.gen_bigint(ybits);
|
let y = rng.gen_bigint(ybits);
|
||||||
|
@ -44,9 +47,9 @@ fn remainder_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
||||||
|
|
||||||
fn factorial(n: usize) -> BigUint {
|
fn factorial(n: usize) -> BigUint {
|
||||||
let mut f: BigUint = One::one();
|
let mut f: BigUint = One::one();
|
||||||
for i in 1..=n {
|
for i in 1..(n + 1) {
|
||||||
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
||||||
f += bu;
|
f = f * bu;
|
||||||
}
|
}
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
@ -68,7 +71,7 @@ fn fib2(n: usize) -> BigUint {
|
||||||
let mut f0: BigUint = Zero::zero();
|
let mut f0: BigUint = Zero::zero();
|
||||||
let mut f1: BigUint = One::one();
|
let mut f1: BigUint = One::one();
|
||||||
for _ in 0..n {
|
for _ in 0..n {
|
||||||
f1 += &f0;
|
f1 = f1 + &f0;
|
||||||
f0 = &f1 - f0;
|
f0 = &f1 - f0;
|
||||||
}
|
}
|
||||||
f0
|
f0
|
||||||
|
@ -109,11 +112,6 @@ fn divide_2(b: &mut Bencher) {
|
||||||
divide_bench(b, 1 << 16, 1 << 12);
|
divide_bench(b, 1 << 16, 1 << 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn divide_big_little(b: &mut Bencher) {
|
|
||||||
divide_bench(b, 1 << 16, 1 << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn remainder_0(b: &mut Bencher) {
|
fn remainder_0(b: &mut Bencher) {
|
||||||
remainder_bench(b, 1 << 8, 1 << 6);
|
remainder_bench(b, 1 << 8, 1 << 6);
|
||||||
|
@ -129,11 +127,6 @@ fn remainder_2(b: &mut Bencher) {
|
||||||
remainder_bench(b, 1 << 16, 1 << 12);
|
remainder_bench(b, 1 << 16, 1 << 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn remainder_big_little(b: &mut Bencher) {
|
|
||||||
remainder_bench(b, 1 << 16, 1 << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn factorial_100(b: &mut Bencher) {
|
fn factorial_100(b: &mut Bencher) {
|
||||||
b.iter(|| factorial(100));
|
b.iter(|| factorial(100));
|
||||||
|
@ -245,7 +238,7 @@ fn from_str_radix_36(b: &mut Bencher) {
|
||||||
from_str_radix_bench(b, 36);
|
from_str_radix_bench(b, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rand_bench(b: &mut Bencher, bits: u64) {
|
fn rand_bench(b: &mut Bencher, bits: usize) {
|
||||||
let mut rng = get_rng();
|
let mut rng = get_rng();
|
||||||
|
|
||||||
b.iter(|| rng.gen_bigint(bits));
|
b.iter(|| rng.gen_bigint(bits));
|
||||||
|
@ -293,24 +286,22 @@ fn rand_131072(b: &mut Bencher) {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn shl(b: &mut Bencher) {
|
fn shl(b: &mut Bencher) {
|
||||||
let n = BigUint::one() << 1000u32;
|
let n = BigUint::one() << 1000;
|
||||||
let mut m = n.clone();
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
m.clone_from(&n);
|
let mut m = n.clone();
|
||||||
for i in 0..50 {
|
for i in 0..50 {
|
||||||
m <<= i;
|
m = m << i;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn shr(b: &mut Bencher) {
|
fn shr(b: &mut Bencher) {
|
||||||
let n = BigUint::one() << 2000u32;
|
let n = BigUint::one() << 2000;
|
||||||
let mut m = n.clone();
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
m.clone_from(&n);
|
let mut m = n.clone();
|
||||||
for i in 0..50 {
|
for i in 0..50 {
|
||||||
m >>= i;
|
m = m >> i;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -329,49 +320,31 @@ fn hash(b: &mut Bencher) {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn pow_bench(b: &mut Bencher) {
|
fn pow_bench(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let upper = 100_u32;
|
let upper = 100_usize;
|
||||||
let mut i_big = BigUint::from(1u32);
|
for i in 2..upper + 1 {
|
||||||
for _i in 2..=upper {
|
for j in 2..upper + 1 {
|
||||||
i_big += 1u32;
|
let i_big = BigUint::from_usize(i).unwrap();
|
||||||
for j in 2..=upper {
|
|
||||||
i_big.pow(j);
|
i_big.pow(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn pow_bench_bigexp(b: &mut Bencher) {
|
|
||||||
use num_traits::Pow;
|
|
||||||
|
|
||||||
b.iter(|| {
|
|
||||||
let upper = 100_u32;
|
|
||||||
let mut i_big = BigUint::from(1u32);
|
|
||||||
for _i in 2..=upper {
|
|
||||||
i_big += 1u32;
|
|
||||||
let mut j_big = BigUint::from(1u32);
|
|
||||||
for _j in 2..=upper {
|
|
||||||
j_big += 1u32;
|
|
||||||
Pow::pow(&i_big, &j_big);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This modulus is the prime from the 2048-bit MODP DH group:
|
/// This modulus is the prime from the 2048-bit MODP DH group:
|
||||||
/// https://tools.ietf.org/html/rfc3526#section-3
|
/// https://tools.ietf.org/html/rfc3526#section-3
|
||||||
const RFC3526_2048BIT_MODP_GROUP: &str = "\
|
const RFC3526_2048BIT_MODP_GROUP: &'static str =
|
||||||
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
"\
|
||||||
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
||||||
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
||||||
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
||||||
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
||||||
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
||||||
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
||||||
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
||||||
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
||||||
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
||||||
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
||||||
|
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn modpow(b: &mut Bencher) {
|
fn modpow(b: &mut Bencher) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![cfg(feature = "rand")]
|
#![cfg(feature = "rand")]
|
||||||
|
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
extern crate rand;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use num_bigint::{BigUint, RandBigInt};
|
use num_bigint::{BigUint, RandBigInt};
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
use rand::rngs::StdRng;
|
use rand::{SeedableRng, StdRng};
|
||||||
use rand::SeedableRng;
|
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
fn get_rng() -> StdRng {
|
fn get_rng() -> StdRng {
|
||||||
|
@ -18,7 +21,7 @@ fn get_rng() -> StdRng {
|
||||||
SeedableRng::from_seed(seed)
|
SeedableRng::from_seed(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench(b: &mut Bencher, bits: u64, gcd: fn(&BigUint, &BigUint) -> BigUint) {
|
fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
|
||||||
let mut rng = get_rng();
|
let mut rng = get_rng();
|
||||||
let x = rng.gen_biguint(bits);
|
let x = rng.gen_biguint(bits);
|
||||||
let y = rng.gen_biguint(bits);
|
let y = rng.gen_biguint(bits);
|
||||||
|
@ -37,7 +40,7 @@ fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
|
||||||
m = n % &temp;
|
m = n % &temp;
|
||||||
n = temp;
|
n = temp;
|
||||||
}
|
}
|
||||||
n
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![cfg(feature = "rand")]
|
#![cfg(feature = "rand")]
|
||||||
|
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
|
extern crate rand;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use num_bigint::{BigUint, RandBigInt};
|
use num_bigint::{BigUint, RandBigInt};
|
||||||
use rand::rngs::StdRng;
|
use num_traits::Pow;
|
||||||
use rand::SeedableRng;
|
use rand::{SeedableRng, StdRng};
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
// The `big64` cases demonstrate the speed of cases where the value
|
// The `big64` cases demonstrate the speed of cases where the value
|
||||||
|
@ -43,7 +46,7 @@ fn check(x: &BigUint, n: u32) {
|
||||||
assert_eq!((&hi - 1u32).nth_root(n), root);
|
assert_eq!((&hi - 1u32).nth_root(n), root);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_sqrt(b: &mut Bencher, bits: u64) {
|
fn bench_sqrt(b: &mut Bencher, bits: usize) {
|
||||||
let x = get_rng().gen_biguint(bits);
|
let x = get_rng().gen_biguint(bits);
|
||||||
eprintln!("bench_sqrt({})", x);
|
eprintln!("bench_sqrt({})", x);
|
||||||
|
|
||||||
|
@ -71,7 +74,7 @@ fn big4k_sqrt(b: &mut Bencher) {
|
||||||
bench_sqrt(b, 4096);
|
bench_sqrt(b, 4096);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_cbrt(b: &mut Bencher, bits: u64) {
|
fn bench_cbrt(b: &mut Bencher, bits: usize) {
|
||||||
let x = get_rng().gen_biguint(bits);
|
let x = get_rng().gen_biguint(bits);
|
||||||
eprintln!("bench_cbrt({})", x);
|
eprintln!("bench_cbrt({})", x);
|
||||||
|
|
||||||
|
@ -99,7 +102,7 @@ fn big4k_cbrt(b: &mut Bencher) {
|
||||||
bench_cbrt(b, 4096);
|
bench_cbrt(b, 4096);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_nth_root(b: &mut Bencher, bits: u64, n: u32) {
|
fn bench_nth_root(b: &mut Bencher, bits: usize, n: u32) {
|
||||||
let x = get_rng().gen_biguint(bits);
|
let x = get_rng().gen_biguint(bits);
|
||||||
eprintln!("bench_{}th_root({})", n, x);
|
eprintln!("bench_{}th_root({})", n, x);
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,10 @@
|
||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -94,7 +98,7 @@ fn pidigits(n: isize, out: &mut dyn io::Write) -> io::Result<()> {
|
||||||
let mut k = 0;
|
let mut k = 0;
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
|
|
||||||
for i in 1..=n {
|
for i in 1..(n + 1) {
|
||||||
let mut d;
|
let mut d;
|
||||||
loop {
|
loop {
|
||||||
k += 1;
|
k += 1;
|
||||||
|
@ -107,7 +111,7 @@ fn pidigits(n: isize, out: &mut dyn io::Write) -> io::Result<()> {
|
||||||
|
|
||||||
write!(out, "{}", d)?;
|
write!(out, "{}", d)?;
|
||||||
if i % 10 == 0 {
|
if i % 10 == 0 {
|
||||||
writeln!(out, "\t:{}", i)?;
|
write!(out, "\t:{}\n", i)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.eliminate_digit(d);
|
context.eliminate_digit(d);
|
||||||
|
@ -118,7 +122,7 @@ fn pidigits(n: isize, out: &mut dyn io::Write) -> io::Result<()> {
|
||||||
for _ in m..10 {
|
for _ in m..10 {
|
||||||
write!(out, " ")?;
|
write!(out, " ")?;
|
||||||
}
|
}
|
||||||
writeln!(out, "\t:{}", n)?;
|
write!(out, "\t:{}\n", n)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +1,14 @@
|
||||||
|
extern crate autocfg;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH");
|
|
||||||
if pointer_width.as_ref().map(String::as_str) == Ok("64") {
|
|
||||||
autocfg::emit("u64_digit");
|
|
||||||
}
|
|
||||||
let ac = autocfg::new();
|
let ac = autocfg::new();
|
||||||
if ac.probe_path("std::convert::TryFrom") || ac.probe_path("core::convert::TryFrom") {
|
if ac.probe_type("i128") {
|
||||||
autocfg::emit("has_try_from");
|
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("build.rs");
|
autocfg::rerun_path(file!());
|
||||||
|
|
||||||
write_radix_bases().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write tables of the greatest power of each radix for the given bit size. These are returned
|
|
||||||
/// from `biguint::get_radix_base` to batch the multiplication/division of radix conversions on
|
|
||||||
/// full `BigUint` values, operating on primitive integers as much as possible.
|
|
||||||
///
|
|
||||||
/// e.g. BASES_16[3] = (59049, 10) // 3¹⁰ fits in u16, but 3¹¹ is too big
|
|
||||||
/// BASES_32[3] = (3486784401, 20)
|
|
||||||
/// BASES_64[3] = (12157665459056928801, 40)
|
|
||||||
///
|
|
||||||
/// Powers of two are not included, just zeroed, as they're implemented with shifts.
|
|
||||||
fn write_radix_bases() -> Result<(), Box<dyn Error>> {
|
|
||||||
let out_dir = env::var("OUT_DIR")?;
|
|
||||||
let dest_path = Path::new(&out_dir).join("radix_bases.rs");
|
|
||||||
let mut f = File::create(&dest_path)?;
|
|
||||||
|
|
||||||
for &bits in &[16, 32, 64] {
|
|
||||||
let max = if bits < 64 {
|
|
||||||
(1 << bits) - 1
|
|
||||||
} else {
|
|
||||||
std::u64::MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
writeln!(f, "#[deny(overflowing_literals)]")?;
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"pub(crate) static BASES_{bits}: [(u{bits}, usize); 257] = [",
|
|
||||||
bits = bits
|
|
||||||
)?;
|
|
||||||
for radix in 0u64..257 {
|
|
||||||
let (base, power) = if radix == 0 || radix.is_power_of_two() {
|
|
||||||
(0, 0)
|
|
||||||
} else {
|
|
||||||
let mut power = 1;
|
|
||||||
let mut base = radix;
|
|
||||||
|
|
||||||
while let Some(b) = base.checked_mul(radix) {
|
|
||||||
if b > max {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
base = b;
|
|
||||||
power += 1;
|
|
||||||
}
|
|
||||||
(base, power)
|
|
||||||
};
|
|
||||||
writeln!(f, " ({}, {}), // {}", base, power, radix)?;
|
|
||||||
}
|
|
||||||
writeln!(f, "];")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use crate::std_alloc::{Cow, Vec};
|
use std::borrow::Cow;
|
||||||
use core::cmp;
|
use std::cmp;
|
||||||
use core::cmp::Ordering::{self, Equal, Greater, Less};
|
use std::cmp::Ordering::{self, Equal, Greater, Less};
|
||||||
use core::iter::repeat;
|
use std::iter::repeat;
|
||||||
use core::mem;
|
use std::mem;
|
||||||
use num_traits::{One, PrimInt, Zero};
|
use traits;
|
||||||
|
use traits::{One, Zero};
|
||||||
|
|
||||||
use crate::biguint::biguint_from_vec;
|
use biguint::BigUint;
|
||||||
use crate::biguint::BigUint;
|
|
||||||
|
|
||||||
use crate::bigint::BigInt;
|
use bigint::BigInt;
|
||||||
use crate::bigint::Sign;
|
use bigint::Sign;
|
||||||
use crate::bigint::Sign::{Minus, NoSign, Plus};
|
use bigint::Sign::{Minus, NoSign, Plus};
|
||||||
|
|
||||||
use crate::big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit};
|
use big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit};
|
||||||
|
|
||||||
// Generic functions for add/subtract/multiply with carry/borrow:
|
// Generic functions for add/subtract/multiply with carry/borrow:
|
||||||
|
|
||||||
|
@ -37,12 +37,7 @@ fn sbb(a: BigDigit, b: BigDigit, acc: &mut SignedDoubleBigDigit) -> BigDigit {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn mac_with_carry(
|
pub fn mac_with_carry(a: BigDigit, b: BigDigit, c: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
|
||||||
a: BigDigit,
|
|
||||||
b: BigDigit,
|
|
||||||
c: BigDigit,
|
|
||||||
acc: &mut DoubleBigDigit,
|
|
||||||
) -> BigDigit {
|
|
||||||
*acc += DoubleBigDigit::from(a);
|
*acc += DoubleBigDigit::from(a);
|
||||||
*acc += DoubleBigDigit::from(b) * DoubleBigDigit::from(c);
|
*acc += DoubleBigDigit::from(b) * DoubleBigDigit::from(c);
|
||||||
let lo = *acc as BigDigit;
|
let lo = *acc as BigDigit;
|
||||||
|
@ -51,7 +46,7 @@ pub(crate) fn mac_with_carry(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn mul_with_carry(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
|
pub fn mul_with_carry(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
|
||||||
*acc += DoubleBigDigit::from(a) * DoubleBigDigit::from(b);
|
*acc += DoubleBigDigit::from(a) * DoubleBigDigit::from(b);
|
||||||
let lo = *acc as BigDigit;
|
let lo = *acc as BigDigit;
|
||||||
*acc >>= big_digit::BITS;
|
*acc >>= big_digit::BITS;
|
||||||
|
@ -73,67 +68,31 @@ fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigi
|
||||||
((lhs / rhs) as BigDigit, (lhs % rhs) as BigDigit)
|
((lhs / rhs) as BigDigit, (lhs % rhs) as BigDigit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For small divisors, we can divide without promoting to `DoubleBigDigit` by
|
pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
|
||||||
/// using half-size pieces of digit, like long-division.
|
|
||||||
#[inline]
|
|
||||||
fn div_half(rem: BigDigit, digit: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigit) {
|
|
||||||
use crate::big_digit::{HALF, HALF_BITS};
|
|
||||||
use num_integer::Integer;
|
|
||||||
|
|
||||||
debug_assert!(rem < divisor && divisor <= HALF);
|
|
||||||
let (hi, rem) = ((rem << HALF_BITS) | (digit >> HALF_BITS)).div_rem(&divisor);
|
|
||||||
let (lo, rem) = ((rem << HALF_BITS) | (digit & HALF)).div_rem(&divisor);
|
|
||||||
((hi << HALF_BITS) | lo, rem)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
|
|
||||||
let mut rem = 0;
|
let mut rem = 0;
|
||||||
|
|
||||||
if b <= big_digit::HALF {
|
for d in a.data.iter_mut().rev() {
|
||||||
for d in a.data.iter_mut().rev() {
|
let (q, r) = div_wide(rem, *d, b);
|
||||||
let (q, r) = div_half(rem, *d, b);
|
*d = q;
|
||||||
*d = q;
|
rem = r;
|
||||||
rem = r;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for d in a.data.iter_mut().rev() {
|
|
||||||
let (q, r) = div_wide(rem, *d, b);
|
|
||||||
*d = q;
|
|
||||||
rem = r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(a.normalized(), rem)
|
(a.normalized(), rem)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
|
||||||
pub(crate) fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
|
let mut rem: DoubleBigDigit = 0;
|
||||||
let mut rem = 0;
|
for &digit in a.data.iter().rev() {
|
||||||
|
rem = (rem << big_digit::BITS) + DoubleBigDigit::from(digit);
|
||||||
if b <= big_digit::HALF {
|
rem %= DoubleBigDigit::from(b);
|
||||||
for &digit in a.data.iter().rev() {
|
|
||||||
let (_, r) = div_half(rem, digit, b);
|
|
||||||
rem = r;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for &digit in a.data.iter().rev() {
|
|
||||||
let (_, r) = div_wide(rem, digit, b);
|
|
||||||
rem = r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rem
|
rem as BigDigit
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Two argument addition of raw slices, `a += b`, returning the carry.
|
// Only for the Add impl:
|
||||||
///
|
|
||||||
/// This is used when the data `Vec` might need to resize to push a non-zero carry, so we perform
|
|
||||||
/// the addition first hoping that it will fit.
|
|
||||||
///
|
|
||||||
/// The caller _must_ ensure that `a` is at least as long as `b`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
pub fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
||||||
debug_assert!(a.len() >= b.len());
|
debug_assert!(a.len() >= b.len());
|
||||||
|
|
||||||
let mut carry = 0;
|
let mut carry = 0;
|
||||||
|
@ -160,13 +119,13 @@ pub(crate) fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
||||||
///
|
///
|
||||||
/// The caller _must_ ensure that a is big enough to store the result - typically this means
|
/// The caller _must_ ensure that a is big enough to store the result - typically this means
|
||||||
/// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry.
|
/// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry.
|
||||||
pub(crate) fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
|
pub fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
|
||||||
let carry = __add2(a, b);
|
let carry = __add2(a, b);
|
||||||
|
|
||||||
debug_assert!(carry == 0);
|
debug_assert!(carry == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
pub fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
||||||
let mut borrow = 0;
|
let mut borrow = 0;
|
||||||
|
|
||||||
let len = cmp::min(a.len(), b.len());
|
let len = cmp::min(a.len(), b.len());
|
||||||
|
@ -195,7 +154,7 @@ pub(crate) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
||||||
|
|
||||||
// Only for the Sub impl. `a` and `b` must have same length.
|
// Only for the Sub impl. `a` and `b` must have same length.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> BigDigit {
|
pub fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> BigDigit {
|
||||||
debug_assert!(b.len() == a.len());
|
debug_assert!(b.len() == a.len());
|
||||||
|
|
||||||
let mut borrow = 0;
|
let mut borrow = 0;
|
||||||
|
@ -207,7 +166,7 @@ pub(crate) fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> BigDigit {
|
||||||
borrow as BigDigit
|
borrow as BigDigit
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
|
pub fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
|
||||||
debug_assert!(b.len() >= a.len());
|
debug_assert!(b.len() >= a.len());
|
||||||
|
|
||||||
let len = cmp::min(a.len(), b.len());
|
let len = cmp::min(a.len(), b.len());
|
||||||
|
@ -225,7 +184,7 @@ pub(crate) fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
pub fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
||||||
// Normalize:
|
// Normalize:
|
||||||
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
||||||
let b = &b[..b.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
let b = &b[..b.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
||||||
|
@ -234,12 +193,12 @@ pub(crate) fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
||||||
Greater => {
|
Greater => {
|
||||||
let mut a = a.to_vec();
|
let mut a = a.to_vec();
|
||||||
sub2(&mut a, b);
|
sub2(&mut a, b);
|
||||||
(Plus, biguint_from_vec(a))
|
(Plus, BigUint::new(a))
|
||||||
}
|
}
|
||||||
Less => {
|
Less => {
|
||||||
let mut b = b.to_vec();
|
let mut b = b.to_vec();
|
||||||
sub2(&mut b, a);
|
sub2(&mut b, a);
|
||||||
(Minus, biguint_from_vec(b))
|
(Minus, BigUint::new(b))
|
||||||
}
|
}
|
||||||
_ => (NoSign, Zero::zero()),
|
_ => (NoSign, Zero::zero()),
|
||||||
}
|
}
|
||||||
|
@ -247,7 +206,7 @@ pub(crate) fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
||||||
|
|
||||||
/// Three argument multiply accumulate:
|
/// Three argument multiply accumulate:
|
||||||
/// acc += b * c
|
/// acc += b * c
|
||||||
pub(crate) fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
|
pub fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
|
||||||
if c == 0 {
|
if c == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -266,10 +225,6 @@ pub(crate) fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bigint_from_slice(slice: &[BigDigit]) -> BigInt {
|
|
||||||
BigInt::from(biguint_from_vec(slice.to_vec()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Three argument multiply accumulate:
|
/// Three argument multiply accumulate:
|
||||||
/// acc += b * c
|
/// acc += b * c
|
||||||
fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
||||||
|
@ -432,14 +387,14 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
||||||
// in place of multiplications.
|
// in place of multiplications.
|
||||||
//
|
//
|
||||||
// x(t) = x2*t^2 + x1*t + x0
|
// x(t) = x2*t^2 + x1*t + x0
|
||||||
let x0 = bigint_from_slice(&x[..x0_len]);
|
let x0 = BigInt::from_slice(Plus, &x[..x0_len]);
|
||||||
let x1 = bigint_from_slice(&x[x0_len..x0_len + x1_len]);
|
let x1 = BigInt::from_slice(Plus, &x[x0_len..x0_len + x1_len]);
|
||||||
let x2 = bigint_from_slice(&x[x0_len + x1_len..]);
|
let x2 = BigInt::from_slice(Plus, &x[x0_len + x1_len..]);
|
||||||
|
|
||||||
// y(t) = y2*t^2 + y1*t + y0
|
// y(t) = y2*t^2 + y1*t + y0
|
||||||
let y0 = bigint_from_slice(&y[..y0_len]);
|
let y0 = BigInt::from_slice(Plus, &y[..y0_len]);
|
||||||
let y1 = bigint_from_slice(&y[y0_len..y0_len + y1_len]);
|
let y1 = BigInt::from_slice(Plus, &y[y0_len..y0_len + y1_len]);
|
||||||
let y2 = bigint_from_slice(&y[y0_len + y1_len..]);
|
let y2 = BigInt::from_slice(Plus, &y[y0_len + y1_len..]);
|
||||||
|
|
||||||
// Let w(t) = x(t) * y(t)
|
// Let w(t) = x(t) * y(t)
|
||||||
//
|
//
|
||||||
|
@ -515,24 +470,23 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
||||||
let mut comp1: BigInt = (r1 - &r2) / 2;
|
let mut comp1: BigInt = (r1 - &r2) / 2;
|
||||||
let mut comp2: BigInt = r2 - &r0;
|
let mut comp2: BigInt = r2 - &r0;
|
||||||
comp3 = (&comp2 - comp3) / 2 + &r4 * 2;
|
comp3 = (&comp2 - comp3) / 2 + &r4 * 2;
|
||||||
comp2 += &comp1 - &r4;
|
comp2 = comp2 + &comp1 - &r4;
|
||||||
comp1 -= &comp3;
|
comp1 = comp1 - &comp3;
|
||||||
|
|
||||||
// Recomposition. The coefficients of the polynomial are now known.
|
// Recomposition. The coefficients of the polynomial are now known.
|
||||||
//
|
//
|
||||||
// Evaluate at w(t) where t is our given base to get the result.
|
// Evaluate at w(t) where t is our given base to get the result.
|
||||||
let bits = u64::from(big_digit::BITS) * i as u64;
|
|
||||||
let result = r0
|
let result = r0
|
||||||
+ (comp1 << bits)
|
+ (comp1 << 32 * i)
|
||||||
+ (comp2 << (2 * bits))
|
+ (comp2 << 2 * 32 * i)
|
||||||
+ (comp3 << (3 * bits))
|
+ (comp3 << 3 * 32 * i)
|
||||||
+ (r4 << (4 * bits));
|
+ (r4 << 4 * 32 * i);
|
||||||
let result_pos = result.to_biguint().unwrap();
|
let result_pos = result.to_biguint().unwrap();
|
||||||
add2(&mut acc[..], &result_pos.data);
|
add2(&mut acc[..], &result_pos.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
||||||
let len = x.len() + y.len() + 1;
|
let len = x.len() + y.len() + 1;
|
||||||
let mut prod = BigUint { data: vec![0; len] };
|
let mut prod = BigUint { data: vec![0; len] };
|
||||||
|
|
||||||
|
@ -540,7 +494,7 @@ pub(crate) fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
||||||
prod.normalized()
|
prod.normalized()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
|
pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
|
||||||
let mut carry = 0;
|
let mut carry = 0;
|
||||||
for a in a.iter_mut() {
|
for a in a.iter_mut() {
|
||||||
*a = mul_with_carry(*a, b, &mut carry);
|
*a = mul_with_carry(*a, b, &mut carry);
|
||||||
|
@ -548,9 +502,9 @@ pub(crate) fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
|
||||||
carry as BigDigit
|
carry as BigDigit
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn div_rem(mut u: BigUint, mut d: BigUint) -> (BigUint, BigUint) {
|
pub fn div_rem(mut u: BigUint, mut d: BigUint) -> (BigUint, BigUint) {
|
||||||
if d.is_zero() {
|
if d.is_zero() {
|
||||||
panic!("attempt to divide by zero")
|
panic!()
|
||||||
}
|
}
|
||||||
if u.is_zero() {
|
if u.is_zero() {
|
||||||
return (Zero::zero(), Zero::zero());
|
return (Zero::zero(), Zero::zero());
|
||||||
|
@ -584,7 +538,6 @@ pub(crate) fn div_rem(mut u: BigUint, mut d: BigUint) -> (BigUint, BigUint) {
|
||||||
// want it to be the largest number we can efficiently divide by.
|
// want it to be the largest number we can efficiently divide by.
|
||||||
//
|
//
|
||||||
let shift = d.data.last().unwrap().leading_zeros() as usize;
|
let shift = d.data.last().unwrap().leading_zeros() as usize;
|
||||||
|
|
||||||
let (q, r) = if shift == 0 {
|
let (q, r) = if shift == 0 {
|
||||||
// no need to clone d
|
// no need to clone d
|
||||||
div_rem_core(u, &d)
|
div_rem_core(u, &d)
|
||||||
|
@ -595,9 +548,9 @@ pub(crate) fn div_rem(mut u: BigUint, mut d: BigUint) -> (BigUint, BigUint) {
|
||||||
(q, r >> shift)
|
(q, r >> shift)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn div_rem_ref(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
pub fn div_rem_ref(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
||||||
if d.is_zero() {
|
if d.is_zero() {
|
||||||
panic!("attempt to divide by zero")
|
panic!()
|
||||||
}
|
}
|
||||||
if u.is_zero() {
|
if u.is_zero() {
|
||||||
return (Zero::zero(), Zero::zero());
|
return (Zero::zero(), Zero::zero());
|
||||||
|
@ -702,8 +655,9 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
|
||||||
let mut prod = b * &q0;
|
let mut prod = b * &q0;
|
||||||
|
|
||||||
while cmp_slice(&prod.data[..], &a.data[j..]) == Greater {
|
while cmp_slice(&prod.data[..], &a.data[j..]) == Greater {
|
||||||
q0 -= 1u32;
|
let one: BigUint = One::one();
|
||||||
prod -= b;
|
q0 = q0 - one;
|
||||||
|
prod = prod - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
add2(&mut q.data[j..], &q0.data[..]);
|
add2(&mut q.data[j..], &q0.data[..]);
|
||||||
|
@ -713,53 +667,41 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
|
||||||
tmp = q0;
|
tmp = q0;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(a < *b);
|
debug_assert!(&a < b);
|
||||||
|
|
||||||
(q.normalized(), a)
|
(q.normalized(), a)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find last set bit
|
/// Find last set bit
|
||||||
/// fls(0) == 0, fls(u32::MAX) == 32
|
/// fls(0) == 0, fls(u32::MAX) == 32
|
||||||
pub(crate) fn fls<T: PrimInt>(v: T) -> u8 {
|
pub fn fls<T: traits::PrimInt>(v: T) -> usize {
|
||||||
mem::size_of::<T>() as u8 * 8 - v.leading_zeros() as u8
|
mem::size_of::<T>() * 8 - v.leading_zeros() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ilog2<T: PrimInt>(v: T) -> u8 {
|
pub fn ilog2<T: traits::PrimInt>(v: T) -> usize {
|
||||||
fls(v) - 1
|
fls(v) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn biguint_shl<T: PrimInt>(n: Cow<'_, BigUint>, shift: T) -> BigUint {
|
pub fn biguint_shl(n: Cow<BigUint>, bits: usize) -> BigUint {
|
||||||
if shift < T::zero() {
|
let n_unit = bits / big_digit::BITS;
|
||||||
panic!("attempt to shift left with negative");
|
let mut data = match n_unit {
|
||||||
}
|
|
||||||
if n.is_zero() {
|
|
||||||
return n.into_owned();
|
|
||||||
}
|
|
||||||
let bits = T::from(big_digit::BITS).unwrap();
|
|
||||||
let digits = (shift / bits).to_usize().expect("capacity overflow");
|
|
||||||
let shift = (shift % bits).to_u8().unwrap();
|
|
||||||
biguint_shl2(n, digits, shift)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn biguint_shl2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
|
|
||||||
let mut data = match digits {
|
|
||||||
0 => n.into_owned().data,
|
0 => n.into_owned().data,
|
||||||
_ => {
|
_ => {
|
||||||
let len = digits.saturating_add(n.data.len() + 1);
|
let len = n_unit + n.data.len() + 1;
|
||||||
let mut data = Vec::with_capacity(len);
|
let mut data = Vec::with_capacity(len);
|
||||||
data.extend(repeat(0).take(digits));
|
data.extend(repeat(0).take(n_unit));
|
||||||
data.extend(n.data.iter());
|
data.extend(n.data.iter().cloned());
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if shift > 0 {
|
let n_bits = bits % big_digit::BITS;
|
||||||
|
if n_bits > 0 {
|
||||||
let mut carry = 0;
|
let mut carry = 0;
|
||||||
let carry_shift = big_digit::BITS as u8 - shift;
|
for elem in data[n_unit..].iter_mut() {
|
||||||
for elem in data[digits..].iter_mut() {
|
let new_carry = *elem >> (big_digit::BITS - n_bits);
|
||||||
let new_carry = *elem >> carry_shift;
|
*elem = (*elem << n_bits) | carry;
|
||||||
*elem = (*elem << shift) | carry;
|
|
||||||
carry = new_carry;
|
carry = new_carry;
|
||||||
}
|
}
|
||||||
if carry != 0 {
|
if carry != 0 {
|
||||||
|
@ -767,65 +709,65 @@ fn biguint_shl2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
biguint_from_vec(data)
|
BigUint::new(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn biguint_shr<T: PrimInt>(n: Cow<'_, BigUint>, shift: T) -> BigUint {
|
pub fn biguint_shr(n: Cow<BigUint>, bits: usize) -> BigUint {
|
||||||
if shift < T::zero() {
|
let n_unit = bits / big_digit::BITS;
|
||||||
panic!("attempt to shift right with negative");
|
if n_unit >= n.data.len() {
|
||||||
}
|
return Zero::zero();
|
||||||
if n.is_zero() {
|
|
||||||
return n.into_owned();
|
|
||||||
}
|
|
||||||
let bits = T::from(big_digit::BITS).unwrap();
|
|
||||||
let digits = (shift / bits).to_usize().unwrap_or(core::usize::MAX);
|
|
||||||
let shift = (shift % bits).to_u8().unwrap();
|
|
||||||
biguint_shr2(n, digits, shift)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn biguint_shr2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
|
|
||||||
if digits >= n.data.len() {
|
|
||||||
let mut n = n.into_owned();
|
|
||||||
n.set_zero();
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
let mut data = match n {
|
let mut data = match n {
|
||||||
Cow::Borrowed(n) => n.data[digits..].to_vec(),
|
Cow::Borrowed(n) => n.data[n_unit..].to_vec(),
|
||||||
Cow::Owned(mut n) => {
|
Cow::Owned(mut n) => {
|
||||||
n.data.drain(..digits);
|
n.data.drain(..n_unit);
|
||||||
n.data
|
n.data
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if shift > 0 {
|
let n_bits = bits % big_digit::BITS;
|
||||||
|
if n_bits > 0 {
|
||||||
let mut borrow = 0;
|
let mut borrow = 0;
|
||||||
let borrow_shift = big_digit::BITS as u8 - shift;
|
|
||||||
for elem in data.iter_mut().rev() {
|
for elem in data.iter_mut().rev() {
|
||||||
let new_borrow = *elem << borrow_shift;
|
let new_borrow = *elem << (big_digit::BITS - n_bits);
|
||||||
*elem = (*elem >> shift) | borrow;
|
*elem = (*elem >> n_bits) | borrow;
|
||||||
borrow = new_borrow;
|
borrow = new_borrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
biguint_from_vec(data)
|
BigUint::new(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
|
pub fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
|
||||||
debug_assert!(a.last() != Some(&0));
|
debug_assert!(a.last() != Some(&0));
|
||||||
debug_assert!(b.last() != Some(&0));
|
debug_assert!(b.last() != Some(&0));
|
||||||
|
|
||||||
match Ord::cmp(&a.len(), &b.len()) {
|
let (a_len, b_len) = (a.len(), b.len());
|
||||||
Equal => Iterator::cmp(a.iter().rev(), b.iter().rev()),
|
if a_len < b_len {
|
||||||
other => other,
|
return Less;
|
||||||
}
|
}
|
||||||
|
if a_len > b_len {
|
||||||
|
return Greater;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (&ai, &bi) in a.iter().rev().zip(b.iter().rev()) {
|
||||||
|
if ai < bi {
|
||||||
|
return Less;
|
||||||
|
}
|
||||||
|
if ai > bi {
|
||||||
|
return Greater;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Equal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod algorithm_tests {
|
mod algorithm_tests {
|
||||||
use crate::big_digit::BigDigit;
|
use big_digit::BigDigit;
|
||||||
use crate::{BigInt, BigUint};
|
use traits::Num;
|
||||||
use num_traits::Num;
|
use Sign::Plus;
|
||||||
|
use {BigInt, BigUint};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sub_sign() {
|
fn test_sub_sign() {
|
||||||
|
@ -838,8 +780,8 @@ mod algorithm_tests {
|
||||||
|
|
||||||
let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap();
|
let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap();
|
||||||
let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap();
|
let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap();
|
||||||
let a_i = BigInt::from(a.clone());
|
let a_i = BigInt::from_biguint(Plus, a.clone());
|
||||||
let b_i = BigInt::from(b.clone());
|
let b_i = BigInt::from_biguint(Plus, b.clone());
|
||||||
|
|
||||||
assert_eq!(sub_sign_i(&a.data[..], &b.data[..]), &a_i - &b_i);
|
assert_eq!(sub_sign_i(&a.data[..], &b.data[..]), &a_i - &b_i);
|
||||||
assert_eq!(sub_sign_i(&b.data[..], &a.data[..]), &b_i - &a_i);
|
assert_eq!(sub_sign_i(&b.data[..], &a.data[..]), &b_i - &a_i);
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,27 +1,25 @@
|
||||||
//! Randomization of big integers
|
//! Randomization of big integers
|
||||||
|
|
||||||
use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
|
use rand::distributions::uniform::{SampleUniform, UniformSampler};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use rand::AsByteSliceMut;
|
||||||
|
|
||||||
use crate::BigInt;
|
use BigInt;
|
||||||
use crate::BigUint;
|
use BigUint;
|
||||||
use crate::Sign::*;
|
use Sign::*;
|
||||||
|
|
||||||
use crate::bigint::{into_magnitude, magnitude};
|
use big_digit::BigDigit;
|
||||||
use crate::biguint::biguint_from_vec;
|
use bigint::{into_magnitude, magnitude};
|
||||||
|
|
||||||
use num_integer::Integer;
|
use integer::Integer;
|
||||||
use num_traits::{ToPrimitive, Zero};
|
use traits::Zero;
|
||||||
|
|
||||||
/// A trait for sampling random big integers.
|
|
||||||
///
|
|
||||||
/// The `rand` feature must be enabled to use this. See crate-level documentation for details.
|
|
||||||
pub trait RandBigInt {
|
pub trait RandBigInt {
|
||||||
/// Generate a random `BigUint` of the given bit size.
|
/// Generate a random `BigUint` of the given bit size.
|
||||||
fn gen_biguint(&mut self, bit_size: u64) -> BigUint;
|
fn gen_biguint(&mut self, bit_size: usize) -> BigUint;
|
||||||
|
|
||||||
/// Generate a random BigInt of the given bit size.
|
/// Generate a random BigInt of the given bit size.
|
||||||
fn gen_bigint(&mut self, bit_size: u64) -> BigInt;
|
fn gen_bigint(&mut self, bit_size: usize) -> BigInt;
|
||||||
|
|
||||||
/// Generate a random `BigUint` less than the given bound. Fails
|
/// Generate a random `BigUint` less than the given bound. Fails
|
||||||
/// when the bound is zero.
|
/// when the bound is zero.
|
||||||
|
@ -38,54 +36,24 @@ pub trait RandBigInt {
|
||||||
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
|
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_bits<R: Rng + ?Sized>(rng: &mut R, data: &mut [u32], rem: u64) {
|
|
||||||
// `fill` is faster than many `gen::<u32>` calls
|
|
||||||
rng.fill(data);
|
|
||||||
if rem > 0 {
|
|
||||||
let last = data.len() - 1;
|
|
||||||
data[last] >>= 32 - rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Rng + ?Sized> RandBigInt for R {
|
impl<R: Rng + ?Sized> RandBigInt for R {
|
||||||
#[cfg(not(u64_digit))]
|
fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
|
||||||
fn gen_biguint(&mut self, bit_size: u64) -> BigUint {
|
use super::big_digit::BITS;
|
||||||
let (digits, rem) = bit_size.div_rem(&32);
|
let (digits, rem) = bit_size.div_rem(&BITS);
|
||||||
let len = (digits + (rem > 0) as u64)
|
let mut data = vec![BigDigit::default(); digits + (rem > 0) as usize];
|
||||||
.to_usize()
|
// `fill_bytes` is faster than many `gen::<u32>` calls
|
||||||
.expect("capacity overflow");
|
self.fill_bytes(data[..].as_byte_slice_mut());
|
||||||
let mut data = vec![0u32; len];
|
// Swap bytes per the `Rng::fill` source. This might be
|
||||||
gen_bits(self, &mut data, rem);
|
// unnecessary if reproducibility across architectures is not
|
||||||
biguint_from_vec(data)
|
// desired.
|
||||||
|
data.to_le();
|
||||||
|
if rem > 0 {
|
||||||
|
data[digits] >>= BITS - rem;
|
||||||
|
}
|
||||||
|
BigUint::new(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(u64_digit)]
|
fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
|
||||||
fn gen_biguint(&mut self, bit_size: u64) -> BigUint {
|
|
||||||
use core::slice;
|
|
||||||
|
|
||||||
let (digits, rem) = bit_size.div_rem(&32);
|
|
||||||
let len = (digits + (rem > 0) as u64)
|
|
||||||
.to_usize()
|
|
||||||
.expect("capacity overflow");
|
|
||||||
let native_digits = bit_size.div_ceil(&64);
|
|
||||||
let native_len = native_digits.to_usize().expect("capacity overflow");
|
|
||||||
let mut data = vec![0u64; native_len];
|
|
||||||
unsafe {
|
|
||||||
// Generate bits in a `&mut [u32]` slice for value stability
|
|
||||||
let ptr = data.as_mut_ptr() as *mut u32;
|
|
||||||
debug_assert!(native_len * 2 >= len);
|
|
||||||
let data = slice::from_raw_parts_mut(ptr, len);
|
|
||||||
gen_bits(self, data, rem);
|
|
||||||
}
|
|
||||||
#[cfg(target_endian = "big")]
|
|
||||||
for digit in &mut data {
|
|
||||||
// swap u32 digits into u64 endianness
|
|
||||||
*digit = (*digit << 32) | (*digit >> 32);
|
|
||||||
}
|
|
||||||
biguint_from_vec(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_bigint(&mut self, bit_size: u64) -> BigInt {
|
|
||||||
loop {
|
loop {
|
||||||
// Generate a random BigUint...
|
// Generate a random BigUint...
|
||||||
let biguint = self.gen_biguint(bit_size);
|
let biguint = self.gen_biguint(bit_size);
|
||||||
|
@ -153,28 +121,16 @@ impl UniformSampler for UniformBigUint {
|
||||||
type X = BigUint;
|
type X = BigUint;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
|
fn new(low: Self::X, high: Self::X) -> Self {
|
||||||
where
|
|
||||||
B1: SampleBorrow<Self::X> + Sized,
|
|
||||||
B2: SampleBorrow<Self::X> + Sized,
|
|
||||||
{
|
|
||||||
let low = low_b.borrow();
|
|
||||||
let high = high_b.borrow();
|
|
||||||
assert!(low < high);
|
assert!(low < high);
|
||||||
UniformBigUint {
|
UniformBigUint {
|
||||||
len: high - low,
|
len: high - &low,
|
||||||
base: low.clone(),
|
base: low,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
|
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
|
||||||
where
|
|
||||||
B1: SampleBorrow<Self::X> + Sized,
|
|
||||||
B2: SampleBorrow<Self::X> + Sized,
|
|
||||||
{
|
|
||||||
let low = low_b.borrow();
|
|
||||||
let high = high_b.borrow();
|
|
||||||
assert!(low <= high);
|
assert!(low <= high);
|
||||||
Self::new(low, high + 1u32)
|
Self::new(low, high + 1u32)
|
||||||
}
|
}
|
||||||
|
@ -185,12 +141,8 @@ impl UniformSampler for UniformBigUint {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sample_single<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R) -> Self::X
|
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
|
||||||
where
|
rng.gen_biguint_range(&low, &high)
|
||||||
B1: SampleBorrow<Self::X> + Sized,
|
|
||||||
B2: SampleBorrow<Self::X> + Sized,
|
|
||||||
{
|
|
||||||
rng.gen_biguint_range(low.borrow(), high.borrow())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,28 +161,16 @@ impl UniformSampler for UniformBigInt {
|
||||||
type X = BigInt;
|
type X = BigInt;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
|
fn new(low: Self::X, high: Self::X) -> Self {
|
||||||
where
|
|
||||||
B1: SampleBorrow<Self::X> + Sized,
|
|
||||||
B2: SampleBorrow<Self::X> + Sized,
|
|
||||||
{
|
|
||||||
let low = low_b.borrow();
|
|
||||||
let high = high_b.borrow();
|
|
||||||
assert!(low < high);
|
assert!(low < high);
|
||||||
UniformBigInt {
|
UniformBigInt {
|
||||||
len: into_magnitude(high - low),
|
len: into_magnitude(high - &low),
|
||||||
base: low.clone(),
|
base: low,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
|
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
|
||||||
where
|
|
||||||
B1: SampleBorrow<Self::X> + Sized,
|
|
||||||
B2: SampleBorrow<Self::X> + Sized,
|
|
||||||
{
|
|
||||||
let low = low_b.borrow();
|
|
||||||
let high = high_b.borrow();
|
|
||||||
assert!(low <= high);
|
assert!(low <= high);
|
||||||
Self::new(low, high + 1u32)
|
Self::new(low, high + 1u32)
|
||||||
}
|
}
|
||||||
|
@ -241,12 +181,8 @@ impl UniformSampler for UniformBigInt {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sample_single<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R) -> Self::X
|
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
|
||||||
where
|
rng.gen_bigint_range(&low, &high)
|
||||||
B1: SampleBorrow<Self::X> + Sized,
|
|
||||||
B2: SampleBorrow<Self::X> + Sized,
|
|
||||||
{
|
|
||||||
rng.gen_bigint_range(low.borrow(), high.borrow())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,16 +191,14 @@ impl SampleUniform for BigInt {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A random distribution for `BigUint` and `BigInt` values of a particular bit size.
|
/// A random distribution for `BigUint` and `BigInt` values of a particular bit size.
|
||||||
///
|
|
||||||
/// The `rand` feature must be enabled to use this. See crate-level documentation for details.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct RandomBits {
|
pub struct RandomBits {
|
||||||
bits: u64,
|
bits: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RandomBits {
|
impl RandomBits {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(bits: u64) -> RandomBits {
|
pub fn new(bits: usize) -> RandomBits {
|
||||||
RandomBits { bits }
|
RandomBits { bits }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,6 +19,9 @@
|
||||||
//! ## Example
|
//! ## Example
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
|
//! extern crate num_bigint;
|
||||||
|
//! extern crate num_traits;
|
||||||
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! use num_bigint::BigUint;
|
//! use num_bigint::BigUint;
|
||||||
//! use num_traits::{Zero, One};
|
//! use num_traits::{Zero, One};
|
||||||
|
@ -43,8 +46,14 @@
|
||||||
//!
|
//!
|
||||||
//! It's easy to generate large random numbers:
|
//! It's easy to generate large random numbers:
|
||||||
//!
|
//!
|
||||||
//! ```rust,ignore
|
//! ```rust
|
||||||
//! use num_bigint::{ToBigInt, RandBigInt};
|
//! # #[cfg(feature = "rand")]
|
||||||
|
//! extern crate rand;
|
||||||
|
//! extern crate num_bigint as bigint;
|
||||||
|
//!
|
||||||
|
//! # #[cfg(feature = "rand")]
|
||||||
|
//! # fn main() {
|
||||||
|
//! use bigint::{ToBigInt, RandBigInt};
|
||||||
//!
|
//!
|
||||||
//! let mut rng = rand::thread_rng();
|
//! let mut rng = rand::thread_rng();
|
||||||
//! let a = rng.gen_bigint(1000);
|
//! let a = rng.gen_bigint(1000);
|
||||||
|
@ -55,67 +64,34 @@
|
||||||
//!
|
//!
|
||||||
//! // Probably an even larger number.
|
//! // Probably an even larger number.
|
||||||
//! println!("{}", a * b);
|
//! println!("{}", a * b);
|
||||||
|
//! # }
|
||||||
|
//!
|
||||||
|
//! # #[cfg(not(feature = "rand"))]
|
||||||
|
//! # fn main() {
|
||||||
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! See the "Features" section for instructions for enabling random number generation.
|
|
||||||
//!
|
|
||||||
//! ## Features
|
|
||||||
//!
|
|
||||||
//! The `std` crate feature is enabled by default, and is mandatory before Rust
|
|
||||||
//! 1.36 and the stabilized `alloc` crate. If you depend on `num-bigint` with
|
|
||||||
//! `default-features = false`, you must manually enable the `std` feature yourself
|
|
||||||
//! if your compiler is not new enough.
|
|
||||||
//!
|
|
||||||
//! ### Random Generation
|
|
||||||
//!
|
|
||||||
//! `num-bigint` supports the generation of random big integers when the `rand`
|
|
||||||
//! feature is enabled. To enable it include rand as
|
|
||||||
//!
|
|
||||||
//! ```toml
|
|
||||||
//! rand = "0.7"
|
|
||||||
//! num-bigint = { version = "0.3", features = ["rand"] }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Note that you must use the version of `rand` that `num-bigint` is compatible
|
|
||||||
//! with: `0.7`.
|
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! ## Compatibility
|
//! ## Compatibility
|
||||||
//!
|
//!
|
||||||
//! The `num-bigint` crate is tested for rustc 1.31 and greater.
|
//! The `num-bigint` crate is tested for rustc 1.15 and greater.
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/num-bigint/0.3")]
|
#![doc(html_root_url = "https://docs.rs/num-bigint/0.2")]
|
||||||
#![no_std]
|
// We don't actually support `no_std` yet, and probably won't until `alloc` is stable. We're just
|
||||||
|
// reserving this ability with the "std" feature now, and compilation will fail without.
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "rand")]
|
||||||
#[macro_use]
|
extern crate rand;
|
||||||
extern crate std;
|
#[cfg(feature = "serde")]
|
||||||
|
extern crate serde;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
extern crate num_integer as integer;
|
||||||
mod std_alloc {
|
extern crate num_traits as traits;
|
||||||
pub(crate) use std::borrow::Cow;
|
#[cfg(feature = "quickcheck")]
|
||||||
#[cfg(feature = "quickcheck")]
|
extern crate quickcheck;
|
||||||
pub(crate) use std::boxed::Box;
|
|
||||||
pub(crate) use std::string::String;
|
|
||||||
pub(crate) use std::vec::Vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate alloc;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
mod std_alloc {
|
|
||||||
pub(crate) use alloc::borrow::Cow;
|
|
||||||
#[cfg(feature = "quickcheck")]
|
|
||||||
pub(crate) use alloc::boxed::Box;
|
|
||||||
pub(crate) use alloc::string::String;
|
|
||||||
pub(crate) use alloc::vec::Vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
use core::fmt;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -149,7 +125,7 @@ enum BigIntErrorKind {
|
||||||
|
|
||||||
impl ParseBigIntError {
|
impl ParseBigIntError {
|
||||||
fn __description(&self) -> &str {
|
fn __description(&self) -> &str {
|
||||||
use crate::BigIntErrorKind::*;
|
use BigIntErrorKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Empty => "cannot parse integer from empty string",
|
Empty => "cannot parse integer from empty string",
|
||||||
InvalidDigit => "invalid digit found in string",
|
InvalidDigit => "invalid digit found in string",
|
||||||
|
@ -170,102 +146,42 @@ impl ParseBigIntError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ParseBigIntError {
|
impl fmt::Display for ParseBigIntError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.__description().fmt(f)
|
self.__description().fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl Error for ParseBigIntError {
|
impl Error for ParseBigIntError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
self.__description()
|
self.__description()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The error type returned when a checked conversion regarding big integer fails.
|
pub use biguint::BigUint;
|
||||||
#[cfg(has_try_from)]
|
pub use biguint::ToBigUint;
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub struct TryFromBigIntError<T> {
|
|
||||||
original: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_try_from)]
|
pub use bigint::BigInt;
|
||||||
impl<T> TryFromBigIntError<T> {
|
pub use bigint::Sign;
|
||||||
fn new(original: T) -> Self {
|
pub use bigint::ToBigInt;
|
||||||
TryFromBigIntError { original }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn __description(&self) -> &str {
|
|
||||||
"out of range conversion regarding big integer attempted"
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract the original value, if available. The value will be available
|
|
||||||
/// if the type before conversion was either [`BigInt`] or [`BigUint`].
|
|
||||||
///
|
|
||||||
/// [`BigInt`]: struct.BigInt.html
|
|
||||||
/// [`BigUint`]: struct.BigUint.html
|
|
||||||
pub fn into_original(self) -> T {
|
|
||||||
self.original
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "std", has_try_from))]
|
|
||||||
impl<T> std::error::Error for TryFromBigIntError<T>
|
|
||||||
where
|
|
||||||
T: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
self.__description()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_try_from)]
|
|
||||||
impl<T> fmt::Display for TryFromBigIntError<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.__description().fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use crate::biguint::BigUint;
|
|
||||||
pub use crate::biguint::ToBigUint;
|
|
||||||
|
|
||||||
pub use crate::bigint::BigInt;
|
|
||||||
pub use crate::bigint::Sign;
|
|
||||||
pub use crate::bigint::ToBigInt;
|
|
||||||
|
|
||||||
#[cfg(feature = "rand")]
|
#[cfg(feature = "rand")]
|
||||||
pub use crate::bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint};
|
pub use bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint};
|
||||||
|
|
||||||
mod big_digit {
|
mod big_digit {
|
||||||
/// A `BigDigit` is a `BigUint`'s composing element.
|
/// A `BigDigit` is a `BigUint`'s composing element.
|
||||||
#[cfg(not(u64_digit))]
|
pub type BigDigit = u32;
|
||||||
pub(crate) type BigDigit = u32;
|
|
||||||
#[cfg(u64_digit)]
|
|
||||||
pub(crate) type BigDigit = u64;
|
|
||||||
|
|
||||||
/// A `DoubleBigDigit` is the internal type used to do the computations. Its
|
/// A `DoubleBigDigit` is the internal type used to do the computations. Its
|
||||||
/// size is the double of the size of `BigDigit`.
|
/// size is the double of the size of `BigDigit`.
|
||||||
#[cfg(not(u64_digit))]
|
pub type DoubleBigDigit = u64;
|
||||||
pub(crate) type DoubleBigDigit = u64;
|
|
||||||
#[cfg(u64_digit)]
|
|
||||||
pub(crate) type DoubleBigDigit = u128;
|
|
||||||
|
|
||||||
/// A `SignedDoubleBigDigit` is the signed version of `DoubleBigDigit`.
|
/// A `SignedDoubleBigDigit` is the signed version of `DoubleBigDigit`.
|
||||||
#[cfg(not(u64_digit))]
|
pub type SignedDoubleBigDigit = i64;
|
||||||
pub(crate) type SignedDoubleBigDigit = i64;
|
|
||||||
#[cfg(u64_digit)]
|
|
||||||
pub(crate) type SignedDoubleBigDigit = i128;
|
|
||||||
|
|
||||||
// `DoubleBigDigit` size dependent
|
// `DoubleBigDigit` size dependent
|
||||||
#[cfg(not(u64_digit))]
|
pub const BITS: usize = 32;
|
||||||
pub(crate) const BITS: u8 = 32;
|
|
||||||
#[cfg(u64_digit)]
|
|
||||||
pub(crate) const BITS: u8 = 64;
|
|
||||||
|
|
||||||
pub(crate) const HALF_BITS: u8 = BITS / 2;
|
const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS;
|
||||||
pub(crate) const HALF: BigDigit = (1 << HALF_BITS) - 1;
|
|
||||||
|
|
||||||
const LO_MASK: DoubleBigDigit = (1 << BITS) - 1;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_hi(n: DoubleBigDigit) -> BigDigit {
|
fn get_hi(n: DoubleBigDigit) -> BigDigit {
|
||||||
|
@ -278,13 +194,13 @@ mod big_digit {
|
||||||
|
|
||||||
/// Split one `DoubleBigDigit` into two `BigDigit`s.
|
/// Split one `DoubleBigDigit` into two `BigDigit`s.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
|
pub fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
|
||||||
(get_hi(n), get_lo(n))
|
(get_hi(n), get_lo(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join two `BigDigit`s into one `DoubleBigDigit`
|
/// Join two `BigDigit`s into one `DoubleBigDigit`
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn to_doublebigdigit(hi: BigDigit, lo: BigDigit) -> DoubleBigDigit {
|
pub fn to_doublebigdigit(hi: BigDigit, lo: BigDigit) -> DoubleBigDigit {
|
||||||
DoubleBigDigit::from(lo) | (DoubleBigDigit::from(hi) << BITS)
|
DoubleBigDigit::from(lo) | (DoubleBigDigit::from(hi) << BITS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(unknown_lints)] // older rustc doesn't know `unused_macros`
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
macro_rules! forward_val_val_binop {
|
macro_rules! forward_val_val_binop {
|
||||||
|
@ -283,7 +284,8 @@ macro_rules! promote_scalars {
|
||||||
impl $imp<$scalar> for $res {
|
impl $imp<$scalar> for $res {
|
||||||
type Output = $res;
|
type Output = $res;
|
||||||
|
|
||||||
#[allow(clippy::cast_lossless)]
|
#[cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, other: $scalar) -> $res {
|
fn $method(self, other: $scalar) -> $res {
|
||||||
$imp::$method(self, other as $promo)
|
$imp::$method(self, other as $promo)
|
||||||
|
@ -293,7 +295,8 @@ macro_rules! promote_scalars {
|
||||||
impl $imp<$res> for $scalar {
|
impl $imp<$res> for $scalar {
|
||||||
type Output = $res;
|
type Output = $res;
|
||||||
|
|
||||||
#[allow(clippy::cast_lossless)]
|
#[cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(self, other: $res) -> $res {
|
fn $method(self, other: $res) -> $res {
|
||||||
$imp::$method(self as $promo, other)
|
$imp::$method(self as $promo, other)
|
||||||
|
@ -306,7 +309,8 @@ macro_rules! promote_scalars_assign {
|
||||||
(impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
|
(impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => {
|
||||||
$(
|
$(
|
||||||
impl $imp<$scalar> for $res {
|
impl $imp<$scalar> for $res {
|
||||||
#[allow(clippy::cast_lossless)]
|
#[cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $method(&mut self, other: $scalar) {
|
fn $method(&mut self, other: $scalar) {
|
||||||
self.$method(other as $promo);
|
self.$method(other as $promo);
|
||||||
|
@ -340,7 +344,7 @@ macro_rules! promote_signed_scalars {
|
||||||
macro_rules! promote_signed_scalars_assign {
|
macro_rules! promote_signed_scalars_assign {
|
||||||
(impl $imp:ident for $res:ty, $method:ident) => {
|
(impl $imp:ident for $res:ty, $method:ident) => {
|
||||||
promote_scalars_assign!(impl $imp<i32> for $res, $method, i8, i16);
|
promote_scalars_assign!(impl $imp<i32> for $res, $method, i8, i16);
|
||||||
promote_scalars_assign!(impl $imp<IsizePromotion> for $res, $method, isize);
|
promote_scalars_assign!(impl $imp<UsizePromotion> for $res, $method, isize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,223 +1,129 @@
|
||||||
use crate::std_alloc::Vec;
|
use integer::Integer;
|
||||||
use core::mem;
|
use traits::Zero;
|
||||||
use core::ops::Shl;
|
|
||||||
use num_traits::{One, Zero};
|
|
||||||
|
|
||||||
use crate::big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit};
|
use biguint::BigUint;
|
||||||
use crate::biguint::BigUint;
|
|
||||||
|
|
||||||
struct MontyReducer {
|
struct MontyReducer<'a> {
|
||||||
n0inv: BigDigit,
|
n: &'a BigUint,
|
||||||
|
n0inv: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// k0 = -m**-1 mod 2**BITS. Algorithm from: Dumas, J.G. "On Newton–Raphson
|
// Calculate the modular inverse of `num`, using Extended GCD.
|
||||||
// Iteration for Multiplicative Inverses Modulo Prime Powers".
|
//
|
||||||
fn inv_mod_alt(b: BigDigit) -> BigDigit {
|
// Reference:
|
||||||
assert_ne!(b & 1, 0);
|
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 1.20
|
||||||
|
fn inv_mod_u32(num: u32) -> u32 {
|
||||||
|
// num needs to be relatively prime to 2**32 -- i.e. it must be odd.
|
||||||
|
assert!(num % 2 != 0);
|
||||||
|
|
||||||
let mut k0 = 2 - b as SignedDoubleBigDigit;
|
let mut a: i64 = i64::from(num);
|
||||||
let mut t = (b - 1) as SignedDoubleBigDigit;
|
let mut b: i64 = i64::from(u32::max_value()) + 1;
|
||||||
let mut i = 1;
|
|
||||||
while i < big_digit::BITS {
|
|
||||||
t = t.wrapping_mul(t);
|
|
||||||
k0 = k0.wrapping_mul(t + 1);
|
|
||||||
|
|
||||||
i <<= 1;
|
// ExtendedGcd
|
||||||
|
// Input: positive integers a and b
|
||||||
|
// Output: integers (g, u, v) such that g = gcd(a, b) = ua + vb
|
||||||
|
// As we don't need v for modular inverse, we don't calculate it.
|
||||||
|
|
||||||
|
// 1: (u, w) <- (1, 0)
|
||||||
|
let mut u = 1;
|
||||||
|
let mut w = 0;
|
||||||
|
// 3: while b != 0
|
||||||
|
while b != 0 {
|
||||||
|
// 4: (q, r) <- DivRem(a, b)
|
||||||
|
let q = a / b;
|
||||||
|
let r = a % b;
|
||||||
|
// 5: (a, b) <- (b, r)
|
||||||
|
a = b;
|
||||||
|
b = r;
|
||||||
|
// 6: (u, w) <- (w, u - qw)
|
||||||
|
let m = u - w * q;
|
||||||
|
u = w;
|
||||||
|
w = m;
|
||||||
}
|
}
|
||||||
-k0 as BigDigit
|
|
||||||
|
assert!(a == 1);
|
||||||
|
// Downcasting acts like a mod 2^32 too.
|
||||||
|
u as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MontyReducer {
|
impl<'a> MontyReducer<'a> {
|
||||||
fn new(n: &BigUint) -> Self {
|
fn new(n: &'a BigUint) -> Self {
|
||||||
let n0inv = inv_mod_alt(n.data[0]);
|
let n0inv = inv_mod_u32(n.data[0]);
|
||||||
MontyReducer { n0inv }
|
MontyReducer { n: n, n0inv: n0inv }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes z mod m = x * y * 2 ** (-n*_W) mod m
|
// Montgomery Reduction
|
||||||
/// assuming k = -1/m mod 2**_W
|
//
|
||||||
/// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
|
// Reference:
|
||||||
/// https://eprint.iacr.org/2011/239.pdf
|
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 2.6
|
||||||
/// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
|
fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint {
|
||||||
/// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
|
let mut c = a.data;
|
||||||
/// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
|
let n = &mr.n.data;
|
||||||
fn montgomery(x: &BigUint, y: &BigUint, m: &BigUint, k: BigDigit, n: usize) -> BigUint {
|
let n_size = n.len();
|
||||||
// This code assumes x, y, m are all the same length, n.
|
|
||||||
// (required by addMulVVW and the for loop).
|
|
||||||
// It also assumes that x, y are already reduced mod m,
|
|
||||||
// or else the result will not be properly reduced.
|
|
||||||
assert!(
|
|
||||||
x.data.len() == n && y.data.len() == n && m.data.len() == n,
|
|
||||||
"{:?} {:?} {:?} {}",
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
m,
|
|
||||||
n
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut z = BigUint::zero();
|
// Allocate sufficient work space
|
||||||
z.data.resize(n * 2, 0);
|
c.resize(2 * n_size + 2, 0);
|
||||||
|
|
||||||
let mut c: BigDigit = 0;
|
// β is the size of a word, in this case 32 bits. So "a mod β" is
|
||||||
for i in 0..n {
|
// equivalent to masking a to 32 bits.
|
||||||
let c2 = add_mul_vvw(&mut z.data[i..n + i], &x.data, y.data[i]);
|
// mu <- -N^(-1) mod β
|
||||||
let t = z.data[i].wrapping_mul(k);
|
let mu = 0u32.wrapping_sub(mr.n0inv);
|
||||||
let c3 = add_mul_vvw(&mut z.data[i..n + i], &m.data, t);
|
|
||||||
let cx = c.wrapping_add(c2);
|
// 1: for i = 0 to (n-1)
|
||||||
let cy = cx.wrapping_add(c3);
|
for i in 0..n_size {
|
||||||
z.data[n + i] = cy;
|
// 2: q_i <- mu*c_i mod β
|
||||||
if cx < c2 || cy < c3 {
|
let q_i = c[i].wrapping_mul(mu);
|
||||||
c = 1;
|
|
||||||
} else {
|
// 3: C <- C + q_i * N * β^i
|
||||||
c = 0;
|
super::algorithms::mac_digit(&mut c[i..], n, q_i);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c == 0 {
|
// 4: R <- C * β^(-n)
|
||||||
z.data = z.data[n..].to_vec();
|
// This is an n-word bitshift, equivalent to skipping n words.
|
||||||
|
let ret = BigUint::new(c[n_size..].to_vec());
|
||||||
|
|
||||||
|
// 5: if R >= β^n then return R-N else return R.
|
||||||
|
if &ret < mr.n {
|
||||||
|
ret
|
||||||
} else {
|
} else {
|
||||||
{
|
ret - mr.n
|
||||||
let (mut first, second) = z.data.split_at_mut(n);
|
}
|
||||||
sub_vv(&mut first, &second, &m.data);
|
}
|
||||||
|
|
||||||
|
// Montgomery Multiplication
|
||||||
|
fn monty_mult(a: BigUint, b: &BigUint, mr: &MontyReducer) -> BigUint {
|
||||||
|
monty_redc(a * b, mr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Montgomery Squaring
|
||||||
|
fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint {
|
||||||
|
// TODO: Replace with an optimised squaring function
|
||||||
|
monty_redc(&a * &a, mr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
|
||||||
|
let mr = MontyReducer::new(modulus);
|
||||||
|
|
||||||
|
// Calculate the Montgomery parameter
|
||||||
|
let mut v = vec![0; modulus.data.len()];
|
||||||
|
v.push(1);
|
||||||
|
let r = BigUint::new(v);
|
||||||
|
|
||||||
|
// Map the base to the Montgomery domain
|
||||||
|
let mut apri = a * &r % modulus;
|
||||||
|
|
||||||
|
// Binary exponentiation
|
||||||
|
let mut ans = &r % modulus;
|
||||||
|
let mut e = exp.clone();
|
||||||
|
while !e.is_zero() {
|
||||||
|
if e.is_odd() {
|
||||||
|
ans = monty_mult(ans, &apri, &mr);
|
||||||
}
|
}
|
||||||
z.data = z.data[..n].to_vec();
|
apri = monty_sqr(apri, &mr);
|
||||||
|
e = e >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
z
|
// Map the result back to the residues domain
|
||||||
}
|
monty_redc(ans, &mr)
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn add_mul_vvw(z: &mut [BigDigit], x: &[BigDigit], y: BigDigit) -> BigDigit {
|
|
||||||
let mut c = 0;
|
|
||||||
for (zi, xi) in z.iter_mut().zip(x.iter()) {
|
|
||||||
let (z1, z0) = mul_add_www(*xi, y, *zi);
|
|
||||||
let (c_, zi_) = add_ww(z0, c, 0);
|
|
||||||
*zi = zi_;
|
|
||||||
c = c_ + z1;
|
|
||||||
}
|
|
||||||
|
|
||||||
c
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The resulting carry c is either 0 or 1.
|
|
||||||
#[inline(always)]
|
|
||||||
fn sub_vv(z: &mut [BigDigit], x: &[BigDigit], y: &[BigDigit]) -> BigDigit {
|
|
||||||
let mut c = 0;
|
|
||||||
for (i, (xi, yi)) in x.iter().zip(y.iter()).enumerate().take(z.len()) {
|
|
||||||
let zi = xi.wrapping_sub(*yi).wrapping_sub(c);
|
|
||||||
z[i] = zi;
|
|
||||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
|
||||||
c = ((yi & !xi) | ((yi | !xi) & zi)) >> (big_digit::BITS - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
c
|
|
||||||
}
|
|
||||||
|
|
||||||
/// z1<<_W + z0 = x+y+c, with c == 0 or 1
|
|
||||||
#[inline(always)]
|
|
||||||
fn add_ww(x: BigDigit, y: BigDigit, c: BigDigit) -> (BigDigit, BigDigit) {
|
|
||||||
let yc = y.wrapping_add(c);
|
|
||||||
let z0 = x.wrapping_add(yc);
|
|
||||||
let z1 = if z0 < x || yc < y { 1 } else { 0 };
|
|
||||||
|
|
||||||
(z1, z0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// z1 << _W + z0 = x * y + c
|
|
||||||
#[inline(always)]
|
|
||||||
fn mul_add_www(x: BigDigit, y: BigDigit, c: BigDigit) -> (BigDigit, BigDigit) {
|
|
||||||
let z = x as DoubleBigDigit * y as DoubleBigDigit + c as DoubleBigDigit;
|
|
||||||
((z >> big_digit::BITS) as BigDigit, z as BigDigit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates x ** y mod m using a fixed, 4-bit window.
|
|
||||||
pub(crate) fn monty_modpow(x: &BigUint, y: &BigUint, m: &BigUint) -> BigUint {
|
|
||||||
assert!(m.data[0] & 1 == 1);
|
|
||||||
let mr = MontyReducer::new(m);
|
|
||||||
let num_words = m.data.len();
|
|
||||||
|
|
||||||
let mut x = x.clone();
|
|
||||||
|
|
||||||
// We want the lengths of x and m to be equal.
|
|
||||||
// It is OK if x >= m as long as len(x) == len(m).
|
|
||||||
if x.data.len() > num_words {
|
|
||||||
x %= m;
|
|
||||||
// Note: now len(x) <= numWords, not guaranteed ==.
|
|
||||||
}
|
|
||||||
if x.data.len() < num_words {
|
|
||||||
x.data.resize(num_words, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rr = 2**(2*_W*len(m)) mod m
|
|
||||||
let mut rr = BigUint::one();
|
|
||||||
rr = (rr.shl(2 * num_words as u64 * u64::from(big_digit::BITS))) % m;
|
|
||||||
if rr.data.len() < num_words {
|
|
||||||
rr.data.resize(num_words, 0);
|
|
||||||
}
|
|
||||||
// one = 1, with equal length to that of m
|
|
||||||
let mut one = BigUint::one();
|
|
||||||
one.data.resize(num_words, 0);
|
|
||||||
|
|
||||||
let n = 4;
|
|
||||||
// powers[i] contains x^i
|
|
||||||
let mut powers = Vec::with_capacity(1 << n);
|
|
||||||
powers.push(montgomery(&one, &rr, m, mr.n0inv, num_words));
|
|
||||||
powers.push(montgomery(&x, &rr, m, mr.n0inv, num_words));
|
|
||||||
for i in 2..1 << n {
|
|
||||||
let r = montgomery(&powers[i - 1], &powers[1], m, mr.n0inv, num_words);
|
|
||||||
powers.push(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize z = 1 (Montgomery 1)
|
|
||||||
let mut z = powers[0].clone();
|
|
||||||
z.data.resize(num_words, 0);
|
|
||||||
let mut zz = BigUint::zero();
|
|
||||||
zz.data.resize(num_words, 0);
|
|
||||||
|
|
||||||
// same windowed exponent, but with Montgomery multiplications
|
|
||||||
for i in (0..y.data.len()).rev() {
|
|
||||||
let mut yi = y.data[i];
|
|
||||||
let mut j = 0;
|
|
||||||
while j < big_digit::BITS {
|
|
||||||
if i != y.data.len() - 1 || j != 0 {
|
|
||||||
zz = montgomery(&z, &z, m, mr.n0inv, num_words);
|
|
||||||
z = montgomery(&zz, &zz, m, mr.n0inv, num_words);
|
|
||||||
zz = montgomery(&z, &z, m, mr.n0inv, num_words);
|
|
||||||
z = montgomery(&zz, &zz, m, mr.n0inv, num_words);
|
|
||||||
}
|
|
||||||
zz = montgomery(
|
|
||||||
&z,
|
|
||||||
&powers[(yi >> (big_digit::BITS - n)) as usize],
|
|
||||||
m,
|
|
||||||
mr.n0inv,
|
|
||||||
num_words,
|
|
||||||
);
|
|
||||||
mem::swap(&mut z, &mut zz);
|
|
||||||
yi <<= n;
|
|
||||||
j += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert to regular number
|
|
||||||
zz = montgomery(&z, &one, m, mr.n0inv, num_words);
|
|
||||||
|
|
||||||
zz.normalize();
|
|
||||||
// One last reduction, just in case.
|
|
||||||
// See golang.org/issue/13907.
|
|
||||||
if zz >= *m {
|
|
||||||
// Common case is m has high bit set; in that case,
|
|
||||||
// since zz is the same length as m, there can be just
|
|
||||||
// one multiple of m to remove. Just subtract.
|
|
||||||
// We think that the subtract should be sufficient in general,
|
|
||||||
// so do that unconditionally, but double-check,
|
|
||||||
// in case our beliefs are wrong.
|
|
||||||
// The div is not expected to be reached.
|
|
||||||
zz -= m;
|
|
||||||
if zz >= *m {
|
|
||||||
zz %= m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zz.normalize();
|
|
||||||
zz
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_bigint::Sign::{Minus, NoSign, Plus};
|
use num_bigint::Sign::{Minus, NoSign, Plus};
|
||||||
use num_bigint::{BigInt, ToBigInt};
|
use num_bigint::{BigInt, ToBigInt};
|
||||||
|
@ -8,15 +14,16 @@ use std::hash::{BuildHasher, Hash, Hasher};
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
use std::{f32, f64};
|
use std::{f32, f64};
|
||||||
|
#[cfg(has_i128)]
|
||||||
use std::{i128, u128};
|
use std::{i128, u128};
|
||||||
use std::{i16, i32, i64, i8, isize};
|
use std::{i16, i32, i64, i8, isize};
|
||||||
use std::{u16, u32, u64, u8, usize};
|
use std::{u16, u32, u64, u8, usize};
|
||||||
|
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use num_traits::{pow, FromPrimitive, Num, One, Pow, Signed, ToPrimitive, Zero};
|
use num_traits::{Float, FromPrimitive, Num, One, Pow, Signed, ToPrimitive, Zero};
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
use crate::consts::*;
|
use consts::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -33,8 +40,8 @@ fn test_from_bytes_be() {
|
||||||
check("AA", "16705");
|
check("AA", "16705");
|
||||||
check("AB", "16706");
|
check("AB", "16706");
|
||||||
check("Hello world!", "22405534230753963835153736737");
|
check("Hello world!", "22405534230753963835153736737");
|
||||||
assert_eq!(BigInt::from_bytes_be(Plus, &[]), BigInt::zero());
|
assert_eq!(BigInt::from_bytes_be(Plus, &[]), Zero::zero());
|
||||||
assert_eq!(BigInt::from_bytes_be(Minus, &[]), BigInt::zero());
|
assert_eq!(BigInt::from_bytes_be(Minus, &[]), Zero::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -68,8 +75,8 @@ fn test_from_bytes_le() {
|
||||||
check("AA", "16705");
|
check("AA", "16705");
|
||||||
check("BA", "16706");
|
check("BA", "16706");
|
||||||
check("!dlrow olleH", "22405534230753963835153736737");
|
check("!dlrow olleH", "22405534230753963835153736737");
|
||||||
assert_eq!(BigInt::from_bytes_le(Plus, &[]), BigInt::zero());
|
assert_eq!(BigInt::from_bytes_le(Plus, &[]), Zero::zero());
|
||||||
assert_eq!(BigInt::from_bytes_le(Minus, &[]), BigInt::zero());
|
assert_eq!(BigInt::from_bytes_le(Minus, &[]), Zero::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -287,6 +294,7 @@ fn test_convert_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(has_i128)]
|
||||||
fn test_convert_i128() {
|
fn test_convert_i128() {
|
||||||
fn check(b1: BigInt, i: i128) {
|
fn check(b1: BigInt, i: i128) {
|
||||||
let b2: BigInt = FromPrimitive::from_i128(i).unwrap();
|
let b2: BigInt = FromPrimitive::from_i128(i).unwrap();
|
||||||
|
@ -344,6 +352,7 @@ fn test_convert_u64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(has_i128)]
|
||||||
fn test_convert_u128() {
|
fn test_convert_u128() {
|
||||||
fn check(b1: BigInt, u: u128) {
|
fn check(b1: BigInt, u: u128) {
|
||||||
let b2: BigInt = FromPrimitive::from_u128(u).unwrap();
|
let b2: BigInt = FromPrimitive::from_u128(u).unwrap();
|
||||||
|
@ -370,7 +379,6 @@ fn test_convert_u128() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::float_cmp)]
|
|
||||||
fn test_convert_f32() {
|
fn test_convert_f32() {
|
||||||
fn check(b1: &BigInt, f: f32) {
|
fn check(b1: &BigInt, f: f32) {
|
||||||
let b2 = BigInt::from_f32(f).unwrap();
|
let b2 = BigInt::from_f32(f).unwrap();
|
||||||
|
@ -384,14 +392,14 @@ fn test_convert_f32() {
|
||||||
|
|
||||||
check(&BigInt::zero(), 0.0);
|
check(&BigInt::zero(), 0.0);
|
||||||
check(&BigInt::one(), 1.0);
|
check(&BigInt::one(), 1.0);
|
||||||
check(&BigInt::from(u16::MAX), pow(2.0_f32, 16) - 1.0);
|
check(&BigInt::from(u16::MAX), 2.0.powi(16) - 1.0);
|
||||||
check(&BigInt::from(1u64 << 32), pow(2.0_f32, 32));
|
check(&BigInt::from(1u64 << 32), 2.0.powi(32));
|
||||||
check(&BigInt::from_slice(Plus, &[0, 0, 1]), pow(2.0_f32, 64));
|
check(&BigInt::from_slice(Plus, &[0, 0, 1]), 2.0.powi(64));
|
||||||
check(
|
check(
|
||||||
&((BigInt::one() << 100) + (BigInt::one() << 123)),
|
&((BigInt::one() << 100) + (BigInt::one() << 123)),
|
||||||
pow(2.0_f32, 100) + pow(2.0_f32, 123),
|
2.0.powi(100) + 2.0.powi(123),
|
||||||
);
|
);
|
||||||
check(&(BigInt::one() << 127), pow(2.0_f32, 127));
|
check(&(BigInt::one() << 127), 2.0.powi(127));
|
||||||
check(&(BigInt::from((1u64 << 24) - 1) << (128 - 24)), f32::MAX);
|
check(&(BigInt::from((1u64 << 24) - 1) << (128 - 24)), f32::MAX);
|
||||||
|
|
||||||
// keeping all 24 digits with the bits at different offsets to the BigDigits
|
// keeping all 24 digits with the bits at different offsets to the BigDigits
|
||||||
|
@ -401,7 +409,7 @@ fn test_convert_f32() {
|
||||||
for _ in 0..64 {
|
for _ in 0..64 {
|
||||||
check(&b, f);
|
check(&b, f);
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this number when rounded to f64 then f32 isn't the same as when rounded straight to f32
|
// this number when rounded to f64 then f32 isn't the same as when rounded straight to f32
|
||||||
|
@ -418,7 +426,7 @@ fn test_convert_f32() {
|
||||||
for _ in 0..64 {
|
for _ in 0..64 {
|
||||||
assert_eq!(b.to_f32(), Some(f));
|
assert_eq!(b.to_f32(), Some(f));
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding
|
// rounding
|
||||||
|
@ -446,20 +454,19 @@ fn test_convert_f32() {
|
||||||
assert_eq!(BigInt::from_f32(f32::NEG_INFINITY), None);
|
assert_eq!(BigInt::from_f32(f32::NEG_INFINITY), None);
|
||||||
|
|
||||||
// largest BigInt that will round to a finite f32 value
|
// largest BigInt that will round to a finite f32 value
|
||||||
let big_num = (BigInt::one() << 128u8) - 1u8 - (BigInt::one() << (128u8 - 25));
|
let big_num = (BigInt::one() << 128) - BigInt::one() - (BigInt::one() << (128 - 25));
|
||||||
assert_eq!(big_num.to_f32(), Some(f32::MAX));
|
assert_eq!(big_num.to_f32(), Some(f32::MAX));
|
||||||
assert_eq!((&big_num + 1u8).to_f32(), None);
|
assert_eq!((&big_num + BigInt::one()).to_f32(), None);
|
||||||
assert_eq!((-&big_num).to_f32(), Some(f32::MIN));
|
assert_eq!((-&big_num).to_f32(), Some(f32::MIN));
|
||||||
assert_eq!(((-&big_num) - 1u8).to_f32(), None);
|
assert_eq!(((-&big_num) - BigInt::one()).to_f32(), None);
|
||||||
|
|
||||||
assert_eq!(((BigInt::one() << 128u8) - 1u8).to_f32(), None);
|
assert_eq!(((BigInt::one() << 128) - BigInt::one()).to_f32(), None);
|
||||||
assert_eq!((BigInt::one() << 128u8).to_f32(), None);
|
assert_eq!((BigInt::one() << 128).to_f32(), None);
|
||||||
assert_eq!((-((BigInt::one() << 128u8) - 1u8)).to_f32(), None);
|
assert_eq!((-((BigInt::one() << 128) - BigInt::one())).to_f32(), None);
|
||||||
assert_eq!((-(BigInt::one() << 128u8)).to_f32(), None);
|
assert_eq!((-(BigInt::one() << 128)).to_f32(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::float_cmp)]
|
|
||||||
fn test_convert_f64() {
|
fn test_convert_f64() {
|
||||||
fn check(b1: &BigInt, f: f64) {
|
fn check(b1: &BigInt, f: f64) {
|
||||||
let b2 = BigInt::from_f64(f).unwrap();
|
let b2 = BigInt::from_f64(f).unwrap();
|
||||||
|
@ -473,14 +480,14 @@ fn test_convert_f64() {
|
||||||
|
|
||||||
check(&BigInt::zero(), 0.0);
|
check(&BigInt::zero(), 0.0);
|
||||||
check(&BigInt::one(), 1.0);
|
check(&BigInt::one(), 1.0);
|
||||||
check(&BigInt::from(u32::MAX), pow(2.0_f64, 32) - 1.0);
|
check(&BigInt::from(u32::MAX), 2.0.powi(32) - 1.0);
|
||||||
check(&BigInt::from(1u64 << 32), pow(2.0_f64, 32));
|
check(&BigInt::from(1u64 << 32), 2.0.powi(32));
|
||||||
check(&BigInt::from_slice(Plus, &[0, 0, 1]), pow(2.0_f64, 64));
|
check(&BigInt::from_slice(Plus, &[0, 0, 1]), 2.0.powi(64));
|
||||||
check(
|
check(
|
||||||
&((BigInt::one() << 100) + (BigInt::one() << 152)),
|
&((BigInt::one() << 100) + (BigInt::one() << 152)),
|
||||||
pow(2.0_f64, 100) + pow(2.0_f64, 152),
|
2.0.powi(100) + 2.0.powi(152),
|
||||||
);
|
);
|
||||||
check(&(BigInt::one() << 1023), pow(2.0_f64, 1023));
|
check(&(BigInt::one() << 1023), 2.0.powi(1023));
|
||||||
check(&(BigInt::from((1u64 << 53) - 1) << (1024 - 53)), f64::MAX);
|
check(&(BigInt::from((1u64 << 53) - 1) << (1024 - 53)), f64::MAX);
|
||||||
|
|
||||||
// keeping all 53 digits with the bits at different offsets to the BigDigits
|
// keeping all 53 digits with the bits at different offsets to the BigDigits
|
||||||
|
@ -490,7 +497,7 @@ fn test_convert_f64() {
|
||||||
for _ in 0..128 {
|
for _ in 0..128 {
|
||||||
check(&b, f);
|
check(&b, f);
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test rounding up with the bits at different offsets to the BigDigits
|
// test rounding up with the bits at different offsets to the BigDigits
|
||||||
|
@ -499,7 +506,7 @@ fn test_convert_f64() {
|
||||||
for _ in 0..128 {
|
for _ in 0..128 {
|
||||||
assert_eq!(b.to_f64(), Some(f));
|
assert_eq!(b.to_f64(), Some(f));
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding
|
// rounding
|
||||||
|
@ -527,16 +534,16 @@ fn test_convert_f64() {
|
||||||
assert_eq!(BigInt::from_f64(f64::NEG_INFINITY), None);
|
assert_eq!(BigInt::from_f64(f64::NEG_INFINITY), None);
|
||||||
|
|
||||||
// largest BigInt that will round to a finite f64 value
|
// largest BigInt that will round to a finite f64 value
|
||||||
let big_num = (BigInt::one() << 1024u16) - 1u8 - (BigInt::one() << (1024u16 - 54));
|
let big_num = (BigInt::one() << 1024) - BigInt::one() - (BigInt::one() << (1024 - 54));
|
||||||
assert_eq!(big_num.to_f64(), Some(f64::MAX));
|
assert_eq!(big_num.to_f64(), Some(f64::MAX));
|
||||||
assert_eq!((&big_num + 1u8).to_f64(), None);
|
assert_eq!((&big_num + BigInt::one()).to_f64(), None);
|
||||||
assert_eq!((-&big_num).to_f64(), Some(f64::MIN));
|
assert_eq!((-&big_num).to_f64(), Some(f64::MIN));
|
||||||
assert_eq!(((-&big_num) - 1u8).to_f64(), None);
|
assert_eq!(((-&big_num) - BigInt::one()).to_f64(), None);
|
||||||
|
|
||||||
assert_eq!(((BigInt::one() << 1024u16) - 1u8).to_f64(), None);
|
assert_eq!(((BigInt::one() << 1024) - BigInt::one()).to_f64(), None);
|
||||||
assert_eq!((BigInt::one() << 1024u16).to_f64(), None);
|
assert_eq!((BigInt::one() << 1024).to_f64(), None);
|
||||||
assert_eq!((-((BigInt::one() << 1024u16) - 1u8)).to_f64(), None);
|
assert_eq!((-((BigInt::one() << 1024) - BigInt::one())).to_f64(), None);
|
||||||
assert_eq!((-(BigInt::one() << 1024u16)).to_f64(), None);
|
assert_eq!((-(BigInt::one() << 1024)).to_f64(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -571,6 +578,7 @@ fn test_convert_from_uint() {
|
||||||
check!(u16, BigInt::from_slice(Plus, &[u16::MAX as u32]));
|
check!(u16, BigInt::from_slice(Plus, &[u16::MAX as u32]));
|
||||||
check!(u32, BigInt::from_slice(Plus, &[u32::MAX]));
|
check!(u32, BigInt::from_slice(Plus, &[u32::MAX]));
|
||||||
check!(u64, BigInt::from_slice(Plus, &[u32::MAX, u32::MAX]));
|
check!(u64, BigInt::from_slice(Plus, &[u32::MAX, u32::MAX]));
|
||||||
|
#[cfg(has_i128)]
|
||||||
check!(
|
check!(
|
||||||
u128,
|
u128,
|
||||||
BigInt::from_slice(Plus, &[u32::MAX, u32::MAX, u32::MAX, u32::MAX])
|
BigInt::from_slice(Plus, &[u32::MAX, u32::MAX, u32::MAX, u32::MAX])
|
||||||
|
@ -612,6 +620,7 @@ fn test_convert_from_int() {
|
||||||
BigInt::from_slice(Minus, &[0, 1 << 31]),
|
BigInt::from_slice(Minus, &[0, 1 << 31]),
|
||||||
BigInt::from_slice(Plus, &[u32::MAX, i32::MAX as u32])
|
BigInt::from_slice(Plus, &[u32::MAX, i32::MAX as u32])
|
||||||
);
|
);
|
||||||
|
#[cfg(has_i128)]
|
||||||
check!(
|
check!(
|
||||||
i128,
|
i128,
|
||||||
BigInt::from_slice(Minus, &[0, 0, 0, 1 << 31]),
|
BigInt::from_slice(Minus, &[0, 0, 0, 1 << 31]),
|
||||||
|
@ -650,7 +659,7 @@ fn test_add() {
|
||||||
assert_op!(a + nc == nb);
|
assert_op!(a + nc == nb);
|
||||||
assert_op!(b + nc == na);
|
assert_op!(b + nc == na);
|
||||||
assert_op!(na + nb == nc);
|
assert_op!(na + nb == nc);
|
||||||
assert_op!(a + na == BigInt::zero());
|
assert_op!(a + na == Zero::zero());
|
||||||
|
|
||||||
assert_assign_op!(a += b == c);
|
assert_assign_op!(a += b == c);
|
||||||
assert_assign_op!(b += a == c);
|
assert_assign_op!(b += a == c);
|
||||||
|
@ -659,7 +668,7 @@ fn test_add() {
|
||||||
assert_assign_op!(a += nc == nb);
|
assert_assign_op!(a += nc == nb);
|
||||||
assert_assign_op!(b += nc == na);
|
assert_assign_op!(b += nc == na);
|
||||||
assert_assign_op!(na += nb == nc);
|
assert_assign_op!(na += nb == nc);
|
||||||
assert_assign_op!(a += na == BigInt::zero());
|
assert_assign_op!(a += na == Zero::zero());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,7 +688,7 @@ fn test_sub() {
|
||||||
assert_op!(b - na == c);
|
assert_op!(b - na == c);
|
||||||
assert_op!(a - nb == c);
|
assert_op!(a - nb == c);
|
||||||
assert_op!(nc - na == nb);
|
assert_op!(nc - na == nb);
|
||||||
assert_op!(a - a == BigInt::zero());
|
assert_op!(a - a == Zero::zero());
|
||||||
|
|
||||||
assert_assign_op!(c -= a == b);
|
assert_assign_op!(c -= a == b);
|
||||||
assert_assign_op!(c -= b == a);
|
assert_assign_op!(c -= b == a);
|
||||||
|
@ -688,7 +697,7 @@ fn test_sub() {
|
||||||
assert_assign_op!(b -= na == c);
|
assert_assign_op!(b -= na == c);
|
||||||
assert_assign_op!(a -= nb == c);
|
assert_assign_op!(a -= nb == c);
|
||||||
assert_assign_op!(nc -= na == nb);
|
assert_assign_op!(nc -= na == nb);
|
||||||
assert_assign_op!(a -= a == BigInt::zero());
|
assert_assign_op!(a -= a == Zero::zero());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,8 +741,6 @@ fn test_mul() {
|
||||||
fn test_div_mod_floor() {
|
fn test_div_mod_floor() {
|
||||||
fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) {
|
fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) {
|
||||||
let (d, m) = a.div_mod_floor(b);
|
let (d, m) = a.div_mod_floor(b);
|
||||||
assert_eq!(d, a.div_floor(b));
|
|
||||||
assert_eq!(m, a.mod_floor(b));
|
|
||||||
if !m.is_zero() {
|
if !m.is_zero() {
|
||||||
assert_eq!(m.sign(), b.sign());
|
assert_eq!(m.sign(), b.sign());
|
||||||
}
|
}
|
||||||
|
@ -837,53 +844,6 @@ fn test_div_rem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_div_ceil() {
|
|
||||||
fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt) {
|
|
||||||
assert_eq!(a.div_ceil(b), *ans_d);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check(a: &BigInt, b: &BigInt, d: &BigInt, m: &BigInt) {
|
|
||||||
if m.is_zero() {
|
|
||||||
check_sub(a, b, d);
|
|
||||||
check_sub(a, &b.neg(), &d.neg());
|
|
||||||
check_sub(&a.neg(), b, &d.neg());
|
|
||||||
check_sub(&a.neg(), &b.neg(), d);
|
|
||||||
} else {
|
|
||||||
check_sub(a, b, &(d + 1));
|
|
||||||
check_sub(a, &b.neg(), &d.neg());
|
|
||||||
check_sub(&a.neg(), b, &d.neg());
|
|
||||||
check_sub(&a.neg(), &b.neg(), &(d + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let b = BigInt::from_slice(Plus, b_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
|
|
||||||
if !a.is_zero() {
|
|
||||||
check(&c, &a, &b, &Zero::zero());
|
|
||||||
}
|
|
||||||
if !b.is_zero() {
|
|
||||||
check(&c, &b, &a, &Zero::zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in DIV_REM_QUADRUPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec, d_vec) = *elm;
|
|
||||||
let a = BigInt::from_slice(Plus, a_vec);
|
|
||||||
let b = BigInt::from_slice(Plus, b_vec);
|
|
||||||
let c = BigInt::from_slice(Plus, c_vec);
|
|
||||||
let d = BigInt::from_slice(Plus, d_vec);
|
|
||||||
|
|
||||||
if !b.is_zero() {
|
|
||||||
check(&a, &b, &c, &d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_checked_add() {
|
fn test_checked_add() {
|
||||||
for elm in SUM_TRIPLES.iter() {
|
for elm in SUM_TRIPLES.iter() {
|
||||||
|
@ -899,7 +859,7 @@ fn test_checked_add() {
|
||||||
assert!(a.checked_add(&(-&c)).unwrap() == (-&b));
|
assert!(a.checked_add(&(-&c)).unwrap() == (-&b));
|
||||||
assert!(b.checked_add(&(-&c)).unwrap() == (-&a));
|
assert!(b.checked_add(&(-&c)).unwrap() == (-&a));
|
||||||
assert!((-&a).checked_add(&(-&b)).unwrap() == (-&c));
|
assert!((-&a).checked_add(&(-&b)).unwrap() == (-&c));
|
||||||
assert!(a.checked_add(&(-&a)).unwrap() == BigInt::zero());
|
assert!(a.checked_add(&(-&a)).unwrap() == Zero::zero());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -918,7 +878,7 @@ fn test_checked_sub() {
|
||||||
assert!(b.checked_sub(&(-&a)).unwrap() == c);
|
assert!(b.checked_sub(&(-&a)).unwrap() == c);
|
||||||
assert!(a.checked_sub(&(-&b)).unwrap() == c);
|
assert!(a.checked_sub(&(-&b)).unwrap() == c);
|
||||||
assert!((-&c).checked_sub(&(-&a)).unwrap() == (-&b));
|
assert!((-&c).checked_sub(&(-&a)).unwrap() == (-&b));
|
||||||
assert!(a.checked_sub(&a).unwrap() == BigInt::zero());
|
assert!(a.checked_sub(&a).unwrap() == Zero::zero());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,9 +940,6 @@ fn test_gcd() {
|
||||||
let big_c: BigInt = FromPrimitive::from_isize(c).unwrap();
|
let big_c: BigInt = FromPrimitive::from_isize(c).unwrap();
|
||||||
|
|
||||||
assert_eq!(big_a.gcd(&big_b), big_c);
|
assert_eq!(big_a.gcd(&big_b), big_c);
|
||||||
assert_eq!(big_a.extended_gcd(&big_b).gcd, big_c);
|
|
||||||
assert_eq!(big_a.gcd_lcm(&big_b).0, big_c);
|
|
||||||
assert_eq!(big_a.extended_gcd_lcm(&big_b).0.gcd, big_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check(10, 2, 2);
|
check(10, 2, 2);
|
||||||
|
@ -1003,8 +960,6 @@ fn test_lcm() {
|
||||||
let big_c: BigInt = FromPrimitive::from_isize(c).unwrap();
|
let big_c: BigInt = FromPrimitive::from_isize(c).unwrap();
|
||||||
|
|
||||||
assert_eq!(big_a.lcm(&big_b), big_c);
|
assert_eq!(big_a.lcm(&big_b), big_c);
|
||||||
assert_eq!(big_a.gcd_lcm(&big_b).1, big_c);
|
|
||||||
assert_eq!(big_a.extended_gcd_lcm(&big_b).1, big_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check(0, 0, 0);
|
check(0, 0, 0);
|
||||||
|
@ -1018,78 +973,6 @@ fn test_lcm() {
|
||||||
check(11, 5, 55);
|
check(11, 5, 55);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_next_multiple_of() {
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(16).next_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(23).next_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(24)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(16).next_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(23).next_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-16).next_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(-16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-23).next_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(-16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-16).next_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(-16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-23).next_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(-24)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_prev_multiple_of() {
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(16).prev_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(23).prev_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(16).prev_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(23).prev_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(24)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-16).prev_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(-16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-23).prev_multiple_of(&BigInt::from(8)),
|
|
||||||
BigInt::from(-24)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-16).prev_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(-16)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigInt::from(-23).prev_multiple_of(&BigInt::from(-8)),
|
|
||||||
BigInt::from(-16)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_abs_sub() {
|
fn test_abs_sub() {
|
||||||
let zero: BigInt = Zero::zero();
|
let zero: BigInt = Zero::zero();
|
||||||
|
@ -1139,7 +1022,7 @@ fn test_from_str_radix() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lower_hex() {
|
fn test_lower_hex() {
|
||||||
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigInt::parse_bytes(b"-22405534230753963835153736737", 10).unwrap();
|
let hello = BigInt::parse_bytes("-22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:x}", a), "a");
|
assert_eq!(format!("{:x}", a), "a");
|
||||||
assert_eq!(format!("{:x}", hello), "-48656c6c6f20776f726c6421");
|
assert_eq!(format!("{:x}", hello), "-48656c6c6f20776f726c6421");
|
||||||
|
@ -1149,7 +1032,7 @@ fn test_lower_hex() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_upper_hex() {
|
fn test_upper_hex() {
|
||||||
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigInt::parse_bytes(b"-22405534230753963835153736737", 10).unwrap();
|
let hello = BigInt::parse_bytes("-22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:X}", a), "A");
|
assert_eq!(format!("{:X}", a), "A");
|
||||||
assert_eq!(format!("{:X}", hello), "-48656C6C6F20776F726C6421");
|
assert_eq!(format!("{:X}", hello), "-48656C6C6F20776F726C6421");
|
||||||
|
@ -1159,7 +1042,7 @@ fn test_upper_hex() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_binary() {
|
fn test_binary() {
|
||||||
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigInt::parse_bytes(b"-224055342307539", 10).unwrap();
|
let hello = BigInt::parse_bytes("-224055342307539".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:b}", a), "1010");
|
assert_eq!(format!("{:b}", a), "1010");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1172,7 +1055,7 @@ fn test_binary() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_octal() {
|
fn test_octal() {
|
||||||
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigInt::parse_bytes(b"-22405534230753963835153736737", 10).unwrap();
|
let hello = BigInt::parse_bytes("-22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:o}", a), "12");
|
assert_eq!(format!("{:o}", a), "12");
|
||||||
assert_eq!(format!("{:o}", hello), "-22062554330674403566756233062041");
|
assert_eq!(format!("{:o}", hello), "-22062554330674403566756233062041");
|
||||||
|
@ -1182,7 +1065,7 @@ fn test_octal() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
let a = BigInt::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigInt::parse_bytes(b"-22405534230753963835153736737", 10).unwrap();
|
let hello = BigInt::parse_bytes("-22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{}", a), "10");
|
assert_eq!(format!("{}", a), "10");
|
||||||
assert_eq!(format!("{}", hello), "-22405534230753963835153736737");
|
assert_eq!(format!("{}", hello), "-22405534230753963835153736737");
|
||||||
|
@ -1205,6 +1088,25 @@ fn test_negative_shr() {
|
||||||
assert_eq!(BigInt::from(-3) >> 2, BigInt::from(-1));
|
assert_eq!(BigInt::from(-3) >> 2, BigInt::from(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
|
fn test_random_shr() {
|
||||||
|
use rand::distributions::Standard;
|
||||||
|
use rand::Rng;
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
for p in rng.sample_iter::<i64, _>(&Standard).take(1000) {
|
||||||
|
let big = BigInt::from(p);
|
||||||
|
let bigger = &big << 1000;
|
||||||
|
assert_eq!(&bigger >> 1000, big);
|
||||||
|
for i in 0..64 {
|
||||||
|
let answer = BigInt::from(p >> i);
|
||||||
|
assert_eq!(&big >> i, answer);
|
||||||
|
assert_eq!(&bigger >> (1000 + i), answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter_sum() {
|
fn test_iter_sum() {
|
||||||
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
||||||
|
@ -1218,8 +1120,8 @@ fn test_iter_sum() {
|
||||||
FromPrimitive::from_i32(-7).unwrap(),
|
FromPrimitive::from_i32(-7).unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(result, data.iter().sum::<BigInt>());
|
assert_eq!(result, data.iter().sum());
|
||||||
assert_eq!(result, data.into_iter().sum::<BigInt>());
|
assert_eq!(result, data.into_iter().sum());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1237,8 +1139,8 @@ fn test_iter_product() {
|
||||||
* data.get(3).unwrap()
|
* data.get(3).unwrap()
|
||||||
* data.get(4).unwrap();
|
* data.get(4).unwrap();
|
||||||
|
|
||||||
assert_eq!(result, data.iter().product::<BigInt>());
|
assert_eq!(result, data.iter().product());
|
||||||
assert_eq!(result, data.into_iter().product::<BigInt>());
|
assert_eq!(result, data.into_iter().product());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1246,8 +1148,8 @@ fn test_iter_sum_generic() {
|
||||||
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
||||||
let data = vec![-1000000, -200000, -30000, -4000, -500, -60, -7];
|
let data = vec![-1000000, -200000, -30000, -4000, -500, -60, -7];
|
||||||
|
|
||||||
assert_eq!(result, data.iter().sum::<BigInt>());
|
assert_eq!(result, data.iter().sum());
|
||||||
assert_eq!(result, data.into_iter().sum::<BigInt>());
|
assert_eq!(result, data.into_iter().sum());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1259,8 +1161,8 @@ fn test_iter_product_generic() {
|
||||||
* data[3].to_bigint().unwrap()
|
* data[3].to_bigint().unwrap()
|
||||||
* data[4].to_bigint().unwrap();
|
* data[4].to_bigint().unwrap();
|
||||||
|
|
||||||
assert_eq!(result, data.iter().product::<BigInt>());
|
assert_eq!(result, data.iter().product());
|
||||||
assert_eq!(result, data.into_iter().product::<BigInt>());
|
assert_eq!(result, data.into_iter().product());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1272,15 +1174,15 @@ fn test_pow() {
|
||||||
let minus_two = BigInt::from(-2i32);
|
let minus_two = BigInt::from(-2i32);
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($t:ty) => {
|
($t:ty) => {
|
||||||
assert_eq!(Pow::pow(&two, 0 as $t), one);
|
assert_eq!(two.pow(0 as $t), one);
|
||||||
assert_eq!(Pow::pow(&two, 1 as $t), two);
|
assert_eq!(two.pow(1 as $t), two);
|
||||||
assert_eq!(Pow::pow(&two, 2 as $t), four);
|
assert_eq!(two.pow(2 as $t), four);
|
||||||
assert_eq!(Pow::pow(&two, 3 as $t), eight);
|
assert_eq!(two.pow(3 as $t), eight);
|
||||||
assert_eq!(Pow::pow(&two, &(3 as $t)), eight);
|
assert_eq!(two.pow(&(3 as $t)), eight);
|
||||||
assert_eq!(Pow::pow(&minus_two, 0 as $t), one, "-2^0");
|
assert_eq!(minus_two.pow(0 as $t), one, "-2^0");
|
||||||
assert_eq!(Pow::pow(&minus_two, 1 as $t), minus_two, "-2^1");
|
assert_eq!(minus_two.pow(1 as $t), minus_two, "-2^1");
|
||||||
assert_eq!(Pow::pow(&minus_two, 2 as $t), four, "-2^2");
|
assert_eq!(minus_two.pow(2 as $t), four, "-2^2");
|
||||||
assert_eq!(Pow::pow(&minus_two, 3 as $t), -&eight, "-2^3");
|
assert_eq!(minus_two.pow(3 as $t), -&eight, "-2^3");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
check!(u8);
|
check!(u8);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
use num_bigint::{BigInt, Sign, ToBigInt};
|
use num_bigint::{BigInt, Sign, ToBigInt};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
use std::{i32, i64, u32};
|
use std::{i32, i64, u32};
|
||||||
|
@ -8,7 +11,7 @@ enum ValueVec {
|
||||||
M(&'static [u32]),
|
M(&'static [u32]),
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::ValueVec::*;
|
use ValueVec::*;
|
||||||
|
|
||||||
impl ToBigInt for ValueVec {
|
impl ToBigInt for ValueVec {
|
||||||
fn to_bigint(&self) -> Option<BigInt> {
|
fn to_bigint(&self) -> Option<BigInt> {
|
||||||
|
@ -21,7 +24,7 @@ impl ToBigInt for ValueVec {
|
||||||
}
|
}
|
||||||
|
|
||||||
// a, !a
|
// a, !a
|
||||||
const NOT_VALUES: &[(ValueVec, ValueVec)] = &[
|
const NOT_VALUES: &'static [(ValueVec, ValueVec)] = &[
|
||||||
(N, M(&[1])),
|
(N, M(&[1])),
|
||||||
(P(&[1]), M(&[2])),
|
(P(&[1]), M(&[2])),
|
||||||
(P(&[2]), M(&[3])),
|
(P(&[2]), M(&[3])),
|
||||||
|
@ -33,7 +36,7 @@ const NOT_VALUES: &[(ValueVec, ValueVec)] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
// a, b, a & b, a | b, a ^ b
|
// a, b, a & b, a | b, a ^ b
|
||||||
const BITWISE_VALUES: &[(ValueVec, ValueVec, ValueVec, ValueVec, ValueVec)] = &[
|
const BITWISE_VALUES: &'static [(ValueVec, ValueVec, ValueVec, ValueVec, ValueVec)] = &[
|
||||||
(N, N, N, N, N),
|
(N, N, N, N, N),
|
||||||
(N, P(&[1]), N, P(&[1]), P(&[1])),
|
(N, P(&[1]), N, P(&[1]), P(&[1])),
|
||||||
(N, P(&[!0]), N, P(&[!0]), P(&[!0])),
|
(N, P(&[!0]), N, P(&[!0]), P(&[!0])),
|
||||||
|
@ -59,7 +62,7 @@ const I32_MAX: i64 = i32::MAX as i64;
|
||||||
const U32_MAX: i64 = u32::MAX as i64;
|
const U32_MAX: i64 = u32::MAX as i64;
|
||||||
|
|
||||||
// some corner cases
|
// some corner cases
|
||||||
const I64_VALUES: &[i64] = &[
|
const I64_VALUES: &'static [i64] = &[
|
||||||
i64::MIN,
|
i64::MIN,
|
||||||
i64::MIN + 1,
|
i64::MIN + 1,
|
||||||
i64::MIN + 2,
|
i64::MIN + 2,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_bigint::Sign::Plus;
|
use num_bigint::Sign::Plus;
|
||||||
use num_traits::{Signed, ToPrimitive, Zero};
|
use num_traits::{Signed, ToPrimitive, Zero};
|
||||||
|
@ -5,7 +8,7 @@ use num_traits::{Signed, ToPrimitive, Zero};
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
use crate::consts::*;
|
use consts::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -15,7 +18,6 @@ fn test_scalar_add() {
|
||||||
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
||||||
assert_signed_scalar_op!(x + y == z);
|
assert_signed_scalar_op!(x + y == z);
|
||||||
assert_signed_scalar_assign_op!(x += y == z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
for elm in SUM_TRIPLES.iter() {
|
||||||
|
@ -41,7 +43,6 @@ fn test_scalar_sub() {
|
||||||
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
||||||
assert_signed_scalar_op!(x - y == z);
|
assert_signed_scalar_op!(x - y == z);
|
||||||
assert_signed_scalar_assign_op!(x -= y == z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
for elm in SUM_TRIPLES.iter() {
|
||||||
|
@ -67,7 +68,6 @@ fn test_scalar_mul() {
|
||||||
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
||||||
assert_signed_scalar_op!(x * y == z);
|
assert_signed_scalar_op!(x * y == z);
|
||||||
assert_signed_scalar_assign_op!(x *= y == z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
for elm in MUL_TRIPLES.iter() {
|
||||||
|
@ -93,23 +93,20 @@ fn test_scalar_div_rem() {
|
||||||
if !r.is_zero() {
|
if !r.is_zero() {
|
||||||
assert_eq!(r.sign(), a.sign());
|
assert_eq!(r.sign(), a.sign());
|
||||||
}
|
}
|
||||||
assert!(r.abs() <= BigInt::from(b));
|
assert!(r.abs() <= From::from(b));
|
||||||
assert!(*a == b * &q + &r);
|
assert!(*a == b * &q + &r);
|
||||||
assert!(q == *ans_q);
|
assert!(q == *ans_q);
|
||||||
assert!(r == *ans_r);
|
assert!(r == *ans_r);
|
||||||
|
|
||||||
let b = BigInt::from(b);
|
let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone());
|
||||||
let (a, ans_q, ans_r) = (a.clone(), ans_q.clone(), ans_r.clone());
|
assert_op!(a / b == ans_q);
|
||||||
assert_signed_scalar_op!(a / b == ans_q);
|
assert_op!(a % b == ans_r);
|
||||||
assert_signed_scalar_op!(a % b == ans_r);
|
|
||||||
assert_signed_scalar_assign_op!(a /= b == ans_q);
|
|
||||||
assert_signed_scalar_assign_op!(a %= b == ans_r);
|
|
||||||
|
|
||||||
let nb = -b;
|
if b <= i32::max_value() as u32 {
|
||||||
assert_signed_scalar_op!(a / nb == -ans_q.clone());
|
let nb = -(b as i32);
|
||||||
assert_signed_scalar_op!(a % nb == ans_r);
|
assert_op!(a / nb == -ans_q.clone());
|
||||||
assert_signed_scalar_assign_op!(a /= nb == -ans_q.clone());
|
assert_op!(a % nb == ans_r);
|
||||||
assert_signed_scalar_assign_op!(a %= nb == ans_r);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {
|
fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
use num_bigint::Sign::Plus;
|
use num_bigint::Sign::Plus;
|
||||||
use num_bigint::{BigInt, ToBigInt};
|
use num_bigint::{BigInt, ToBigInt};
|
||||||
use num_bigint::{BigUint, ToBigUint};
|
use num_bigint::{BigUint, ToBigUint};
|
||||||
|
@ -10,16 +14,17 @@ use std::i64;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{f32, f64};
|
use std::{f32, f64};
|
||||||
|
#[cfg(has_i128)]
|
||||||
use std::{i128, u128};
|
use std::{i128, u128};
|
||||||
use std::{u16, u32, u64, u8, usize};
|
use std::{u16, u32, u64, u8, usize};
|
||||||
|
|
||||||
use num_traits::{
|
use num_traits::{
|
||||||
pow, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Num, One, Pow, ToPrimitive,
|
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Float, FromPrimitive, Num, One, Pow,
|
||||||
Zero,
|
ToPrimitive, Zero,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
use crate::consts::*;
|
use consts::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -36,7 +41,7 @@ fn test_from_bytes_be() {
|
||||||
check("AA", "16705");
|
check("AA", "16705");
|
||||||
check("AB", "16706");
|
check("AB", "16706");
|
||||||
check("Hello world!", "22405534230753963835153736737");
|
check("Hello world!", "22405534230753963835153736737");
|
||||||
assert_eq!(BigUint::from_bytes_be(&[]), BigUint::zero());
|
assert_eq!(BigUint::from_bytes_be(&[]), Zero::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -69,7 +74,7 @@ fn test_from_bytes_le() {
|
||||||
check("AA", "16705");
|
check("AA", "16705");
|
||||||
check("BA", "16706");
|
check("BA", "16706");
|
||||||
check("!dlrow olleH", "22405534230753963835153736737");
|
check("!dlrow olleH", "22405534230753963835153736737");
|
||||||
assert_eq!(BigUint::from_bytes_le(&[]), BigUint::zero());
|
assert_eq!(BigUint::from_bytes_le(&[]), Zero::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -135,7 +140,7 @@ fn hash<T: Hash>(x: &T) -> u64 {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hash() {
|
fn test_hash() {
|
||||||
use crate::hash;
|
use hash;
|
||||||
|
|
||||||
let a = BigUint::new(vec![]);
|
let a = BigUint::new(vec![]);
|
||||||
let b = BigUint::new(vec![0]);
|
let b = BigUint::new(vec![0]);
|
||||||
|
@ -149,7 +154,13 @@ fn test_hash() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LEFT, RIGHT, AND, OR, XOR
|
// LEFT, RIGHT, AND, OR, XOR
|
||||||
const BIT_TESTS: &[(&[u32], &[u32], &[u32], &[u32], &[u32])] = &[
|
const BIT_TESTS: &'static [(
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
)] = &[
|
||||||
(&[], &[], &[], &[], &[]),
|
(&[], &[], &[], &[], &[]),
|
||||||
(&[1, 0, 1], &[1, 1], &[1], &[1, 1, 1], &[0, 1, 1]),
|
(&[1, 0, 1], &[1, 1], &[1], &[1, 1, 1], &[0, 1, 1]),
|
||||||
(&[1, 0, 1], &[0, 1, 1], &[0, 0, 1], &[1, 1, 1], &[1, 1]),
|
(&[1, 0, 1], &[0, 1, 1], &[0, 0, 1], &[1, 1, 1], &[1, 1]),
|
||||||
|
@ -531,6 +542,7 @@ fn test_convert_i64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(has_i128)]
|
||||||
fn test_convert_i128() {
|
fn test_convert_i128() {
|
||||||
fn check(b1: BigUint, i: i128) {
|
fn check(b1: BigUint, i: i128) {
|
||||||
let b2: BigUint = FromPrimitive::from_i128(i).unwrap();
|
let b2: BigUint = FromPrimitive::from_i128(i).unwrap();
|
||||||
|
@ -579,6 +591,7 @@ fn test_convert_u64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(has_i128)]
|
||||||
fn test_convert_u128() {
|
fn test_convert_u128() {
|
||||||
fn check(b1: BigUint, u: u128) {
|
fn check(b1: BigUint, u: u128) {
|
||||||
let b2: BigUint = FromPrimitive::from_u128(u).unwrap();
|
let b2: BigUint = FromPrimitive::from_u128(u).unwrap();
|
||||||
|
@ -602,7 +615,6 @@ fn test_convert_u128() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::float_cmp)]
|
|
||||||
fn test_convert_f32() {
|
fn test_convert_f32() {
|
||||||
fn check(b1: &BigUint, f: f32) {
|
fn check(b1: &BigUint, f: f32) {
|
||||||
let b2 = BigUint::from_f32(f).unwrap();
|
let b2 = BigUint::from_f32(f).unwrap();
|
||||||
|
@ -612,14 +624,14 @@ fn test_convert_f32() {
|
||||||
|
|
||||||
check(&BigUint::zero(), 0.0);
|
check(&BigUint::zero(), 0.0);
|
||||||
check(&BigUint::one(), 1.0);
|
check(&BigUint::one(), 1.0);
|
||||||
check(&BigUint::from(u16::MAX), pow(2.0_f32, 16) - 1.0);
|
check(&BigUint::from(u16::MAX), 2.0.powi(16) - 1.0);
|
||||||
check(&BigUint::from(1u64 << 32), pow(2.0_f32, 32));
|
check(&BigUint::from(1u64 << 32), 2.0.powi(32));
|
||||||
check(&BigUint::from_slice(&[0, 0, 1]), pow(2.0_f32, 64));
|
check(&BigUint::from_slice(&[0, 0, 1]), 2.0.powi(64));
|
||||||
check(
|
check(
|
||||||
&((BigUint::one() << 100) + (BigUint::one() << 123)),
|
&((BigUint::one() << 100) + (BigUint::one() << 123)),
|
||||||
pow(2.0_f32, 100) + pow(2.0_f32, 123),
|
2.0.powi(100) + 2.0.powi(123),
|
||||||
);
|
);
|
||||||
check(&(BigUint::one() << 127), pow(2.0_f32, 127));
|
check(&(BigUint::one() << 127), 2.0.powi(127));
|
||||||
check(&(BigUint::from((1u64 << 24) - 1) << (128 - 24)), f32::MAX);
|
check(&(BigUint::from((1u64 << 24) - 1) << (128 - 24)), f32::MAX);
|
||||||
|
|
||||||
// keeping all 24 digits with the bits at different offsets to the BigDigits
|
// keeping all 24 digits with the bits at different offsets to the BigDigits
|
||||||
|
@ -629,7 +641,7 @@ fn test_convert_f32() {
|
||||||
for _ in 0..64 {
|
for _ in 0..64 {
|
||||||
check(&b, f);
|
check(&b, f);
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this number when rounded to f64 then f32 isn't the same as when rounded straight to f32
|
// this number when rounded to f64 then f32 isn't the same as when rounded straight to f32
|
||||||
|
@ -643,7 +655,7 @@ fn test_convert_f32() {
|
||||||
for _ in 0..64 {
|
for _ in 0..64 {
|
||||||
assert_eq!(b.to_f32(), Some(f));
|
assert_eq!(b.to_f32(), Some(f));
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding
|
// rounding
|
||||||
|
@ -671,16 +683,15 @@ fn test_convert_f32() {
|
||||||
assert_eq!(BigUint::from_f32(f32::MIN), None);
|
assert_eq!(BigUint::from_f32(f32::MIN), None);
|
||||||
|
|
||||||
// largest BigUint that will round to a finite f32 value
|
// largest BigUint that will round to a finite f32 value
|
||||||
let big_num = (BigUint::one() << 128u8) - 1u8 - (BigUint::one() << (128u8 - 25));
|
let big_num = (BigUint::one() << 128) - BigUint::one() - (BigUint::one() << (128 - 25));
|
||||||
assert_eq!(big_num.to_f32(), Some(f32::MAX));
|
assert_eq!(big_num.to_f32(), Some(f32::MAX));
|
||||||
assert_eq!((big_num + 1u8).to_f32(), None);
|
assert_eq!((big_num + BigUint::one()).to_f32(), None);
|
||||||
|
|
||||||
assert_eq!(((BigUint::one() << 128u8) - 1u8).to_f32(), None);
|
assert_eq!(((BigUint::one() << 128) - BigUint::one()).to_f32(), None);
|
||||||
assert_eq!((BigUint::one() << 128u8).to_f32(), None);
|
assert_eq!((BigUint::one() << 128).to_f32(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::float_cmp)]
|
|
||||||
fn test_convert_f64() {
|
fn test_convert_f64() {
|
||||||
fn check(b1: &BigUint, f: f64) {
|
fn check(b1: &BigUint, f: f64) {
|
||||||
let b2 = BigUint::from_f64(f).unwrap();
|
let b2 = BigUint::from_f64(f).unwrap();
|
||||||
|
@ -690,14 +701,14 @@ fn test_convert_f64() {
|
||||||
|
|
||||||
check(&BigUint::zero(), 0.0);
|
check(&BigUint::zero(), 0.0);
|
||||||
check(&BigUint::one(), 1.0);
|
check(&BigUint::one(), 1.0);
|
||||||
check(&BigUint::from(u32::MAX), pow(2.0_f64, 32) - 1.0);
|
check(&BigUint::from(u32::MAX), 2.0.powi(32) - 1.0);
|
||||||
check(&BigUint::from(1u64 << 32), pow(2.0_f64, 32));
|
check(&BigUint::from(1u64 << 32), 2.0.powi(32));
|
||||||
check(&BigUint::from_slice(&[0, 0, 1]), pow(2.0_f64, 64));
|
check(&BigUint::from_slice(&[0, 0, 1]), 2.0.powi(64));
|
||||||
check(
|
check(
|
||||||
&((BigUint::one() << 100) + (BigUint::one() << 152)),
|
&((BigUint::one() << 100) + (BigUint::one() << 152)),
|
||||||
pow(2.0_f64, 100) + pow(2.0_f64, 152),
|
2.0.powi(100) + 2.0.powi(152),
|
||||||
);
|
);
|
||||||
check(&(BigUint::one() << 1023), pow(2.0_f64, 1023));
|
check(&(BigUint::one() << 1023), 2.0.powi(1023));
|
||||||
check(&(BigUint::from((1u64 << 53) - 1) << (1024 - 53)), f64::MAX);
|
check(&(BigUint::from((1u64 << 53) - 1) << (1024 - 53)), f64::MAX);
|
||||||
|
|
||||||
// keeping all 53 digits with the bits at different offsets to the BigDigits
|
// keeping all 53 digits with the bits at different offsets to the BigDigits
|
||||||
|
@ -707,7 +718,7 @@ fn test_convert_f64() {
|
||||||
for _ in 0..128 {
|
for _ in 0..128 {
|
||||||
check(&b, f);
|
check(&b, f);
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test rounding up with the bits at different offsets to the BigDigits
|
// test rounding up with the bits at different offsets to the BigDigits
|
||||||
|
@ -716,7 +727,7 @@ fn test_convert_f64() {
|
||||||
for _ in 0..128 {
|
for _ in 0..128 {
|
||||||
assert_eq!(b.to_f64(), Some(f));
|
assert_eq!(b.to_f64(), Some(f));
|
||||||
f *= 2.0;
|
f *= 2.0;
|
||||||
b <<= 1;
|
b = b << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding
|
// rounding
|
||||||
|
@ -744,12 +755,12 @@ fn test_convert_f64() {
|
||||||
assert_eq!(BigUint::from_f64(f64::MIN), None);
|
assert_eq!(BigUint::from_f64(f64::MIN), None);
|
||||||
|
|
||||||
// largest BigUint that will round to a finite f64 value
|
// largest BigUint that will round to a finite f64 value
|
||||||
let big_num = (BigUint::one() << 1024u16) - 1u8 - (BigUint::one() << (1024u16 - 54));
|
let big_num = (BigUint::one() << 1024) - BigUint::one() - (BigUint::one() << (1024 - 54));
|
||||||
assert_eq!(big_num.to_f64(), Some(f64::MAX));
|
assert_eq!(big_num.to_f64(), Some(f64::MAX));
|
||||||
assert_eq!((big_num + 1u8).to_f64(), None);
|
assert_eq!((big_num + BigUint::one()).to_f64(), None);
|
||||||
|
|
||||||
assert_eq!(((BigUint::one() << 1024u16) - 1u8).to_f64(), None);
|
assert_eq!(((BigInt::one() << 1024) - BigInt::one()).to_f64(), None);
|
||||||
assert_eq!((BigUint::one() << 1024u16).to_f64(), None);
|
assert_eq!((BigUint::one() << 1024).to_f64(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -780,6 +791,7 @@ fn test_convert_from_uint() {
|
||||||
check!(u16, BigUint::from_slice(&[u16::MAX as u32]));
|
check!(u16, BigUint::from_slice(&[u16::MAX as u32]));
|
||||||
check!(u32, BigUint::from_slice(&[u32::MAX]));
|
check!(u32, BigUint::from_slice(&[u32::MAX]));
|
||||||
check!(u64, BigUint::from_slice(&[u32::MAX, u32::MAX]));
|
check!(u64, BigUint::from_slice(&[u32::MAX, u32::MAX]));
|
||||||
|
#[cfg(has_i128)]
|
||||||
check!(
|
check!(
|
||||||
u128,
|
u128,
|
||||||
BigUint::from_slice(&[u32::MAX, u32::MAX, u32::MAX, u32::MAX])
|
BigUint::from_slice(&[u32::MAX, u32::MAX, u32::MAX, u32::MAX])
|
||||||
|
@ -860,17 +872,17 @@ fn test_div_rem() {
|
||||||
|
|
||||||
if !a.is_zero() {
|
if !a.is_zero() {
|
||||||
assert_op!(c / a == b);
|
assert_op!(c / a == b);
|
||||||
assert_op!(c % a == BigUint::zero());
|
assert_op!(c % a == Zero::zero());
|
||||||
assert_assign_op!(c /= a == b);
|
assert_assign_op!(c /= a == b);
|
||||||
assert_assign_op!(c %= a == BigUint::zero());
|
assert_assign_op!(c %= a == Zero::zero());
|
||||||
assert_eq!(c.div_rem(&a), (b.clone(), BigUint::zero()));
|
assert_eq!(c.div_rem(&a), (b.clone(), Zero::zero()));
|
||||||
}
|
}
|
||||||
if !b.is_zero() {
|
if !b.is_zero() {
|
||||||
assert_op!(c / b == a);
|
assert_op!(c / b == a);
|
||||||
assert_op!(c % b == BigUint::zero());
|
assert_op!(c % b == Zero::zero());
|
||||||
assert_assign_op!(c /= b == a);
|
assert_assign_op!(c /= b == a);
|
||||||
assert_assign_op!(c %= b == BigUint::zero());
|
assert_assign_op!(c %= b == Zero::zero());
|
||||||
assert_eq!(c.div_rem(&b), (a.clone(), BigUint::zero()));
|
assert_eq!(c.div_rem(&b), (a.clone(), Zero::zero()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -891,43 +903,6 @@ fn test_div_rem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_div_ceil() {
|
|
||||||
fn check(a: &BigUint, b: &BigUint, d: &BigUint, m: &BigUint) {
|
|
||||||
if m.is_zero() {
|
|
||||||
assert_eq!(a.div_ceil(b), *d);
|
|
||||||
} else {
|
|
||||||
assert_eq!(a.div_ceil(b), d + 1u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
|
|
||||||
if !a.is_zero() {
|
|
||||||
check(&c, &a, &b, &Zero::zero());
|
|
||||||
}
|
|
||||||
if !b.is_zero() {
|
|
||||||
check(&c, &b, &a, &Zero::zero());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for elm in DIV_REM_QUADRUPLES.iter() {
|
|
||||||
let (a_vec, b_vec, c_vec, d_vec) = *elm;
|
|
||||||
let a = BigUint::from_slice(a_vec);
|
|
||||||
let b = BigUint::from_slice(b_vec);
|
|
||||||
let c = BigUint::from_slice(c_vec);
|
|
||||||
let d = BigUint::from_slice(d_vec);
|
|
||||||
|
|
||||||
if !b.is_zero() {
|
|
||||||
check(&a, &b, &c, &d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_checked_add() {
|
fn test_checked_add() {
|
||||||
for elm in SUM_TRIPLES.iter() {
|
for elm in SUM_TRIPLES.iter() {
|
||||||
|
@ -1021,7 +996,6 @@ fn test_gcd() {
|
||||||
let big_c: BigUint = FromPrimitive::from_usize(c).unwrap();
|
let big_c: BigUint = FromPrimitive::from_usize(c).unwrap();
|
||||||
|
|
||||||
assert_eq!(big_a.gcd(&big_b), big_c);
|
assert_eq!(big_a.gcd(&big_b), big_c);
|
||||||
assert_eq!(big_a.gcd_lcm(&big_b).0, big_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check(10, 2, 2);
|
check(10, 2, 2);
|
||||||
|
@ -1039,7 +1013,6 @@ fn test_lcm() {
|
||||||
let big_c: BigUint = FromPrimitive::from_usize(c).unwrap();
|
let big_c: BigUint = FromPrimitive::from_usize(c).unwrap();
|
||||||
|
|
||||||
assert_eq!(big_a.lcm(&big_b), big_c);
|
assert_eq!(big_a.lcm(&big_b), big_c);
|
||||||
assert_eq!(big_a.gcd_lcm(&big_b).1, big_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check(0, 0, 0);
|
check(0, 0, 0);
|
||||||
|
@ -1051,30 +1024,6 @@ fn test_lcm() {
|
||||||
check(99, 17, 1683);
|
check(99, 17, 1683);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_next_multiple_of() {
|
|
||||||
assert_eq!(
|
|
||||||
BigUint::from(16u32).next_multiple_of(&BigUint::from(8u32)),
|
|
||||||
BigUint::from(16u32)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigUint::from(23u32).next_multiple_of(&BigUint::from(8u32)),
|
|
||||||
BigUint::from(24u32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_prev_multiple_of() {
|
|
||||||
assert_eq!(
|
|
||||||
BigUint::from(16u32).prev_multiple_of(&BigUint::from(8u32)),
|
|
||||||
BigUint::from(16u32)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
BigUint::from(23u32).prev_multiple_of(&BigUint::from(8u32)),
|
|
||||||
BigUint::from(16u32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_even() {
|
fn test_is_even() {
|
||||||
let one: BigUint = FromStr::from_str("1").unwrap();
|
let one: BigUint = FromStr::from_str("1").unwrap();
|
||||||
|
@ -1087,8 +1036,8 @@ fn test_is_even() {
|
||||||
assert!(thousand.is_even());
|
assert!(thousand.is_even());
|
||||||
assert!(big.is_even());
|
assert!(big.is_even());
|
||||||
assert!(bigger.is_odd());
|
assert!(bigger.is_odd());
|
||||||
assert!((&one << 64u8).is_even());
|
assert!((&one << 64).is_even());
|
||||||
assert!(((&one << 64u8) + one).is_odd());
|
assert!(((&one << 64) + one).is_odd());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_str_pairs() -> Vec<(BigUint, Vec<(u32, String)>)> {
|
fn to_str_pairs() -> Vec<(BigUint, Vec<(u32, String)>)> {
|
||||||
|
@ -1216,7 +1165,7 @@ fn test_to_str_radix() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_and_to_radix() {
|
fn test_from_and_to_radix() {
|
||||||
const GROUND_TRUTH: &[(&[u8], u32, &[u8])] = &[
|
const GROUND_TRUTH: &'static [(&'static [u8], u32, &'static [u8])] = &[
|
||||||
(b"0", 42, &[0]),
|
(b"0", 42, &[0]),
|
||||||
(
|
(
|
||||||
b"ffffeeffbb",
|
b"ffffeeffbb",
|
||||||
|
@ -1566,6 +1515,9 @@ fn test_from_str_radix() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_all_str_radix() {
|
fn test_all_str_radix() {
|
||||||
|
#[allow(deprecated, unused_imports)]
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
|
||||||
let n = BigUint::new((0..10).collect());
|
let n = BigUint::new((0..10).collect());
|
||||||
for radix in 2..37 {
|
for radix in 2..37 {
|
||||||
let s = n.to_str_radix(radix);
|
let s = n.to_str_radix(radix);
|
||||||
|
@ -1581,7 +1533,7 @@ fn test_all_str_radix() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lower_hex() {
|
fn test_lower_hex() {
|
||||||
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigUint::parse_bytes(b"22405534230753963835153736737", 10).unwrap();
|
let hello = BigUint::parse_bytes("22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:x}", a), "a");
|
assert_eq!(format!("{:x}", a), "a");
|
||||||
assert_eq!(format!("{:x}", hello), "48656c6c6f20776f726c6421");
|
assert_eq!(format!("{:x}", hello), "48656c6c6f20776f726c6421");
|
||||||
|
@ -1591,7 +1543,7 @@ fn test_lower_hex() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_upper_hex() {
|
fn test_upper_hex() {
|
||||||
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigUint::parse_bytes(b"22405534230753963835153736737", 10).unwrap();
|
let hello = BigUint::parse_bytes("22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:X}", a), "A");
|
assert_eq!(format!("{:X}", a), "A");
|
||||||
assert_eq!(format!("{:X}", hello), "48656C6C6F20776F726C6421");
|
assert_eq!(format!("{:X}", hello), "48656C6C6F20776F726C6421");
|
||||||
|
@ -1601,7 +1553,7 @@ fn test_upper_hex() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_binary() {
|
fn test_binary() {
|
||||||
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigUint::parse_bytes(b"224055342307539", 10).unwrap();
|
let hello = BigUint::parse_bytes("224055342307539".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:b}", a), "1010");
|
assert_eq!(format!("{:b}", a), "1010");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1614,7 +1566,7 @@ fn test_binary() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_octal() {
|
fn test_octal() {
|
||||||
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigUint::parse_bytes(b"22405534230753963835153736737", 10).unwrap();
|
let hello = BigUint::parse_bytes("22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{:o}", a), "12");
|
assert_eq!(format!("{:o}", a), "12");
|
||||||
assert_eq!(format!("{:o}", hello), "22062554330674403566756233062041");
|
assert_eq!(format!("{:o}", hello), "22062554330674403566756233062041");
|
||||||
|
@ -1624,7 +1576,7 @@ fn test_octal() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_display() {
|
fn test_display() {
|
||||||
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
let a = BigUint::parse_bytes(b"A", 16).unwrap();
|
||||||
let hello = BigUint::parse_bytes(b"22405534230753963835153736737", 10).unwrap();
|
let hello = BigUint::parse_bytes("22405534230753963835153736737".as_bytes(), 10).unwrap();
|
||||||
|
|
||||||
assert_eq!(format!("{}", a), "10");
|
assert_eq!(format!("{}", a), "10");
|
||||||
assert_eq!(format!("{}", hello), "22405534230753963835153736737");
|
assert_eq!(format!("{}", hello), "22405534230753963835153736737");
|
||||||
|
@ -1635,18 +1587,21 @@ fn test_display() {
|
||||||
fn test_factor() {
|
fn test_factor() {
|
||||||
fn factor(n: usize) -> BigUint {
|
fn factor(n: usize) -> BigUint {
|
||||||
let mut f: BigUint = One::one();
|
let mut f: BigUint = One::one();
|
||||||
for i in 2..=n {
|
for i in 2..n + 1 {
|
||||||
// FIXME(#5992): assignment operator overloads
|
// FIXME(#5992): assignment operator overloads
|
||||||
// f *= FromPrimitive::from_usize(i);
|
// f *= FromPrimitive::from_usize(i);
|
||||||
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
||||||
f *= bu;
|
f = f * bu;
|
||||||
}
|
}
|
||||||
f
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(n: usize, s: &str) {
|
fn check(n: usize, s: &str) {
|
||||||
let n = factor(n);
|
let n = factor(n);
|
||||||
let ans = BigUint::from_str_radix(s, 10).unwrap();
|
let ans = match BigUint::from_str_radix(s, 10) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(_) => panic!(),
|
||||||
|
};
|
||||||
assert_eq!(n, ans);
|
assert_eq!(n, ans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1668,7 +1623,7 @@ fn test_bits() {
|
||||||
let n: BigUint = BigUint::from_str_radix("4000000000", 16).unwrap();
|
let n: BigUint = BigUint::from_str_radix("4000000000", 16).unwrap();
|
||||||
assert_eq!(n.bits(), 39);
|
assert_eq!(n.bits(), 39);
|
||||||
let one: BigUint = One::one();
|
let one: BigUint = One::one();
|
||||||
assert_eq!((one << 426u16).bits(), 427);
|
assert_eq!((one << 426).bits(), 427);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1684,8 +1639,8 @@ fn test_iter_sum() {
|
||||||
FromPrimitive::from_u32(7).unwrap(),
|
FromPrimitive::from_u32(7).unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(result, data.iter().sum::<BigUint>());
|
assert_eq!(result, data.iter().sum());
|
||||||
assert_eq!(result, data.into_iter().sum::<BigUint>());
|
assert_eq!(result, data.into_iter().sum());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1703,8 +1658,8 @@ fn test_iter_product() {
|
||||||
* data.get(3).unwrap()
|
* data.get(3).unwrap()
|
||||||
* data.get(4).unwrap();
|
* data.get(4).unwrap();
|
||||||
|
|
||||||
assert_eq!(result, data.iter().product::<BigUint>());
|
assert_eq!(result, data.iter().product());
|
||||||
assert_eq!(result, data.into_iter().product::<BigUint>());
|
assert_eq!(result, data.into_iter().product());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1712,8 +1667,8 @@ fn test_iter_sum_generic() {
|
||||||
let result: BigUint = FromPrimitive::from_isize(1234567).unwrap();
|
let result: BigUint = FromPrimitive::from_isize(1234567).unwrap();
|
||||||
let data = vec![1000000_u32, 200000, 30000, 4000, 500, 60, 7];
|
let data = vec![1000000_u32, 200000, 30000, 4000, 500, 60, 7];
|
||||||
|
|
||||||
assert_eq!(result, data.iter().sum::<BigUint>());
|
assert_eq!(result, data.iter().sum());
|
||||||
assert_eq!(result, data.into_iter().sum::<BigUint>());
|
assert_eq!(result, data.into_iter().sum());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1725,8 +1680,8 @@ fn test_iter_product_generic() {
|
||||||
* data[3].to_biguint().unwrap()
|
* data[3].to_biguint().unwrap()
|
||||||
* data[4].to_biguint().unwrap();
|
* data[4].to_biguint().unwrap();
|
||||||
|
|
||||||
assert_eq!(result, data.iter().product::<BigUint>());
|
assert_eq!(result, data.iter().product());
|
||||||
assert_eq!(result, data.into_iter().product::<BigUint>());
|
assert_eq!(result, data.into_iter().product());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1739,19 +1694,20 @@ fn test_pow() {
|
||||||
let twentyfourtyeight = BigUint::from(2048u32);
|
let twentyfourtyeight = BigUint::from(2048u32);
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($t:ty) => {
|
($t:ty) => {
|
||||||
assert_eq!(Pow::pow(&two, 0 as $t), one);
|
assert_eq!(two.pow(0 as $t), one);
|
||||||
assert_eq!(Pow::pow(&two, 1 as $t), two);
|
assert_eq!(two.pow(1 as $t), two);
|
||||||
assert_eq!(Pow::pow(&two, 2 as $t), four);
|
assert_eq!(two.pow(2 as $t), four);
|
||||||
assert_eq!(Pow::pow(&two, 3 as $t), eight);
|
assert_eq!(two.pow(3 as $t), eight);
|
||||||
assert_eq!(Pow::pow(&two, 10 as $t), tentwentyfour);
|
assert_eq!(two.pow(10 as $t), tentwentyfour);
|
||||||
assert_eq!(Pow::pow(&two, 11 as $t), twentyfourtyeight);
|
assert_eq!(two.pow(11 as $t), twentyfourtyeight);
|
||||||
assert_eq!(Pow::pow(&two, &(11 as $t)), twentyfourtyeight);
|
assert_eq!(two.pow(&(11 as $t)), twentyfourtyeight);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
check!(u8);
|
check!(u8);
|
||||||
check!(u16);
|
check!(u16);
|
||||||
check!(u32);
|
check!(u32);
|
||||||
check!(u64);
|
check!(u64);
|
||||||
check!(u128);
|
|
||||||
check!(usize);
|
check!(usize);
|
||||||
|
#[cfg(has_i128)]
|
||||||
|
check!(u128);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_traits::{ToPrimitive, Zero};
|
use num_traits::{ToPrimitive, Zero};
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
use crate::consts::*;
|
use consts::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -12,7 +15,6 @@ fn test_scalar_add() {
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
||||||
assert_unsigned_scalar_op!(x + y == z);
|
assert_unsigned_scalar_op!(x + y == z);
|
||||||
assert_unsigned_scalar_assign_op!(x += y == z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
for elm in SUM_TRIPLES.iter() {
|
||||||
|
@ -31,7 +33,6 @@ fn test_scalar_sub() {
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
||||||
assert_unsigned_scalar_op!(x - y == z);
|
assert_unsigned_scalar_op!(x - y == z);
|
||||||
assert_unsigned_scalar_assign_op!(x -= y == z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in SUM_TRIPLES.iter() {
|
for elm in SUM_TRIPLES.iter() {
|
||||||
|
@ -50,7 +51,6 @@ fn test_scalar_mul() {
|
||||||
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
fn check(x: &BigUint, y: &BigUint, z: &BigUint) {
|
||||||
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
let (x, y, z) = (x.clone(), y.clone(), z.clone());
|
||||||
assert_unsigned_scalar_op!(x * y == z);
|
assert_unsigned_scalar_op!(x * y == z);
|
||||||
assert_unsigned_scalar_assign_op!(x *= y == z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
for elm in MUL_TRIPLES.iter() {
|
||||||
|
@ -66,8 +66,8 @@ fn test_scalar_mul() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scalar_rem_noncommutative() {
|
fn test_scalar_rem_noncommutative() {
|
||||||
assert_eq!(5u8 % BigUint::from(7u8), BigUint::from(5u8));
|
assert_eq!(5u8 % BigUint::from(7u8), 5u8.into());
|
||||||
assert_eq!(BigUint::from(5u8) % 7u8, BigUint::from(5u8));
|
assert_eq!(BigUint::from(5u8) % 7u8, 5u8.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -76,8 +76,6 @@ fn test_scalar_div_rem() {
|
||||||
let (x, y, z, r) = (x.clone(), y.clone(), z.clone(), r.clone());
|
let (x, y, z, r) = (x.clone(), y.clone(), z.clone(), r.clone());
|
||||||
assert_unsigned_scalar_op!(x / y == z);
|
assert_unsigned_scalar_op!(x / y == z);
|
||||||
assert_unsigned_scalar_op!(x % y == r);
|
assert_unsigned_scalar_op!(x % y == r);
|
||||||
assert_unsigned_scalar_assign_op!(x /= y == z);
|
|
||||||
assert_unsigned_scalar_assign_op!(x %= y == r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for elm in MUL_TRIPLES.iter() {
|
for elm in MUL_TRIPLES.iter() {
|
||||||
|
@ -106,8 +104,6 @@ fn test_scalar_div_rem() {
|
||||||
check(&a, &b, &c, &d);
|
check(&a, &b, &c, &d);
|
||||||
assert_unsigned_scalar_op!(a / b == c);
|
assert_unsigned_scalar_op!(a / b == c);
|
||||||
assert_unsigned_scalar_op!(a % b == d);
|
assert_unsigned_scalar_op!(a % b == d);
|
||||||
assert_unsigned_scalar_assign_op!(a /= b == c);
|
|
||||||
assert_unsigned_scalar_assign_op!(a %= b == d);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
pub const N1: u32 = -1i32 as u32;
|
pub const N1: u32 = -1i32 as u32;
|
||||||
pub const N2: u32 = -2i32 as u32;
|
pub const N2: u32 = -2i32 as u32;
|
||||||
|
|
||||||
pub const SUM_TRIPLES: &[(&[u32], &[u32], &[u32])] = &[
|
pub const SUM_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32])] = &[
|
||||||
(&[], &[], &[]),
|
(&[], &[], &[]),
|
||||||
(&[], &[1], &[1]),
|
(&[], &[1], &[1]),
|
||||||
(&[1], &[1], &[2]),
|
(&[1], &[1], &[2]),
|
||||||
|
@ -17,7 +17,7 @@ pub const SUM_TRIPLES: &[(&[u32], &[u32], &[u32])] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const M: u32 = ::std::u32::MAX;
|
pub const M: u32 = ::std::u32::MAX;
|
||||||
pub const MUL_TRIPLES: &[(&[u32], &[u32], &[u32])] = &[
|
pub const MUL_TRIPLES: &'static [(&'static [u32], &'static [u32], &'static [u32])] = &[
|
||||||
(&[], &[], &[]),
|
(&[], &[], &[]),
|
||||||
(&[], &[1], &[]),
|
(&[], &[1], &[]),
|
||||||
(&[2], &[], &[]),
|
(&[2], &[], &[]),
|
||||||
|
@ -41,7 +41,12 @@ pub const MUL_TRIPLES: &[(&[u32], &[u32], &[u32])] = &[
|
||||||
(&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]),
|
(&[0, 0, 1], &[0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const DIV_REM_QUADRUPLES: &[(&[u32], &[u32], &[u32], &[u32])] = &[
|
pub const DIV_REM_QUADRUPLES: &'static [(
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
&'static [u32],
|
||||||
|
)] = &[
|
||||||
(&[1], &[2], &[], &[1]),
|
(&[1], &[2], &[], &[1]),
|
||||||
(&[3], &[2], &[1], &[1]),
|
(&[3], &[2], &[1], &[1]),
|
||||||
(&[1, 1], &[2], &[M / 2 + 1], &[1]),
|
(&[1, 1], &[2], &[M / 2 + 1], &[1]),
|
||||||
|
|
|
@ -35,6 +35,15 @@ macro_rules! assert_scalar_op {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(has_i128))]
|
||||||
|
macro_rules! assert_unsigned_scalar_op {
|
||||||
|
($left:ident $op:tt $right:ident == $expected:expr) => {
|
||||||
|
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize)
|
||||||
|
$left $op $right == $expected);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(has_i128)]
|
||||||
macro_rules! assert_unsigned_scalar_op {
|
macro_rules! assert_unsigned_scalar_op {
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
($left:ident $op:tt $right:ident == $expected:expr) => {
|
||||||
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128)
|
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128)
|
||||||
|
@ -42,6 +51,16 @@ macro_rules! assert_unsigned_scalar_op {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(has_i128))]
|
||||||
|
macro_rules! assert_signed_scalar_op {
|
||||||
|
($left:ident $op:tt $right:ident == $expected:expr) => {
|
||||||
|
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize,
|
||||||
|
to_i8, to_i16, to_i32, to_i64, to_isize)
|
||||||
|
$left $op $right == $expected);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(has_i128)]
|
||||||
macro_rules! assert_signed_scalar_op {
|
macro_rules! assert_signed_scalar_op {
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
($left:ident $op:tt $right:ident == $expected:expr) => {
|
||||||
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128,
|
assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128,
|
||||||
|
@ -49,30 +68,3 @@ macro_rules! assert_signed_scalar_op {
|
||||||
$left $op $right == $expected);
|
$left $op $right == $expected);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert that an op works for scalar right
|
|
||||||
macro_rules! assert_scalar_assign_op {
|
|
||||||
(($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
$(
|
|
||||||
if let Some(right) = $right.$to() {
|
|
||||||
let mut left = $left.clone();
|
|
||||||
assert_eq!({ left $op right; left}, $expected);
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_unsigned_scalar_assign_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_scalar_assign_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128)
|
|
||||||
$left $op $right == $expected);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_signed_scalar_assign_op {
|
|
||||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
|
||||||
assert_scalar_assign_op!((to_u8, to_u16, to_u32, to_u64, to_usize, to_u128,
|
|
||||||
to_i8, to_i16, to_i32, to_i64, to_isize, to_i128)
|
|
||||||
$left $op $right == $expected);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,56 +1,60 @@
|
||||||
static BIG_B: &str = "\
|
extern crate num_bigint;
|
||||||
efac3c0a_0de55551_fee0bfe4_67fa017a_1a898fa1_6ca57cb1\
|
extern crate num_integer;
|
||||||
ca9e3248_cacc09a9_b99d6abc_38418d0f_82ae4238_d9a68832\
|
extern crate num_traits;
|
||||||
aadec7c1_ac5fed48_7a56a71b_67ac59d5_afb28022_20d9592d\
|
|
||||||
247c4efc_abbd9b75_586088ee_1dc00dc4_232a8e15_6e8191dd\
|
|
||||||
675b6ae0_c80f5164_752940bc_284b7cee_885c1e10_e495345b\
|
|
||||||
8fbe9cfd_e5233fe1_19459d0b_d64be53c_27de5a02_a829976b\
|
|
||||||
33096862_82dad291_bd38b6a9_be396646_ddaf8039_a2573c39\
|
|
||||||
1b14e8bc_2cb53e48_298c047e_d9879e9c_5a521076_f0e27df3\
|
|
||||||
990e1659_d3d8205b_6443ebc0_9918ebee_6764f668_9f2b2be3\
|
|
||||||
b59cbc76_d76d0dfc_d737c3ec_0ccf9c00_ad0554bf_17e776ad\
|
|
||||||
b4edf9cc_6ce540be_76229093_5c53893b";
|
|
||||||
|
|
||||||
static BIG_E: &str = "\
|
static BIG_B: &'static str = "\
|
||||||
be0e6ea6_08746133_e0fbc1bf_82dba91e_e2b56231_a81888d2\
|
efac3c0a_0de55551_fee0bfe4_67fa017a_1a898fa1_6ca57cb1\
|
||||||
a833a1fc_f7ff002a_3c486a13_4f420bf3_a5435be9_1a5c8391\
|
ca9e3248_cacc09a9_b99d6abc_38418d0f_82ae4238_d9a68832\
|
||||||
774d6e6c_085d8357_b0c97d4d_2bb33f7c_34c68059_f78d2541\
|
aadec7c1_ac5fed48_7a56a71b_67ac59d5_afb28022_20d9592d\
|
||||||
eacc8832_426f1816_d3be001e_b69f9242_51c7708e_e10efe98\
|
247c4efc_abbd9b75_586088ee_1dc00dc4_232a8e15_6e8191dd\
|
||||||
449c9a4a_b55a0f23_9d797410_515da00d_3ea07970_4478a2ca\
|
675b6ae0_c80f5164_752940bc_284b7cee_885c1e10_e495345b\
|
||||||
c3d5043c_bd9be1b4_6dce479d_4302d344_84a939e6_0ab5ada7\
|
8fbe9cfd_e5233fe1_19459d0b_d64be53c_27de5a02_a829976b\
|
||||||
12ae34b2_30cc473c_9f8ee69d_2cac5970_29f5bf18_bc8203e4\
|
33096862_82dad291_bd38b6a9_be396646_ddaf8039_a2573c39\
|
||||||
f3e895a2_13c94f1e_24c73d77_e517e801_53661fdd_a2ce9e47\
|
1b14e8bc_2cb53e48_298c047e_d9879e9c_5a521076_f0e27df3\
|
||||||
a73dd7f8_2f2adb1e_3f136bf7_8ae5f3b8_08730de1_a4eff678\
|
990e1659_d3d8205b_6443ebc0_9918ebee_6764f668_9f2b2be3\
|
||||||
e77a06d0_19a522eb_cbefba2a_9caf7736_b157c5c6_2d192591\
|
b59cbc76_d76d0dfc_d737c3ec_0ccf9c00_ad0554bf_17e776ad\
|
||||||
17946850_2ddb1822_117b68a0_32f7db88";
|
b4edf9cc_6ce540be_76229093_5c53893b";
|
||||||
|
|
||||||
|
static BIG_E: &'static str = "\
|
||||||
|
be0e6ea6_08746133_e0fbc1bf_82dba91e_e2b56231_a81888d2\
|
||||||
|
a833a1fc_f7ff002a_3c486a13_4f420bf3_a5435be9_1a5c8391\
|
||||||
|
774d6e6c_085d8357_b0c97d4d_2bb33f7c_34c68059_f78d2541\
|
||||||
|
eacc8832_426f1816_d3be001e_b69f9242_51c7708e_e10efe98\
|
||||||
|
449c9a4a_b55a0f23_9d797410_515da00d_3ea07970_4478a2ca\
|
||||||
|
c3d5043c_bd9be1b4_6dce479d_4302d344_84a939e6_0ab5ada7\
|
||||||
|
12ae34b2_30cc473c_9f8ee69d_2cac5970_29f5bf18_bc8203e4\
|
||||||
|
f3e895a2_13c94f1e_24c73d77_e517e801_53661fdd_a2ce9e47\
|
||||||
|
a73dd7f8_2f2adb1e_3f136bf7_8ae5f3b8_08730de1_a4eff678\
|
||||||
|
e77a06d0_19a522eb_cbefba2a_9caf7736_b157c5c6_2d192591\
|
||||||
|
17946850_2ddb1822_117b68a0_32f7db88";
|
||||||
|
|
||||||
// This modulus is the prime from the 2048-bit MODP DH group:
|
// This modulus is the prime from the 2048-bit MODP DH group:
|
||||||
// https://tools.ietf.org/html/rfc3526#section-3
|
// https://tools.ietf.org/html/rfc3526#section-3
|
||||||
static BIG_M: &str = "\
|
static BIG_M: &'static str = "\
|
||||||
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
||||||
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
||||||
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
||||||
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
||||||
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
||||||
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
||||||
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
||||||
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
||||||
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
||||||
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
||||||
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
||||||
|
|
||||||
static BIG_R: &str = "\
|
static BIG_R: &'static str = "\
|
||||||
a1468311_6e56edc9_7a98228b_5e924776_0dd7836e_caabac13\
|
a1468311_6e56edc9_7a98228b_5e924776_0dd7836e_caabac13\
|
||||||
eda5373b_4752aa65_a1454850_40dc770e_30aa8675_6be7d3a8\
|
eda5373b_4752aa65_a1454850_40dc770e_30aa8675_6be7d3a8\
|
||||||
9d3085e4_da5155cf_b451ef62_54d0da61_cf2b2c87_f495e096\
|
9d3085e4_da5155cf_b451ef62_54d0da61_cf2b2c87_f495e096\
|
||||||
055309f7_77802bbb_37271ba8_1313f1b5_075c75d1_024b6c77\
|
055309f7_77802bbb_37271ba8_1313f1b5_075c75d1_024b6c77\
|
||||||
fdb56f17_b05bce61_e527ebfd_2ee86860_e9907066_edd526e7\
|
fdb56f17_b05bce61_e527ebfd_2ee86860_e9907066_edd526e7\
|
||||||
93d289bf_6726b293_41b0de24_eff82424_8dfd374b_4ec59542\
|
93d289bf_6726b293_41b0de24_eff82424_8dfd374b_4ec59542\
|
||||||
35ced2b2_6b195c90_10042ffb_8f58ce21_bc10ec42_64fda779\
|
35ced2b2_6b195c90_10042ffb_8f58ce21_bc10ec42_64fda779\
|
||||||
d352d234_3d4eaea6_a86111ad_a37e9555_43ca78ce_2885bed7\
|
d352d234_3d4eaea6_a86111ad_a37e9555_43ca78ce_2885bed7\
|
||||||
5a30d182_f1cf6834_dc5b6e27_1a41ac34_a2e91e11_33363ff0\
|
5a30d182_f1cf6834_dc5b6e27_1a41ac34_a2e91e11_33363ff0\
|
||||||
f88a7b04_900227c9_f6e6d06b_7856b4bb_4e354d61_060db6c8\
|
f88a7b04_900227c9_f6e6d06b_7856b4bb_4e354d61_060db6c8\
|
||||||
109c4735_6e7db425_7b5d74c7_0b709508";
|
109c4735_6e7db425_7b5d74c7_0b709508";
|
||||||
|
|
||||||
mod biguint {
|
mod biguint {
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
|
@ -72,24 +76,11 @@ mod biguint {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_modpow_single() {
|
fn test_modpow() {
|
||||||
check_modpow::<u32>(1, 0, 11, 1);
|
check_modpow::<u32>(1, 0, 11, 1);
|
||||||
check_modpow::<u32>(0, 15, 11, 0);
|
check_modpow::<u32>(0, 15, 11, 0);
|
||||||
check_modpow::<u32>(3, 7, 11, 9);
|
check_modpow::<u32>(3, 7, 11, 9);
|
||||||
check_modpow::<u32>(5, 117, 19, 1);
|
check_modpow::<u32>(5, 117, 19, 1);
|
||||||
check_modpow::<u32>(20, 1, 2, 0);
|
|
||||||
check_modpow::<u32>(20, 1, 3, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_modpow_small() {
|
|
||||||
for b in 0u64..11 {
|
|
||||||
for e in 0u64..11 {
|
|
||||||
for m in 1..11 {
|
|
||||||
check_modpow::<u64>(b, e, m, b.pow(e as u32) % m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -111,13 +102,13 @@ mod biguint {
|
||||||
mod bigint {
|
mod bigint {
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
use num_traits::{Num, One, Signed};
|
use num_traits::{Num, One, Signed, Zero};
|
||||||
|
|
||||||
fn check_modpow<T: Into<BigInt>>(b: T, e: T, m: T, r: T) {
|
fn check_modpow<T: Into<BigInt>>(b: T, e: T, m: T, r: T) {
|
||||||
fn check(b: &BigInt, e: &BigInt, m: &BigInt, r: &BigInt) {
|
fn check(b: &BigInt, e: &BigInt, m: &BigInt, r: &BigInt) {
|
||||||
assert_eq!(&b.modpow(e, m), r, "{} ** {} (mod {}) != {}", b, e, m, r);
|
assert_eq!(&b.modpow(e, m), r);
|
||||||
|
|
||||||
let even_m = m << 1u8;
|
let even_m = m << 1;
|
||||||
let even_modpow = b.modpow(e, m);
|
let even_modpow = b.modpow(e, m);
|
||||||
assert!(even_modpow.abs() < even_m.abs());
|
assert!(even_modpow.abs() < even_m.abs());
|
||||||
assert_eq!(&even_modpow.mod_floor(&m), r);
|
assert_eq!(&even_modpow.mod_floor(&m), r);
|
||||||
|
@ -131,18 +122,12 @@ mod bigint {
|
||||||
let m: BigInt = m.into();
|
let m: BigInt = m.into();
|
||||||
let r: BigInt = r.into();
|
let r: BigInt = r.into();
|
||||||
|
|
||||||
let neg_b_r = if e.is_odd() {
|
let neg_r = if r.is_zero() { BigInt::zero() } else { &m - &r };
|
||||||
(-&r).mod_floor(&m)
|
|
||||||
} else {
|
|
||||||
r.clone()
|
|
||||||
};
|
|
||||||
let neg_m_r = r.mod_floor(&-&m);
|
|
||||||
let neg_bm_r = neg_b_r.mod_floor(&-&m);
|
|
||||||
|
|
||||||
check(&b, &e, &m, &r);
|
check(&b, &e, &m, &r);
|
||||||
check(&-&b, &e, &m, &neg_b_r);
|
check(&-&b, &e, &m, &neg_r);
|
||||||
check(&b, &e, &-&m, &neg_m_r);
|
check(&b, &e, &-&m, &-neg_r);
|
||||||
check(&-b, &e, &-&m, &neg_bm_r);
|
check(&-b, &e, &-m, &-r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -151,22 +136,6 @@ mod bigint {
|
||||||
check_modpow(0, 15, 11, 0);
|
check_modpow(0, 15, 11, 0);
|
||||||
check_modpow(3, 7, 11, 9);
|
check_modpow(3, 7, 11, 9);
|
||||||
check_modpow(5, 117, 19, 1);
|
check_modpow(5, 117, 19, 1);
|
||||||
check_modpow(-20, 1, 2, 0);
|
|
||||||
check_modpow(-20, 1, 3, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_modpow_small() {
|
|
||||||
for b in -10i64..11 {
|
|
||||||
for e in 0i64..11 {
|
|
||||||
for m in -10..11 {
|
|
||||||
if m == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_modpow(b, e, m, b.pow(e as u32).mod_floor(&m));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_integer;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
mod biguint {
|
mod biguint {
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_traits::{One, Zero};
|
use num_traits::{One, Pow, Zero};
|
||||||
use std::{i32, u32};
|
use std::{i32, u32};
|
||||||
|
|
||||||
fn check<T: Into<BigUint>>(x: T, n: u32) {
|
fn check<T: Into<BigUint>>(x: T, n: u32) {
|
||||||
|
@ -81,7 +88,7 @@ mod biguint {
|
||||||
let x = BigUint::one() << LOG2;
|
let x = BigUint::one() << LOG2;
|
||||||
|
|
||||||
// the perfect divisors are just powers of two
|
// the perfect divisors are just powers of two
|
||||||
for exp in 1..=EXP {
|
for exp in 1..EXP + 1 {
|
||||||
let n = 2u32.pow(exp);
|
let n = 2u32.pow(exp);
|
||||||
let expected = BigUint::one() << (LOG2 / n as usize);
|
let expected = BigUint::one() << (LOG2 / n as usize);
|
||||||
assert_eq!(x.nth_root(n), expected);
|
assert_eq!(x.nth_root(n), expected);
|
||||||
|
@ -94,6 +101,25 @@ mod biguint {
|
||||||
assert!(x.nth_root(u32::MAX).is_one());
|
assert!(x.nth_root(u32::MAX).is_one());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rand")]
|
||||||
|
#[test]
|
||||||
|
fn test_roots_rand() {
|
||||||
|
use num_bigint::RandBigInt;
|
||||||
|
use rand::distributions::Uniform;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
let bit_range = Uniform::new(0, 2048);
|
||||||
|
let sample_bits: Vec<_> = rng.sample_iter(&bit_range).take(100).collect();
|
||||||
|
for bits in sample_bits {
|
||||||
|
let x = rng.gen_biguint(bits);
|
||||||
|
for n in 2..11 {
|
||||||
|
check(x.clone(), n);
|
||||||
|
}
|
||||||
|
check(x.clone(), 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_roots_rand1() {
|
fn test_roots_rand1() {
|
||||||
// A random input that found regressions
|
// A random input that found regressions
|
||||||
|
@ -108,13 +134,13 @@ mod biguint {
|
||||||
check(x.clone(), 2);
|
check(x.clone(), 2);
|
||||||
check(x.clone(), 3);
|
check(x.clone(), 3);
|
||||||
check(x.clone(), 10);
|
check(x.clone(), 10);
|
||||||
check(x, 100);
|
check(x.clone(), 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod bigint {
|
mod bigint {
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::Signed;
|
use num_traits::{Pow, Signed};
|
||||||
|
|
||||||
fn check(x: i64, n: u32) {
|
fn check(x: i64, n: u32) {
|
||||||
let big_x = BigInt::from(x);
|
let big_x = BigInt::from(x);
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"files":{"Cargo.toml":"ae77ec097a983a6d365193723032ccc161f15ef5a37ffc14c1b3fd26caacbf1d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"60255cfba4fe9fc25ca1e1f51702ce8e52e7a8b2d747e3e2055eacb04e2bae70","RELEASES.md":"834ab68be8ce6e4a46fb2f591bc93ff01e6481955e6b027adfb60f393c24a6b6","src/cast.rs":"8206bcfb99b712340383332fb760dba9cee4be8c994bd9a38d0b8c6e6bc5f7b1","src/crand.rs":"81dd604ea3bc74d7ed5e132cddecb3d6a1aaa5f6cdadac7311b62beac5e7ef89","src/lib.rs":"ef7fff45cc8ef75df68836f0b5d8dd3bd9f3a686c20e7b8761295c3b6e39699a","src/pow.rs":"974fd585da8c2b7ac3f68e93a3881c56a3f0f3e506009fb3d862c6000064abb7"},"package":"b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5"}
|
|
|
@ -1,47 +0,0 @@
|
||||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
|
||||||
#
|
|
||||||
# When uploading crates to the registry Cargo will automatically
|
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
|
||||||
# to registry (e.g., crates.io) dependencies
|
|
||||||
#
|
|
||||||
# If you believe there's an error in this file please file an
|
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
|
||||||
# editing this file be aware that the upstream Cargo.toml
|
|
||||||
# will likely look very different (and much more reasonable)
|
|
||||||
|
|
||||||
[package]
|
|
||||||
edition = "2018"
|
|
||||||
name = "num-complex"
|
|
||||||
version = "0.3.0"
|
|
||||||
authors = ["The Rust Project Developers"]
|
|
||||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
|
||||||
description = "Complex numbers implementation for Rust"
|
|
||||||
homepage = "https://github.com/rust-num/num-complex"
|
|
||||||
documentation = "https://docs.rs/num-complex"
|
|
||||||
readme = "README.md"
|
|
||||||
keywords = ["mathematics", "numerics"]
|
|
||||||
categories = ["algorithms", "data-structures", "science", "no-std"]
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
repository = "https://github.com/rust-num/num-complex"
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
features = ["std", "serde", "rand"]
|
|
||||||
[dependencies.num-traits]
|
|
||||||
version = "0.2.11"
|
|
||||||
features = ["i128"]
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.rand]
|
|
||||||
version = "0.7"
|
|
||||||
optional = true
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dependencies.serde]
|
|
||||||
version = "1.0"
|
|
||||||
optional = true
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["std"]
|
|
||||||
libm = ["num-traits/libm"]
|
|
||||||
std = ["num-traits/std"]
|
|
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,25 +0,0 @@
|
||||||
Copyright (c) 2014 The Rust Project Developers
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
|
||||||
person obtaining a copy of this software and associated
|
|
||||||
documentation files (the "Software"), to deal in the
|
|
||||||
Software without restriction, including without
|
|
||||||
limitation the rights to use, copy, modify, merge,
|
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software
|
|
||||||
is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
|
||||||
shall be included in all copies or substantial portions
|
|
||||||
of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,40 +0,0 @@
|
||||||
# num-complex
|
|
||||||
|
|
||||||
[![crate](https://img.shields.io/crates/v/num-complex.svg)](https://crates.io/crates/num-complex)
|
|
||||||
[![documentation](https://docs.rs/num-complex/badge.svg)](https://docs.rs/num-complex)
|
|
||||||
[![minimum rustc 1.31](https://img.shields.io/badge/rustc-1.31+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
|
|
||||||
[![build status](https://github.com/rust-num/num-complex/workflows/master/badge.svg)](https://github.com/rust-num/num-complex/actions)
|
|
||||||
|
|
||||||
`Complex` numbers for Rust.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add this to your `Cargo.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
num-complex = "0.3"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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-complex]
|
|
||||||
version = "0.3"
|
|
||||||
default-features = false
|
|
||||||
```
|
|
||||||
|
|
||||||
Features based on `Float` types are only available when `std` or `libm` is
|
|
||||||
enabled. Where possible, `FloatCore` is used instead. Formatting complex
|
|
||||||
numbers only supports format width when `std` is enabled.
|
|
||||||
|
|
||||||
## Releases
|
|
||||||
|
|
||||||
Release notes are available in [RELEASES.md](RELEASES.md).
|
|
||||||
|
|
||||||
## Compatibility
|
|
||||||
|
|
||||||
The `num-complex` crate is tested for rustc 1.31 and greater.
|
|
|
@ -1,125 +0,0 @@
|
||||||
# Release 0.3.0 (2020-06-13)
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- [The new "libm" feature passes through to `num-traits`][73], enabling `Float`
|
|
||||||
features on no-`std` builds.
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
- `num-complex` now requires Rust 1.31 or greater.
|
|
||||||
- The "i128" opt-in feature was removed, now always available.
|
|
||||||
- [Updated public dependences][65]:
|
|
||||||
- `rand` support has been updated to 0.7, requiring Rust 1.32.
|
|
||||||
- [Methods for `T: Float` now take values instead of references][82], most
|
|
||||||
notably affecting the constructor `from_polar`.
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @SOF3, @vks
|
|
||||||
|
|
||||||
[65]: https://github.com/rust-num/num-complex/pull/65
|
|
||||||
[73]: https://github.com/rust-num/num-complex/pull/73
|
|
||||||
[82]: https://github.com/rust-num/num-complex/pull/82
|
|
||||||
|
|
||||||
# Release 0.2.4 (2020-01-09)
|
|
||||||
|
|
||||||
- [`Complex::new` is now a `const fn` for Rust 1.31 and later][63].
|
|
||||||
- [Updated the `autocfg` build dependency to 1.0][68].
|
|
||||||
|
|
||||||
**Contributors**: @burrbull, @cuviper, @dingelish
|
|
||||||
|
|
||||||
[63]: https://github.com/rust-num/num-complex/pull/63
|
|
||||||
[68]: https://github.com/rust-num/num-complex/pull/68
|
|
||||||
|
|
||||||
# Release 0.2.3 (2019-06-11)
|
|
||||||
|
|
||||||
- [`Complex::sqrt()` is now more accurate for negative reals][60].
|
|
||||||
- [`Complex::cbrt()` computes the principal cube root][61].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper
|
|
||||||
|
|
||||||
[60]: https://github.com/rust-num/num-complex/pull/60
|
|
||||||
[61]: https://github.com/rust-num/num-complex/pull/61
|
|
||||||
|
|
||||||
# Release 0.2.2 (2019-06-10)
|
|
||||||
|
|
||||||
- [`Complex::l1_norm()` computes the Manhattan distance from the origin][43].
|
|
||||||
- [`Complex::fdiv()` and `finv()` use floating-point for inversion][41], which
|
|
||||||
may avoid overflows for some inputs, at the cost of trigonometric rounding.
|
|
||||||
- [`Complex` now implements `num_traits::MulAdd` and `MulAddAssign`][44].
|
|
||||||
- [`Complex` now implements `Zero::set_zero` and `One::set_one`][57].
|
|
||||||
- [`Complex` now implements `num_traits::Pow` and adds `powi` and `powu`][56].
|
|
||||||
|
|
||||||
**Contributors**: @adamnemecek, @cuviper, @ignatenkobrain, @Schultzer
|
|
||||||
|
|
||||||
[41]: https://github.com/rust-num/num-complex/pull/41
|
|
||||||
[43]: https://github.com/rust-num/num-complex/pull/43
|
|
||||||
[44]: https://github.com/rust-num/num-complex/pull/44
|
|
||||||
[56]: https://github.com/rust-num/num-complex/pull/56
|
|
||||||
[57]: https://github.com/rust-num/num-complex/pull/57
|
|
||||||
|
|
||||||
# Release 0.2.1 (2018-10-08)
|
|
||||||
|
|
||||||
- [`Complex` now implements `ToPrimitive`, `FromPrimitive`, `AsPrimitive`, and `NumCast`][33].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @termoshtt
|
|
||||||
|
|
||||||
[33]: https://github.com/rust-num/num-complex/pull/33
|
|
||||||
|
|
||||||
# Release 0.2.0 (2018-05-24)
|
|
||||||
|
|
||||||
### Enhancements
|
|
||||||
|
|
||||||
- [`Complex` now implements `num_traits::Inv` and `One::is_one`][17].
|
|
||||||
- [`Complex` now implements `Sum` and `Product`][11].
|
|
||||||
- [`Complex` now supports `i128` and `u128` components][27] with Rust 1.26+.
|
|
||||||
- [`Complex` now optionally supports `rand` 0.5][28], implementing the
|
|
||||||
`Standard` distribution and [a generic `ComplexDistribution`][30].
|
|
||||||
- [`Rem` with a scalar divisor now avoids `norm_sqr` overflow][25].
|
|
||||||
|
|
||||||
### Breaking Changes
|
|
||||||
|
|
||||||
- [`num-complex` now requires rustc 1.15 or greater][16].
|
|
||||||
- [There is now a `std` feature][22], enabled by default, along with the
|
|
||||||
implication that building *without* this feature makes this a `#![no_std]`
|
|
||||||
crate. A few methods now require `FloatCore`, and the remaining methods
|
|
||||||
based on `Float` are only supported with `std`.
|
|
||||||
- [The `serde` dependency has been updated to 1.0][7], and `rustc-serialize`
|
|
||||||
is no longer supported by `num-complex`.
|
|
||||||
|
|
||||||
**Contributors**: @clarcharr, @cuviper, @shingtaklam1324, @termoshtt
|
|
||||||
|
|
||||||
[7]: https://github.com/rust-num/num-complex/pull/7
|
|
||||||
[11]: https://github.com/rust-num/num-complex/pull/11
|
|
||||||
[16]: https://github.com/rust-num/num-complex/pull/16
|
|
||||||
[17]: https://github.com/rust-num/num-complex/pull/17
|
|
||||||
[22]: https://github.com/rust-num/num-complex/pull/22
|
|
||||||
[25]: https://github.com/rust-num/num-complex/pull/25
|
|
||||||
[27]: https://github.com/rust-num/num-complex/pull/27
|
|
||||||
[28]: https://github.com/rust-num/num-complex/pull/28
|
|
||||||
[30]: https://github.com/rust-num/num-complex/pull/30
|
|
||||||
|
|
||||||
|
|
||||||
# Release 0.1.43 (2018-03-08)
|
|
||||||
|
|
||||||
- [Fix a usage typo in README.md][20].
|
|
||||||
|
|
||||||
**Contributors**: @shingtaklam1324
|
|
||||||
|
|
||||||
[20]: https://github.com/rust-num/num-complex/pull/20
|
|
||||||
|
|
||||||
|
|
||||||
# Release 0.1.42 (2018-02-07)
|
|
||||||
|
|
||||||
- [num-complex now has its own source repository][num-356] at [rust-num/num-complex][home].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper
|
|
||||||
|
|
||||||
[home]: https://github.com/rust-num/num-complex
|
|
||||||
[num-356]: https://github.com/rust-num/num/pull/356
|
|
||||||
|
|
||||||
|
|
||||||
# Prior releases
|
|
||||||
|
|
||||||
No prior release notes were kept. Thanks all the same to the many
|
|
||||||
contributors that have made this crate what it is!
|
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
use super::Complex;
|
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num, NumCast, ToPrimitive};
|
|
||||||
|
|
||||||
macro_rules! impl_to_primitive {
|
|
||||||
($ty:ty, $to:ident) => {
|
|
||||||
#[inline]
|
|
||||||
fn $to(&self) -> Option<$ty> {
|
|
||||||
if self.im.is_zero() {
|
|
||||||
self.re.$to()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // impl_to_primitive
|
|
||||||
|
|
||||||
// Returns None if Complex part is non-zero
|
|
||||||
impl<T: ToPrimitive + Num> ToPrimitive for Complex<T> {
|
|
||||||
impl_to_primitive!(usize, to_usize);
|
|
||||||
impl_to_primitive!(isize, to_isize);
|
|
||||||
impl_to_primitive!(u8, to_u8);
|
|
||||||
impl_to_primitive!(u16, to_u16);
|
|
||||||
impl_to_primitive!(u32, to_u32);
|
|
||||||
impl_to_primitive!(u64, to_u64);
|
|
||||||
impl_to_primitive!(i8, to_i8);
|
|
||||||
impl_to_primitive!(i16, to_i16);
|
|
||||||
impl_to_primitive!(i32, to_i32);
|
|
||||||
impl_to_primitive!(i64, to_i64);
|
|
||||||
impl_to_primitive!(u128, to_u128);
|
|
||||||
impl_to_primitive!(i128, to_i128);
|
|
||||||
impl_to_primitive!(f32, to_f32);
|
|
||||||
impl_to_primitive!(f64, to_f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_from_primitive {
|
|
||||||
($ty:ty, $from_xx:ident) => {
|
|
||||||
#[inline]
|
|
||||||
fn $from_xx(n: $ty) -> Option<Self> {
|
|
||||||
Some(Complex {
|
|
||||||
re: T::$from_xx(n)?,
|
|
||||||
im: T::zero(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // impl_from_primitive
|
|
||||||
|
|
||||||
impl<T: FromPrimitive + Num> FromPrimitive for Complex<T> {
|
|
||||||
impl_from_primitive!(usize, from_usize);
|
|
||||||
impl_from_primitive!(isize, from_isize);
|
|
||||||
impl_from_primitive!(u8, from_u8);
|
|
||||||
impl_from_primitive!(u16, from_u16);
|
|
||||||
impl_from_primitive!(u32, from_u32);
|
|
||||||
impl_from_primitive!(u64, from_u64);
|
|
||||||
impl_from_primitive!(i8, from_i8);
|
|
||||||
impl_from_primitive!(i16, from_i16);
|
|
||||||
impl_from_primitive!(i32, from_i32);
|
|
||||||
impl_from_primitive!(i64, from_i64);
|
|
||||||
impl_from_primitive!(u128, from_u128);
|
|
||||||
impl_from_primitive!(i128, from_i128);
|
|
||||||
impl_from_primitive!(f32, from_f32);
|
|
||||||
impl_from_primitive!(f64, from_f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: NumCast + Num> NumCast for Complex<T> {
|
|
||||||
fn from<U: ToPrimitive>(n: U) -> Option<Self> {
|
|
||||||
Some(Complex {
|
|
||||||
re: T::from(n)?,
|
|
||||||
im: T::zero(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> AsPrimitive<U> for Complex<T>
|
|
||||||
where
|
|
||||||
T: AsPrimitive<U>,
|
|
||||||
U: 'static + Copy,
|
|
||||||
{
|
|
||||||
fn as_(self) -> U {
|
|
||||||
self.re.as_()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_to_primitive() {
|
|
||||||
let a: Complex<u32> = Complex { re: 3, im: 0 };
|
|
||||||
assert_eq!(a.to_i32(), Some(3_i32));
|
|
||||||
let b: Complex<u32> = Complex { re: 3, im: 1 };
|
|
||||||
assert_eq!(b.to_i32(), None);
|
|
||||||
let x: Complex<f32> = Complex { re: 1.0, im: 0.1 };
|
|
||||||
assert_eq!(x.to_f32(), None);
|
|
||||||
let y: Complex<f32> = Complex { re: 1.0, im: 0.0 };
|
|
||||||
assert_eq!(y.to_f32(), Some(1.0));
|
|
||||||
let z: Complex<f32> = Complex { re: 1.0, im: 0.0 };
|
|
||||||
assert_eq!(z.to_i32(), Some(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_from_primitive() {
|
|
||||||
let a: Complex<f32> = FromPrimitive::from_i32(2).unwrap();
|
|
||||||
assert_eq!(a, Complex { re: 2.0, im: 0.0 });
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_num_cast() {
|
|
||||||
let a: Complex<f32> = NumCast::from(2_i32).unwrap();
|
|
||||||
assert_eq!(a, Complex { re: 2.0, im: 0.0 });
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_as_primitive() {
|
|
||||||
let a: Complex<f32> = Complex { re: 2.0, im: 0.2 };
|
|
||||||
let a_: i32 = a.as_();
|
|
||||||
assert_eq!(a_, 2_i32);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
//! Rand implementations for complex numbers
|
|
||||||
|
|
||||||
use crate::Complex;
|
|
||||||
use num_traits::Num;
|
|
||||||
use rand::distributions::Standard;
|
|
||||||
use rand::prelude::*;
|
|
||||||
|
|
||||||
impl<T> Distribution<Complex<T>> for Standard
|
|
||||||
where
|
|
||||||
T: Num + Clone,
|
|
||||||
Standard: Distribution<T>,
|
|
||||||
{
|
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Complex<T> {
|
|
||||||
Complex::new(self.sample(rng), self.sample(rng))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A generic random value distribution for complex numbers.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct ComplexDistribution<Re, Im = Re> {
|
|
||||||
re: Re,
|
|
||||||
im: Im,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Re, Im> ComplexDistribution<Re, Im> {
|
|
||||||
/// Creates a complex distribution from independent
|
|
||||||
/// distributions of the real and imaginary parts.
|
|
||||||
pub fn new(re: Re, im: Im) -> Self {
|
|
||||||
ComplexDistribution { re, im }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, Re, Im> Distribution<Complex<T>> for ComplexDistribution<Re, Im>
|
|
||||||
where
|
|
||||||
T: Num + Clone,
|
|
||||||
Re: Distribution<T>,
|
|
||||||
Im: Distribution<T>,
|
|
||||||
{
|
|
||||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Complex<T> {
|
|
||||||
Complex::new(self.re.sample(rng), self.im.sample(rng))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn test_rng() -> StdRng {
|
|
||||||
StdRng::from_seed([42; 32])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn standard_f64() {
|
|
||||||
let mut rng = test_rng();
|
|
||||||
for _ in 0..100 {
|
|
||||||
let c: Complex<f64> = rng.gen();
|
|
||||||
assert!(c.re >= 0.0 && c.re < 1.0);
|
|
||||||
assert!(c.im >= 0.0 && c.im < 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generic_standard_f64() {
|
|
||||||
let mut rng = test_rng();
|
|
||||||
let dist = ComplexDistribution::new(Standard, Standard);
|
|
||||||
for _ in 0..100 {
|
|
||||||
let c: Complex<f64> = rng.sample(&dist);
|
|
||||||
assert!(c.re >= 0.0 && c.re < 1.0);
|
|
||||||
assert!(c.im >= 0.0 && c.im < 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generic_uniform_f64() {
|
|
||||||
use rand::distributions::Uniform;
|
|
||||||
|
|
||||||
let mut rng = test_rng();
|
|
||||||
let re = Uniform::new(-100.0, 0.0);
|
|
||||||
let im = Uniform::new(0.0, 100.0);
|
|
||||||
let dist = ComplexDistribution::new(re, im);
|
|
||||||
for _ in 0..100 {
|
|
||||||
// no type annotation required, since `Uniform` only produces one type.
|
|
||||||
let c = rng.sample(&dist);
|
|
||||||
assert!(c.re >= -100.0 && c.re < 0.0);
|
|
||||||
assert!(c.im >= 0.0 && c.im < 100.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generic_mixed_f64() {
|
|
||||||
use rand::distributions::Uniform;
|
|
||||||
|
|
||||||
let mut rng = test_rng();
|
|
||||||
let re = Uniform::new(-100.0, 0.0);
|
|
||||||
let dist = ComplexDistribution::new(re, Standard);
|
|
||||||
for _ in 0..100 {
|
|
||||||
// no type annotation required, since `Uniform` only produces one type.
|
|
||||||
let c = rng.sample(&dist);
|
|
||||||
assert!(c.re >= -100.0 && c.re < 0.0);
|
|
||||||
assert!(c.im >= 0.0 && c.im < 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generic_uniform_i32() {
|
|
||||||
use rand::distributions::Uniform;
|
|
||||||
|
|
||||||
let mut rng = test_rng();
|
|
||||||
let re = Uniform::new(-100, 0);
|
|
||||||
let im = Uniform::new(0, 100);
|
|
||||||
let dist = ComplexDistribution::new(re, im);
|
|
||||||
for _ in 0..100 {
|
|
||||||
// no type annotation required, since `Uniform` only produces one type.
|
|
||||||
let c = rng.sample(&dist);
|
|
||||||
assert!(c.re >= -100 && c.re < 0);
|
|
||||||
assert!(c.im >= 0 && c.im < 100);
|
|
||||||
}
|
|
||||||
}
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,186 +0,0 @@
|
||||||
use super::Complex;
|
|
||||||
|
|
||||||
use core::ops::Neg;
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
use num_traits::Float;
|
|
||||||
use num_traits::{Num, One, Pow};
|
|
||||||
|
|
||||||
macro_rules! pow_impl {
|
|
||||||
($U:ty, $S:ty) => {
|
|
||||||
impl<'a, T: Clone + Num> Pow<$U> for &'a Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, mut exp: $U) -> Self::Output {
|
|
||||||
if exp == 0 {
|
|
||||||
return Complex::one();
|
|
||||||
}
|
|
||||||
let mut base = self.clone();
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, T: Clone + Num> Pow<&'b $U> for &'a Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: &$U) -> Self::Output {
|
|
||||||
self.pow(*exp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Clone + Num + Neg<Output = T>> Pow<$S> for &'a Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: $S) -> Self::Output {
|
|
||||||
if exp < 0 {
|
|
||||||
Pow::pow(&self.inv(), exp.wrapping_neg() as $U)
|
|
||||||
} else {
|
|
||||||
Pow::pow(self, exp as $U)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, T: Clone + Num + Neg<Output = T>> Pow<&'b $S> for &'a Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: &$S) -> Self::Output {
|
|
||||||
self.pow(*exp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_impl!(u8, i8);
|
|
||||||
pow_impl!(u16, i16);
|
|
||||||
pow_impl!(u32, i32);
|
|
||||||
pow_impl!(u64, i64);
|
|
||||||
pow_impl!(usize, isize);
|
|
||||||
pow_impl!(u128, i128);
|
|
||||||
|
|
||||||
// Note: we can't add `impl<T: Float> Pow<T> for Complex<T>` because new blanket impls are a
|
|
||||||
// breaking change. Someone could already have their own `F` and `impl Pow<F> for Complex<F>`
|
|
||||||
// which would conflict. We can't even do this in a new semantic version, because we have to
|
|
||||||
// gate it on the "std" feature, and features can't add breaking changes either.
|
|
||||||
|
|
||||||
macro_rules! powf_impl {
|
|
||||||
($F:ty) => {
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<'a, T: Float> Pow<$F> for &'a Complex<T>
|
|
||||||
where
|
|
||||||
$F: Into<T>,
|
|
||||||
{
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: $F) -> Self::Output {
|
|
||||||
self.powf(exp.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<'a, 'b, T: Float> Pow<&'b $F> for &'a Complex<T>
|
|
||||||
where
|
|
||||||
$F: Into<T>,
|
|
||||||
{
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, &exp: &$F) -> Self::Output {
|
|
||||||
self.powf(exp.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<T: Float> Pow<$F> for Complex<T>
|
|
||||||
where
|
|
||||||
$F: Into<T>,
|
|
||||||
{
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: $F) -> Self::Output {
|
|
||||||
self.powf(exp.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<'b, T: Float> Pow<&'b $F> for Complex<T>
|
|
||||||
where
|
|
||||||
$F: Into<T>,
|
|
||||||
{
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, &exp: &$F) -> Self::Output {
|
|
||||||
self.powf(exp.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
powf_impl!(f32);
|
|
||||||
powf_impl!(f64);
|
|
||||||
|
|
||||||
// These blanket impls are OK, because both the target type and the trait parameter would be
|
|
||||||
// foreign to anyone else trying to implement something that would overlap, raising E0117.
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<'a, T: Float> Pow<Complex<T>> for &'a Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: Complex<T>) -> Self::Output {
|
|
||||||
self.powc(exp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<'a, 'b, T: Float> Pow<&'b Complex<T>> for &'a Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
|
|
||||||
self.powc(exp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<T: Float> Pow<Complex<T>> for Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, exp: Complex<T>) -> Self::Output {
|
|
||||||
self.powc(exp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "libm"))]
|
|
||||||
impl<'b, T: Float> Pow<&'b Complex<T>> for Complex<T> {
|
|
||||||
type Output = Complex<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pow(self, &exp: &'b Complex<T>) -> Self::Output {
|
|
||||||
self.powc(exp)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"df725a7c5780368b03dbe14ac170989ddd987e2e3c8a69bfb47d34025e0e06ec","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"c49fdda3780903fa8c17bb5811ea3029e271e9e79a8f6c59aa3b2468eb9b203f","RELEASES.md":"756843fa25e29f642367b6b3fc161ce34a72d01ae0fb67d5531a280245d287c8","benches/average.rs":"2a30b4ccd8ece8663d17583ae2e3623e654b5f401babef90f1634722824e6c2b","benches/gcd.rs":"9b5c0ae8ccd6c7fc8f8384fb351d10cfdd0be5fbea9365f9ea925d8915b015bf","benches/roots.rs":"79b4ab2d8fe7bbf43fe65314d2e1bc206165bc4cb34b3ceaa899f9ea7af31c09","build.rs":"b4b2d0df90ca7570a339ca4d84a72e4ef00d9dced8927350424e666790c752d7","src/average.rs":"a66cf6a49f893e60697c17b2540258e69daa15ab97d8d444c6f2e8cac2f01ae9","src/lib.rs":"bf0ce9a09f92f606ca038288cde7a29670ccca480d42ec97e88f3c56b117e33c","src/roots.rs":"2a9b908bd3666b5cffc58c1b37d329e46ed02f71ad6d5deea1e8440c10660e1a","tests/average.rs":"5f26a31be042626e9af66f7b751798621561fa090da48b1ec5ab63e388288a91","tests/roots.rs":"a0caa4142899ec8cb806a7a0d3410c39d50de97cceadc4c2ceca707be91b1ddd"},"package":"8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"}
|
{"files":{"Cargo.toml":"f491aec76f2252ca15a333dd3cfd18cfd91ebf841c7d607857dfa75c7080cb9a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"7ad5fb625f7ef61595a2180f3b26715457552faa8bb08526c70b416da29b2533","RELEASES.md":"ebe114c148e4fc43b63c2523e13e9d903f07db139ab70f48320f9cb8c17ac9d8","benches/roots.rs":"df3554c0025d78235b5dca975b641f3bb10cae8d5ad3a79eb6cbd1a21475f133","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"2aa9e89e4af81ed9da86bdcf7cdabe512287c877248783b69eed1eccf09ad6bb","ci/test_full.sh":"fd4928a73c13905d939d009801bd448a7a9d2ca00a30260eedd1feb03fc88e11","src/lib.rs":"1e19a19aa0d414d7548e4bc9510f89bed122430564e044302edd4a21a1b83134","src/roots.rs":"51a994a5e0bf505911cf912954283f52e7aa582ce0cd1c483e6b2e4c09a47b9e","tests/roots.rs":"ef70f711cb1544311c343dbaf411ad2598432e82b6dfa3d166c1d99096991d9e"},"package":"e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"}
|
|
@ -3,7 +3,7 @@
|
||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
# to registry (e.g., crates.io) dependencies
|
# to registry (e.g. crates.io) dependencies
|
||||||
#
|
#
|
||||||
# If you believe there's an error in this file please file an
|
# If you believe there's an error in this file please file an
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
# issue against the rust-lang/cargo repository. If you're
|
||||||
|
@ -12,10 +12,9 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.43"
|
version = "0.1.39"
|
||||||
authors = ["The Rust Project Developers"]
|
authors = ["The Rust Project Developers"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
|
||||||
description = "Integer traits and functions"
|
description = "Integer traits and functions"
|
||||||
homepage = "https://github.com/rust-num/num-integer"
|
homepage = "https://github.com/rust-num/num-integer"
|
||||||
documentation = "https://docs.rs/num-integer"
|
documentation = "https://docs.rs/num-integer"
|
||||||
|
@ -27,10 +26,8 @@ repository = "https://github.com/rust-num/num-integer"
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["std"]
|
features = ["std"]
|
||||||
[dependencies.num-traits]
|
[dependencies.num-traits]
|
||||||
version = "0.2.11"
|
version = "0.2.4"
|
||||||
default-features = false
|
default-features = false
|
||||||
[build-dependencies.autocfg]
|
|
||||||
version = "1"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
[![crate](https://img.shields.io/crates/v/num-integer.svg)](https://crates.io/crates/num-integer)
|
[![crate](https://img.shields.io/crates/v/num-integer.svg)](https://crates.io/crates/num-integer)
|
||||||
[![documentation](https://docs.rs/num-integer/badge.svg)](https://docs.rs/num-integer)
|
[![documentation](https://docs.rs/num-integer/badge.svg)](https://docs.rs/num-integer)
|
||||||
[![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
|
![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
|
||||||
[![build status](https://github.com/rust-num/num-integer/workflows/master/badge.svg)](https://github.com/rust-num/num-integer/actions)
|
[![Travis status](https://travis-ci.org/rust-num/num-integer.svg?branch=master)](https://travis-ci.org/rust-num/num-integer)
|
||||||
|
|
||||||
`Integer` trait and functions for Rust.
|
`Integer` trait and functions for Rust.
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,4 @@
|
||||||
# Release 0.1.43 (2020-06-11)
|
# Release 0.1.39
|
||||||
|
|
||||||
- [The new `Average` trait][31] computes fast integer averages, rounded up or
|
|
||||||
down, without any risk of overflow.
|
|
||||||
|
|
||||||
**Contributors**: @althonos, @cuviper
|
|
||||||
|
|
||||||
[31]: https://github.com/rust-num/num-integer/pull/31
|
|
||||||
|
|
||||||
# Release 0.1.42 (2020-01-09)
|
|
||||||
|
|
||||||
- [Updated the `autocfg` build dependency to 1.0][29].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @dingelish
|
|
||||||
|
|
||||||
[29]: https://github.com/rust-num/num-integer/pull/29
|
|
||||||
|
|
||||||
# Release 0.1.41 (2019-05-21)
|
|
||||||
|
|
||||||
- [Fixed feature detection on `no_std` targets][25].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper
|
|
||||||
|
|
||||||
[25]: https://github.com/rust-num/num-integer/pull/25
|
|
||||||
|
|
||||||
# Release 0.1.40 (2019-05-20)
|
|
||||||
|
|
||||||
- [Optimized primitive `gcd` by avoiding memory swaps][11].
|
|
||||||
- [Fixed `lcm(0, 0)` to return `0`, rather than panicking][18].
|
|
||||||
- [Added `Integer::div_ceil`, `next_multiple_of`, and `prev_multiple_of`][16].
|
|
||||||
- [Added `Integer::gcd_lcm`, `extended_gcd`, and `extended_gcd_lcm`][19].
|
|
||||||
|
|
||||||
**Contributors**: @cuviper, @ignatenkobrain, @smarnach, @strake
|
|
||||||
|
|
||||||
[11]: https://github.com/rust-num/num-integer/pull/11
|
|
||||||
[16]: https://github.com/rust-num/num-integer/pull/16
|
|
||||||
[18]: https://github.com/rust-num/num-integer/pull/18
|
|
||||||
[19]: https://github.com/rust-num/num-integer/pull/19
|
|
||||||
|
|
||||||
# Release 0.1.39 (2018-06-20)
|
|
||||||
|
|
||||||
- [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9],
|
- [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9],
|
||||||
calculating an `Integer`'s principal roots rounded toward zero.
|
calculating an `Integer`'s principal roots rounded toward zero.
|
||||||
|
@ -46,7 +7,7 @@
|
||||||
|
|
||||||
[9]: https://github.com/rust-num/num-integer/pull/9
|
[9]: https://github.com/rust-num/num-integer/pull/9
|
||||||
|
|
||||||
# Release 0.1.38 (2018-05-11)
|
# Release 0.1.38
|
||||||
|
|
||||||
- [Support for 128-bit integers is now automatically detected and enabled.][8]
|
- [Support for 128-bit integers is now automatically detected and enabled.][8]
|
||||||
Setting the `i128` crate feature now causes the build script to panic if such
|
Setting the `i128` crate feature now causes the build script to panic if such
|
||||||
|
@ -56,7 +17,7 @@
|
||||||
|
|
||||||
[8]: https://github.com/rust-num/num-integer/pull/8
|
[8]: https://github.com/rust-num/num-integer/pull/8
|
||||||
|
|
||||||
# Release 0.1.37 (2018-05-10)
|
# Release 0.1.37
|
||||||
|
|
||||||
- [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust
|
- [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust
|
||||||
1.26, enabled by the new `i128` crate feature.
|
1.26, enabled by the new `i128` crate feature.
|
||||||
|
@ -65,7 +26,7 @@
|
||||||
|
|
||||||
[7]: https://github.com/rust-num/num-integer/pull/7
|
[7]: https://github.com/rust-num/num-integer/pull/7
|
||||||
|
|
||||||
# Release 0.1.36 (2018-02-06)
|
# Release 0.1.36
|
||||||
|
|
||||||
- [num-integer now has its own source repository][num-356] at [rust-num/num-integer][home].
|
- [num-integer now has its own source repository][num-356] at [rust-num/num-integer][home].
|
||||||
- [Corrected the argument order documented in `Integer::is_multiple_of`][1]
|
- [Corrected the argument order documented in `Integer::is_multiple_of`][1]
|
||||||
|
|
|
@ -1,414 +0,0 @@
|
||||||
//! Benchmark sqrt and cbrt
|
|
||||||
|
|
||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul};
|
|
||||||
use std::cmp::{max, min};
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use test::{black_box, Bencher};
|
|
||||||
|
|
||||||
// --- Utilities for RNG ----------------------------------------------------
|
|
||||||
|
|
||||||
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
|
|
||||||
|
|
||||||
impl<T> BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
|
|
||||||
|
|
||||||
// Simple PRNG so we don't have to worry about rand compatibility
|
|
||||||
fn lcg<T>(x: T) -> T
|
|
||||||
where
|
|
||||||
u32: AsPrimitive<T>,
|
|
||||||
T: BenchInteger,
|
|
||||||
{
|
|
||||||
// LCG parameters from Numerical Recipes
|
|
||||||
// (but we're applying it to arbitrary sizes)
|
|
||||||
const LCG_A: u32 = 1664525;
|
|
||||||
const LCG_C: u32 = 1013904223;
|
|
||||||
x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_())
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Alt. Implementations -------------------------------------------------
|
|
||||||
|
|
||||||
trait NaiveAverage {
|
|
||||||
fn naive_average_ceil(&self, other: &Self) -> Self;
|
|
||||||
fn naive_average_floor(&self, other: &Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait UncheckedAverage {
|
|
||||||
fn unchecked_average_ceil(&self, other: &Self) -> Self;
|
|
||||||
fn unchecked_average_floor(&self, other: &Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ModuloAverage {
|
|
||||||
fn modulo_average_ceil(&self, other: &Self) -> Self;
|
|
||||||
fn modulo_average_floor(&self, other: &Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! naive_average {
|
|
||||||
($T:ident) => {
|
|
||||||
impl super::NaiveAverage for $T {
|
|
||||||
fn naive_average_floor(&self, other: &$T) -> $T {
|
|
||||||
match self.checked_add(*other) {
|
|
||||||
Some(z) => z.div_floor(&2),
|
|
||||||
None => {
|
|
||||||
if self > other {
|
|
||||||
let diff = self - other;
|
|
||||||
other + diff.div_floor(&2)
|
|
||||||
} else {
|
|
||||||
let diff = other - self;
|
|
||||||
self + diff.div_floor(&2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn naive_average_ceil(&self, other: &$T) -> $T {
|
|
||||||
match self.checked_add(*other) {
|
|
||||||
Some(z) => z.div_ceil(&2),
|
|
||||||
None => {
|
|
||||||
if self > other {
|
|
||||||
let diff = self - other;
|
|
||||||
self - diff.div_floor(&2)
|
|
||||||
} else {
|
|
||||||
let diff = other - self;
|
|
||||||
other - diff.div_floor(&2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! unchecked_average {
|
|
||||||
($T:ident) => {
|
|
||||||
impl super::UncheckedAverage for $T {
|
|
||||||
fn unchecked_average_floor(&self, other: &$T) -> $T {
|
|
||||||
self.wrapping_add(*other) / 2
|
|
||||||
}
|
|
||||||
fn unchecked_average_ceil(&self, other: &$T) -> $T {
|
|
||||||
(self.wrapping_add(*other) / 2).wrapping_add(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! modulo_average {
|
|
||||||
($T:ident) => {
|
|
||||||
impl super::ModuloAverage for $T {
|
|
||||||
fn modulo_average_ceil(&self, other: &$T) -> $T {
|
|
||||||
let (q1, r1) = self.div_mod_floor(&2);
|
|
||||||
let (q2, r2) = other.div_mod_floor(&2);
|
|
||||||
q1 + q2 + (r1 | r2)
|
|
||||||
}
|
|
||||||
fn modulo_average_floor(&self, other: &$T) -> $T {
|
|
||||||
let (q1, r1) = self.div_mod_floor(&2);
|
|
||||||
let (q2, r2) = other.div_mod_floor(&2);
|
|
||||||
q1 + q2 + (r1 * r2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Bench functions ------------------------------------------------------
|
|
||||||
|
|
||||||
fn bench_unchecked<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
|
|
||||||
where
|
|
||||||
T: Integer + Debug + Copy,
|
|
||||||
F: Fn(&T, &T) -> T,
|
|
||||||
{
|
|
||||||
b.iter(|| {
|
|
||||||
for (x, y) in v {
|
|
||||||
black_box(f(x, y));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_ceil<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
|
|
||||||
where
|
|
||||||
T: Integer + Debug + Copy,
|
|
||||||
F: Fn(&T, &T) -> T,
|
|
||||||
{
|
|
||||||
for &(i, j) in v {
|
|
||||||
let rt = f(&i, &j);
|
|
||||||
let (a, b) = (min(i, j), max(i, j));
|
|
||||||
// if both number are the same sign, check rt is in the middle
|
|
||||||
if (a < T::zero()) == (b < T::zero()) {
|
|
||||||
if (b - a).is_even() {
|
|
||||||
assert_eq!(rt - a, b - rt);
|
|
||||||
} else {
|
|
||||||
assert_eq!(rt - a, b - rt + T::one());
|
|
||||||
}
|
|
||||||
// if both number have a different sign,
|
|
||||||
} else {
|
|
||||||
if (a + b).is_even() {
|
|
||||||
assert_eq!(rt, (a + b) / (T::one() + T::one()))
|
|
||||||
} else {
|
|
||||||
assert_eq!(rt, (a + b + T::one()) / (T::one() + T::one()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bench_unchecked(b, v, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bench_floor<T, F>(b: &mut Bencher, v: &[(T, T)], f: F)
|
|
||||||
where
|
|
||||||
T: Integer + Debug + Copy,
|
|
||||||
F: Fn(&T, &T) -> T,
|
|
||||||
{
|
|
||||||
for &(i, j) in v {
|
|
||||||
let rt = f(&i, &j);
|
|
||||||
let (a, b) = (min(i, j), max(i, j));
|
|
||||||
// if both number are the same sign, check rt is in the middle
|
|
||||||
if (a < T::zero()) == (b < T::zero()) {
|
|
||||||
if (b - a).is_even() {
|
|
||||||
assert_eq!(rt - a, b - rt);
|
|
||||||
} else {
|
|
||||||
assert_eq!(rt - a + T::one(), b - rt);
|
|
||||||
}
|
|
||||||
// if both number have a different sign,
|
|
||||||
} else {
|
|
||||||
if (a + b).is_even() {
|
|
||||||
assert_eq!(rt, (a + b) / (T::one() + T::one()))
|
|
||||||
} else {
|
|
||||||
assert_eq!(rt, (a + b - T::one()) / (T::one() + T::one()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bench_unchecked(b, v, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Bench implementation -------------------------------------------------
|
|
||||||
|
|
||||||
macro_rules! bench_average {
|
|
||||||
($($T:ident),*) => {$(
|
|
||||||
mod $T {
|
|
||||||
use test::Bencher;
|
|
||||||
use num_integer::{Average, Integer};
|
|
||||||
use super::{UncheckedAverage, NaiveAverage, ModuloAverage};
|
|
||||||
use super::{bench_ceil, bench_floor, bench_unchecked};
|
|
||||||
|
|
||||||
naive_average!($T);
|
|
||||||
unchecked_average!($T);
|
|
||||||
modulo_average!($T);
|
|
||||||
|
|
||||||
const SIZE: $T = 30;
|
|
||||||
|
|
||||||
fn overflowing() -> Vec<($T, $T)> {
|
|
||||||
(($T::max_value()-SIZE)..$T::max_value())
|
|
||||||
.flat_map(|x| -> Vec<_> {
|
|
||||||
(($T::max_value()-100)..($T::max_value()-100+SIZE))
|
|
||||||
.map(|y| (x, y))
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn small() -> Vec<($T, $T)> {
|
|
||||||
(0..SIZE)
|
|
||||||
.flat_map(|x| -> Vec<_> {(0..SIZE).map(|y| (x, y)).collect()})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rand() -> Vec<($T, $T)> {
|
|
||||||
small()
|
|
||||||
.into_iter()
|
|
||||||
.map(|(x, y)| (super::lcg(x), super::lcg(y)))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
mod ceil {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
mod small {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn optimized(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn naive(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn unchecked(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modulo(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod overflowing {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn optimized(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn naive(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn unchecked(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modulo(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod rand {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn optimized(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn naive(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.naive_average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn unchecked(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_ceil(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modulo(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_ceil(b, &v, |x: &$T, y: &$T| x.modulo_average_ceil(y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mod floor {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
mod small {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn optimized(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn naive(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn unchecked(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modulo(b: &mut Bencher) {
|
|
||||||
let v = small();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod overflowing {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn optimized(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn naive(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn unchecked(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modulo(b: &mut Bencher) {
|
|
||||||
let v = overflowing();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod rand {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn optimized(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn naive(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.naive_average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn unchecked(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_unchecked(b, &v, |x: &$T, y: &$T| x.unchecked_average_floor(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn modulo(b: &mut Bencher) {
|
|
||||||
let v = rand();
|
|
||||||
bench_floor(b, &v, |x: &$T, y: &$T| x.modulo_average_floor(y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
)*}
|
|
||||||
}
|
|
||||||
|
|
||||||
bench_average!(i8, i16, i32, i64, i128, isize);
|
|
||||||
bench_average!(u8, u16, u32, u64, u128, usize);
|
|
|
@ -1,176 +0,0 @@
|
||||||
//! Benchmark comparing the current GCD implemtation against an older one.
|
|
||||||
|
|
||||||
#![feature(test)]
|
|
||||||
|
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
extern crate test;
|
|
||||||
|
|
||||||
use num_integer::Integer;
|
|
||||||
use num_traits::{AsPrimitive, Bounded, Signed};
|
|
||||||
use test::{black_box, Bencher};
|
|
||||||
|
|
||||||
trait GcdOld: Integer {
|
|
||||||
fn gcd_old(&self, other: &Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_gcd_old_for_isize {
|
|
||||||
($T:ty) => {
|
|
||||||
impl GcdOld for $T {
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) of the number and
|
|
||||||
/// `other`. The result is always positive.
|
|
||||||
#[inline]
|
|
||||||
fn gcd_old(&self, other: &Self) -> Self {
|
|
||||||
// Use Stein's algorithm
|
|
||||||
let mut m = *self;
|
|
||||||
let mut n = *other;
|
|
||||||
if m == 0 || n == 0 {
|
|
||||||
return (m | n).abs();
|
|
||||||
}
|
|
||||||
|
|
||||||
// find common factors of 2
|
|
||||||
let shift = (m | n).trailing_zeros();
|
|
||||||
|
|
||||||
// The algorithm needs positive numbers, but the minimum value
|
|
||||||
// can't be represented as a positive one.
|
|
||||||
// It's also a power of two, so the gcd can be
|
|
||||||
// calculated by bitshifting in that case
|
|
||||||
|
|
||||||
// Assuming two's complement, the number created by the shift
|
|
||||||
// is positive for all numbers except gcd = abs(min value)
|
|
||||||
// The call to .abs() causes a panic in debug mode
|
|
||||||
if m == Self::min_value() || n == Self::min_value() {
|
|
||||||
return (1 << shift).abs();
|
|
||||||
}
|
|
||||||
|
|
||||||
// guaranteed to be positive now, rest like unsigned algorithm
|
|
||||||
m = m.abs();
|
|
||||||
n = n.abs();
|
|
||||||
|
|
||||||
// divide n and m by 2 until odd
|
|
||||||
// m inside loop
|
|
||||||
n >>= n.trailing_zeros();
|
|
||||||
|
|
||||||
while m != 0 {
|
|
||||||
m >>= m.trailing_zeros();
|
|
||||||
if n > m {
|
|
||||||
std::mem::swap(&mut n, &mut m)
|
|
||||||
}
|
|
||||||
m -= n;
|
|
||||||
}
|
|
||||||
|
|
||||||
n << shift
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_gcd_old_for_isize!(i8);
|
|
||||||
impl_gcd_old_for_isize!(i16);
|
|
||||||
impl_gcd_old_for_isize!(i32);
|
|
||||||
impl_gcd_old_for_isize!(i64);
|
|
||||||
impl_gcd_old_for_isize!(isize);
|
|
||||||
impl_gcd_old_for_isize!(i128);
|
|
||||||
|
|
||||||
macro_rules! impl_gcd_old_for_usize {
|
|
||||||
($T:ty) => {
|
|
||||||
impl GcdOld for $T {
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) of the number and
|
|
||||||
/// `other`. The result is always positive.
|
|
||||||
#[inline]
|
|
||||||
fn gcd_old(&self, other: &Self) -> Self {
|
|
||||||
// Use Stein's algorithm
|
|
||||||
let mut m = *self;
|
|
||||||
let mut n = *other;
|
|
||||||
if m == 0 || n == 0 {
|
|
||||||
return m | n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find common factors of 2
|
|
||||||
let shift = (m | n).trailing_zeros();
|
|
||||||
|
|
||||||
// divide n and m by 2 until odd
|
|
||||||
// m inside loop
|
|
||||||
n >>= n.trailing_zeros();
|
|
||||||
|
|
||||||
while m != 0 {
|
|
||||||
m >>= m.trailing_zeros();
|
|
||||||
if n > m {
|
|
||||||
std::mem::swap(&mut n, &mut m)
|
|
||||||
}
|
|
||||||
m -= n;
|
|
||||||
}
|
|
||||||
|
|
||||||
n << shift
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_gcd_old_for_usize!(u8);
|
|
||||||
impl_gcd_old_for_usize!(u16);
|
|
||||||
impl_gcd_old_for_usize!(u32);
|
|
||||||
impl_gcd_old_for_usize!(u64);
|
|
||||||
impl_gcd_old_for_usize!(usize);
|
|
||||||
impl_gcd_old_for_usize!(u128);
|
|
||||||
|
|
||||||
/// Return an iterator that yields all Fibonacci numbers fitting into a u128.
|
|
||||||
fn fibonacci() -> impl Iterator<Item = u128> {
|
|
||||||
(0..185).scan((0, 1), |&mut (ref mut a, ref mut b), _| {
|
|
||||||
let tmp = *a;
|
|
||||||
*a = *b;
|
|
||||||
*b += tmp;
|
|
||||||
Some(*b)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_bench<T: Integer + Bounded + Copy + 'static>(b: &mut Bencher, gcd: fn(&T, &T) -> T)
|
|
||||||
where
|
|
||||||
T: AsPrimitive<u128>,
|
|
||||||
u128: AsPrimitive<T>,
|
|
||||||
{
|
|
||||||
let max_value: u128 = T::max_value().as_();
|
|
||||||
let pairs: Vec<(T, T)> = fibonacci()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.windows(2)
|
|
||||||
.filter(|&pair| pair[0] <= max_value && pair[1] <= max_value)
|
|
||||||
.map(|pair| (pair[0].as_(), pair[1].as_()))
|
|
||||||
.collect();
|
|
||||||
b.iter(|| {
|
|
||||||
for &(ref m, ref n) in &pairs {
|
|
||||||
black_box(gcd(m, n));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! bench_gcd {
|
|
||||||
($T:ident) => {
|
|
||||||
mod $T {
|
|
||||||
use crate::{run_bench, GcdOld};
|
|
||||||
use num_integer::Integer;
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_gcd(b: &mut Bencher) {
|
|
||||||
run_bench(b, $T::gcd);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_gcd_old(b: &mut Bencher) {
|
|
||||||
run_bench(b, $T::gcd_old);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bench_gcd!(u8);
|
|
||||||
bench_gcd!(u16);
|
|
||||||
bench_gcd!(u32);
|
|
||||||
bench_gcd!(u64);
|
|
||||||
bench_gcd!(u128);
|
|
||||||
|
|
||||||
bench_gcd!(i8);
|
|
||||||
bench_gcd!(i16);
|
|
||||||
bench_gcd!(i32);
|
|
||||||
bench_gcd!(i64);
|
|
||||||
bench_gcd!(i128);
|
|
|
@ -13,7 +13,11 @@ use test::{black_box, Bencher};
|
||||||
|
|
||||||
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
|
trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
|
||||||
|
|
||||||
impl<T> BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {}
|
impl<T> BenchInteger for T
|
||||||
|
where
|
||||||
|
T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
fn bench<T, F>(b: &mut Bencher, v: &[T], f: F, n: u32)
|
fn bench<T, F>(b: &mut Bencher, v: &[T], f: F, n: u32)
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,14 +1,35 @@
|
||||||
extern crate autocfg;
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ac = autocfg::new();
|
if probe("fn main() { 0i128; }") {
|
||||||
if ac.probe_type("i128") {
|
|
||||||
println!("cargo:rustc-cfg=has_i128");
|
println!("cargo:rustc-cfg=has_i128");
|
||||||
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
||||||
panic!("i128 support was not detected!");
|
panic!("i128 support was not detected!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
autocfg::rerun_path("build.rs");
|
|
||||||
|
/// 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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Use rustup to locally run the same suite of tests as .travis.yml.
|
||||||
|
# (You should first install/update 1.8.0, stable, beta, and nightly.)
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
export TRAVIS_RUST_VERSION
|
||||||
|
for TRAVIS_RUST_VERSION in 1.8.0 1.15.0 1.20.0 stable beta nightly; do
|
||||||
|
run="rustup run $TRAVIS_RUST_VERSION"
|
||||||
|
$run cargo build --verbose
|
||||||
|
$run $PWD/ci/test_full.sh
|
||||||
|
done
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
echo Testing num-integer on rustc ${TRAVIS_RUST_VERSION}
|
||||||
|
|
||||||
|
# num-integer should build and test everywhere.
|
||||||
|
cargo build --verbose
|
||||||
|
cargo test --verbose
|
||||||
|
|
||||||
|
# test `no_std`
|
||||||
|
cargo build --verbose --no-default-features
|
||||||
|
cargo test --verbose --no-default-features
|
||||||
|
|
||||||
|
# test `i128`
|
||||||
|
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable)$ ]]; then
|
||||||
|
cargo build --verbose --features=i128
|
||||||
|
cargo test --verbose --features=i128
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||||
|
cargo test --verbose --all-features --benches
|
||||||
|
fi
|
|
@ -1,78 +0,0 @@
|
||||||
use core::ops::{BitAnd, BitOr, BitXor, Shr};
|
|
||||||
use Integer;
|
|
||||||
|
|
||||||
/// Provides methods to compute the average of two integers, without overflows.
|
|
||||||
pub trait Average: Integer {
|
|
||||||
/// Returns the ceiling value of the average of `self` and `other`.
|
|
||||||
/// -- `⌈(self + other)/2⌉`
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use num_integer::Average;
|
|
||||||
///
|
|
||||||
/// assert_eq!(( 3).average_ceil(&10), 7);
|
|
||||||
/// assert_eq!((-2).average_ceil(&-5), -3);
|
|
||||||
/// assert_eq!(( 4).average_ceil(& 4), 4);
|
|
||||||
///
|
|
||||||
/// assert_eq!(u8::max_value().average_ceil(&2), 129);
|
|
||||||
/// assert_eq!(i8::min_value().average_ceil(&-1), -64);
|
|
||||||
/// assert_eq!(i8::min_value().average_ceil(&i8::max_value()), 0);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
fn average_ceil(&self, other: &Self) -> Self;
|
|
||||||
|
|
||||||
/// Returns the floor value of the average of `self` and `other`.
|
|
||||||
/// -- `⌊(self + other)/2⌋`
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use num_integer::Average;
|
|
||||||
///
|
|
||||||
/// assert_eq!(( 3).average_floor(&10), 6);
|
|
||||||
/// assert_eq!((-2).average_floor(&-5), -4);
|
|
||||||
/// assert_eq!(( 4).average_floor(& 4), 4);
|
|
||||||
///
|
|
||||||
/// assert_eq!(u8::max_value().average_floor(&2), 128);
|
|
||||||
/// assert_eq!(i8::min_value().average_floor(&-1), -65);
|
|
||||||
/// assert_eq!(i8::min_value().average_floor(&i8::max_value()), -1);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
fn average_floor(&self, other: &Self) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> Average for I
|
|
||||||
where
|
|
||||||
I: Integer + Shr<usize, Output = I>,
|
|
||||||
for<'a, 'b> &'a I:
|
|
||||||
BitAnd<&'b I, Output = I> + BitOr<&'b I, Output = I> + BitXor<&'b I, Output = I>,
|
|
||||||
{
|
|
||||||
// The Henry Gordon Dietz implementation as shown in the Hacker's Delight,
|
|
||||||
// see http://aggregate.org/MAGIC/#Average%20of%20Integers
|
|
||||||
|
|
||||||
/// Returns the floor value of the average of `self` and `other`.
|
|
||||||
#[inline]
|
|
||||||
fn average_floor(&self, other: &I) -> I {
|
|
||||||
(self & other) + ((self ^ other) >> 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the ceil value of the average of `self` and `other`.
|
|
||||||
#[inline]
|
|
||||||
fn average_ceil(&self, other: &I) -> I {
|
|
||||||
(self | other) - ((self ^ other) >> 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the floor value of the average of `x` and `y` --
|
|
||||||
/// see [Average::average_floor](trait.Average.html#tymethod.average_floor).
|
|
||||||
#[inline]
|
|
||||||
pub fn average_floor<T: Average>(x: T, y: T) -> T {
|
|
||||||
x.average_floor(&y)
|
|
||||||
}
|
|
||||||
/// Returns the ceiling value of the average of `x` and `y` --
|
|
||||||
/// see [Average::average_ceil](trait.Average.html#tymethod.average_ceil).
|
|
||||||
#[inline]
|
|
||||||
pub fn average_ceil<T: Average>(x: T, y: T) -> T {
|
|
||||||
x.average_ceil(&y)
|
|
||||||
}
|
|
|
@ -15,24 +15,21 @@
|
||||||
//! The `num-integer` crate is tested for rustc 1.8 and greater.
|
//! The `num-integer` crate is tested for rustc 1.8 and greater.
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/num-integer/0.1")]
|
#![doc(html_root_url = "https://docs.rs/num-integer/0.1")]
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
extern crate num_traits as traits;
|
extern crate num_traits as traits;
|
||||||
|
|
||||||
use core::mem;
|
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
use traits::{Num, Signed, Zero};
|
use traits::{Num, Signed};
|
||||||
|
|
||||||
mod roots;
|
mod roots;
|
||||||
pub use roots::Roots;
|
pub use roots::Roots;
|
||||||
pub use roots::{cbrt, nth_root, sqrt};
|
pub use roots::{sqrt, cbrt, nth_root};
|
||||||
|
|
||||||
mod average;
|
|
||||||
pub use average::Average;
|
|
||||||
pub use average::{average_ceil, average_floor};
|
|
||||||
|
|
||||||
pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||||
/// Floored integer division.
|
/// Floored integer division.
|
||||||
|
@ -77,31 +74,6 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||||
/// ~~~
|
/// ~~~
|
||||||
fn mod_floor(&self, other: &Self) -> Self;
|
fn mod_floor(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
/// Ceiled integer division.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ~~~
|
|
||||||
/// # use num_integer::Integer;
|
|
||||||
/// assert_eq!(( 8).div_ceil( &3), 3);
|
|
||||||
/// assert_eq!(( 8).div_ceil(&-3), -2);
|
|
||||||
/// assert_eq!((-8).div_ceil( &3), -2);
|
|
||||||
/// assert_eq!((-8).div_ceil(&-3), 3);
|
|
||||||
///
|
|
||||||
/// assert_eq!(( 1).div_ceil( &2), 1);
|
|
||||||
/// assert_eq!(( 1).div_ceil(&-2), 0);
|
|
||||||
/// assert_eq!((-1).div_ceil( &2), 0);
|
|
||||||
/// assert_eq!((-1).div_ceil(&-2), 1);
|
|
||||||
/// ~~~
|
|
||||||
fn div_ceil(&self, other: &Self) -> Self {
|
|
||||||
let (q, r) = self.div_mod_floor(other);
|
|
||||||
if r.is_zero() {
|
|
||||||
q
|
|
||||||
} else {
|
|
||||||
q + Self::one()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Greatest Common Divisor (GCD).
|
/// Greatest Common Divisor (GCD).
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -121,93 +93,9 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||||
/// # use num_integer::Integer;
|
/// # use num_integer::Integer;
|
||||||
/// assert_eq!(7.lcm(&3), 21);
|
/// assert_eq!(7.lcm(&3), 21);
|
||||||
/// assert_eq!(2.lcm(&4), 4);
|
/// assert_eq!(2.lcm(&4), 4);
|
||||||
/// assert_eq!(0.lcm(&0), 0);
|
|
||||||
/// ~~~
|
/// ~~~
|
||||||
fn lcm(&self, other: &Self) -> Self;
|
fn lcm(&self, other: &Self) -> Self;
|
||||||
|
|
||||||
/// Greatest Common Divisor (GCD) and
|
|
||||||
/// Lowest Common Multiple (LCM) together.
|
|
||||||
///
|
|
||||||
/// Potentially more efficient than calling `gcd` and `lcm`
|
|
||||||
/// individually for identical inputs.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ~~~
|
|
||||||
/// # use num_integer::Integer;
|
|
||||||
/// assert_eq!(10.gcd_lcm(&4), (2, 20));
|
|
||||||
/// assert_eq!(8.gcd_lcm(&9), (1, 72));
|
|
||||||
/// ~~~
|
|
||||||
#[inline]
|
|
||||||
fn gcd_lcm(&self, other: &Self) -> (Self, Self) {
|
|
||||||
(self.gcd(other), self.lcm(other))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Greatest common divisor and Bézout coefficients.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ~~~
|
|
||||||
/// # extern crate num_integer;
|
|
||||||
/// # extern crate num_traits;
|
|
||||||
/// # fn main() {
|
|
||||||
/// # use num_integer::{ExtendedGcd, Integer};
|
|
||||||
/// # use num_traits::NumAssign;
|
|
||||||
/// fn check<A: Copy + Integer + NumAssign>(a: A, b: A) -> bool {
|
|
||||||
/// let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b);
|
|
||||||
/// gcd == x * a + y * b
|
|
||||||
/// }
|
|
||||||
/// assert!(check(10isize, 4isize));
|
|
||||||
/// assert!(check(8isize, 9isize));
|
|
||||||
/// # }
|
|
||||||
/// ~~~
|
|
||||||
#[inline]
|
|
||||||
fn extended_gcd(&self, other: &Self) -> ExtendedGcd<Self>
|
|
||||||
where
|
|
||||||
Self: Clone,
|
|
||||||
{
|
|
||||||
let mut s = (Self::zero(), Self::one());
|
|
||||||
let mut t = (Self::one(), Self::zero());
|
|
||||||
let mut r = (other.clone(), self.clone());
|
|
||||||
|
|
||||||
while !r.0.is_zero() {
|
|
||||||
let q = r.1.clone() / r.0.clone();
|
|
||||||
let f = |mut r: (Self, Self)| {
|
|
||||||
mem::swap(&mut r.0, &mut r.1);
|
|
||||||
r.0 = r.0 - q.clone() * r.1.clone();
|
|
||||||
r
|
|
||||||
};
|
|
||||||
r = f(r);
|
|
||||||
s = f(s);
|
|
||||||
t = f(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.1 >= Self::zero() {
|
|
||||||
ExtendedGcd {
|
|
||||||
gcd: r.1,
|
|
||||||
x: s.1,
|
|
||||||
y: t.1,
|
|
||||||
_hidden: (),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ExtendedGcd {
|
|
||||||
gcd: Self::zero() - r.1,
|
|
||||||
x: Self::zero() - s.1,
|
|
||||||
y: Self::zero() - t.1,
|
|
||||||
_hidden: (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Greatest common divisor, least common multiple, and Bézout coefficients.
|
|
||||||
#[inline]
|
|
||||||
fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd<Self>, Self)
|
|
||||||
where
|
|
||||||
Self: Clone + Signed,
|
|
||||||
{
|
|
||||||
(self.extended_gcd(other), self.lcm(other))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deprecated, use `is_multiple_of` instead.
|
/// Deprecated, use `is_multiple_of` instead.
|
||||||
fn divides(&self, other: &Self) -> bool;
|
fn divides(&self, other: &Self) -> bool;
|
||||||
|
|
||||||
|
@ -261,6 +149,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||||
/// assert_eq!((-1).div_rem( &2), ( 0, -1));
|
/// assert_eq!((-1).div_rem( &2), ( 0, -1));
|
||||||
/// assert_eq!((-1).div_rem(&-2), ( 0, -1));
|
/// assert_eq!((-1).div_rem(&-2), ( 0, -1));
|
||||||
/// ~~~
|
/// ~~~
|
||||||
|
#[inline]
|
||||||
fn div_rem(&self, other: &Self) -> (Self, Self);
|
fn div_rem(&self, other: &Self) -> (Self, Self);
|
||||||
|
|
||||||
/// Simultaneous floored integer division and modulus.
|
/// Simultaneous floored integer division and modulus.
|
||||||
|
@ -283,80 +172,6 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||||
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
|
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
|
||||||
(self.div_floor(other), self.mod_floor(other))
|
(self.div_floor(other), self.mod_floor(other))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rounds up to nearest multiple of argument.
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
///
|
|
||||||
/// For signed types, `a.next_multiple_of(b) = a.prev_multiple_of(b.neg())`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ~~~
|
|
||||||
/// # use num_integer::Integer;
|
|
||||||
/// assert_eq!(( 16).next_multiple_of(& 8), 16);
|
|
||||||
/// assert_eq!(( 23).next_multiple_of(& 8), 24);
|
|
||||||
/// assert_eq!(( 16).next_multiple_of(&-8), 16);
|
|
||||||
/// assert_eq!(( 23).next_multiple_of(&-8), 16);
|
|
||||||
/// assert_eq!((-16).next_multiple_of(& 8), -16);
|
|
||||||
/// assert_eq!((-23).next_multiple_of(& 8), -16);
|
|
||||||
/// assert_eq!((-16).next_multiple_of(&-8), -16);
|
|
||||||
/// assert_eq!((-23).next_multiple_of(&-8), -24);
|
|
||||||
/// ~~~
|
|
||||||
#[inline]
|
|
||||||
fn next_multiple_of(&self, other: &Self) -> Self
|
|
||||||
where
|
|
||||||
Self: Clone,
|
|
||||||
{
|
|
||||||
let m = self.mod_floor(other);
|
|
||||||
self.clone()
|
|
||||||
+ if m.is_zero() {
|
|
||||||
Self::zero()
|
|
||||||
} else {
|
|
||||||
other.clone() - m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rounds down to nearest multiple of argument.
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
///
|
|
||||||
/// For signed types, `a.prev_multiple_of(b) = a.next_multiple_of(b.neg())`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ~~~
|
|
||||||
/// # use num_integer::Integer;
|
|
||||||
/// assert_eq!(( 16).prev_multiple_of(& 8), 16);
|
|
||||||
/// assert_eq!(( 23).prev_multiple_of(& 8), 16);
|
|
||||||
/// assert_eq!(( 16).prev_multiple_of(&-8), 16);
|
|
||||||
/// assert_eq!(( 23).prev_multiple_of(&-8), 24);
|
|
||||||
/// assert_eq!((-16).prev_multiple_of(& 8), -16);
|
|
||||||
/// assert_eq!((-23).prev_multiple_of(& 8), -24);
|
|
||||||
/// assert_eq!((-16).prev_multiple_of(&-8), -16);
|
|
||||||
/// assert_eq!((-23).prev_multiple_of(&-8), -16);
|
|
||||||
/// ~~~
|
|
||||||
#[inline]
|
|
||||||
fn prev_multiple_of(&self, other: &Self) -> Self
|
|
||||||
where
|
|
||||||
Self: Clone,
|
|
||||||
{
|
|
||||||
self.clone() - self.mod_floor(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Greatest common divisor and Bézout coefficients
|
|
||||||
///
|
|
||||||
/// ```no_build
|
|
||||||
/// let e = isize::extended_gcd(a, b);
|
|
||||||
/// assert_eq!(e.gcd, e.x*a + e.y*b);
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct ExtendedGcd<A> {
|
|
||||||
pub gcd: A,
|
|
||||||
pub x: A,
|
|
||||||
pub y: A,
|
|
||||||
_hidden: (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simultaneous integer division and modulus
|
/// Simultaneous integer division and modulus
|
||||||
|
@ -379,11 +194,6 @@ pub fn mod_floor<T: Integer>(x: T, y: T) -> T {
|
||||||
pub fn div_mod_floor<T: Integer>(x: T, y: T) -> (T, T) {
|
pub fn div_mod_floor<T: Integer>(x: T, y: T) -> (T, T) {
|
||||||
x.div_mod_floor(&y)
|
x.div_mod_floor(&y)
|
||||||
}
|
}
|
||||||
/// Ceiled integer division
|
|
||||||
#[inline]
|
|
||||||
pub fn div_ceil<T: Integer>(x: T, y: T) -> T {
|
|
||||||
x.div_ceil(&y)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The
|
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The
|
||||||
/// result is always positive.
|
/// result is always positive.
|
||||||
|
@ -397,26 +207,18 @@ pub fn lcm<T: Integer>(x: T, y: T) -> T {
|
||||||
x.lcm(&y)
|
x.lcm(&y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) and
|
|
||||||
/// Lowest Common Multiple (LCM) of the number and `other`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn gcd_lcm<T: Integer>(x: T, y: T) -> (T, T) {
|
|
||||||
x.gcd_lcm(&y)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_integer_for_isize {
|
macro_rules! impl_integer_for_isize {
|
||||||
($T:ty, $test_mod:ident) => {
|
($T:ty, $test_mod:ident) => (
|
||||||
impl Integer for $T {
|
impl Integer for $T {
|
||||||
/// Floored integer division
|
/// Floored integer division
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div_floor(&self, other: &Self) -> Self {
|
fn div_floor(&self, other: &Self) -> Self {
|
||||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||||
let (d, r) = self.div_rem(other);
|
match self.div_rem(other) {
|
||||||
if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
|
(d, r) if (r > 0 && *other < 0)
|
||||||
d - 1
|
|| (r < 0 && *other > 0) => d - 1,
|
||||||
} else {
|
(d, _) => d,
|
||||||
d
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,11 +227,10 @@ macro_rules! impl_integer_for_isize {
|
||||||
fn mod_floor(&self, other: &Self) -> Self {
|
fn mod_floor(&self, other: &Self) -> Self {
|
||||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||||
let r = *self % *other;
|
match *self % *other {
|
||||||
if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
|
r if (r > 0 && *other < 0)
|
||||||
r + *other
|
|| (r < 0 && *other > 0) => r + *other,
|
||||||
} else {
|
r => r,
|
||||||
r
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,21 +239,10 @@ macro_rules! impl_integer_for_isize {
|
||||||
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
|
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
|
||||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||||
let (d, r) = self.div_rem(other);
|
match self.div_rem(other) {
|
||||||
if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
|
(d, r) if (r > 0 && *other < 0)
|
||||||
(d - 1, r + *other)
|
|| (r < 0 && *other > 0) => (d - 1, r + *other),
|
||||||
} else {
|
(d, r) => (d, r),
|
||||||
(d, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div_ceil(&self, other: &Self) -> Self {
|
|
||||||
let (d, r) = self.div_rem(other);
|
|
||||||
if (r > 0 && *other > 0) || (r < 0 && *other < 0) {
|
|
||||||
d + 1
|
|
||||||
} else {
|
|
||||||
d
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,9 +253,7 @@ macro_rules! impl_integer_for_isize {
|
||||||
// Use Stein's algorithm
|
// Use Stein's algorithm
|
||||||
let mut m = *self;
|
let mut m = *self;
|
||||||
let mut n = *other;
|
let mut n = *other;
|
||||||
if m == 0 || n == 0 {
|
if m == 0 || n == 0 { return (m | n).abs() }
|
||||||
return (m | n).abs();
|
|
||||||
}
|
|
||||||
|
|
||||||
// find common factors of 2
|
// find common factors of 2
|
||||||
let shift = (m | n).trailing_zeros();
|
let shift = (m | n).trailing_zeros();
|
||||||
|
@ -479,7 +267,7 @@ macro_rules! impl_integer_for_isize {
|
||||||
// is positive for all numbers except gcd = abs(min value)
|
// is positive for all numbers except gcd = abs(min value)
|
||||||
// The call to .abs() causes a panic in debug mode
|
// The call to .abs() causes a panic in debug mode
|
||||||
if m == Self::min_value() || n == Self::min_value() {
|
if m == Self::min_value() || n == Self::min_value() {
|
||||||
return (1 << shift).abs();
|
return (1 << shift).abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// guaranteed to be positive now, rest like unsigned algorithm
|
// guaranteed to be positive now, rest like unsigned algorithm
|
||||||
|
@ -487,51 +275,24 @@ macro_rules! impl_integer_for_isize {
|
||||||
n = n.abs();
|
n = n.abs();
|
||||||
|
|
||||||
// divide n and m by 2 until odd
|
// divide n and m by 2 until odd
|
||||||
m >>= m.trailing_zeros();
|
// m inside loop
|
||||||
n >>= n.trailing_zeros();
|
n >>= n.trailing_zeros();
|
||||||
|
|
||||||
while m != n {
|
while m != 0 {
|
||||||
if m > n {
|
m >>= m.trailing_zeros();
|
||||||
m -= n;
|
if n > m { mem::swap(&mut n, &mut m) }
|
||||||
m >>= m.trailing_zeros();
|
m -= n;
|
||||||
} else {
|
|
||||||
n -= m;
|
|
||||||
n >>= n.trailing_zeros();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m << shift
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
n << shift
|
||||||
fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd<Self>, Self) {
|
|
||||||
let egcd = self.extended_gcd(other);
|
|
||||||
// should not have to recalculate abs
|
|
||||||
let lcm = if egcd.gcd.is_zero() {
|
|
||||||
Self::zero()
|
|
||||||
} else {
|
|
||||||
(*self * (*other / egcd.gcd)).abs()
|
|
||||||
};
|
|
||||||
(egcd, lcm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the Lowest Common Multiple (LCM) of the number and
|
/// Calculates the Lowest Common Multiple (LCM) of the number and
|
||||||
/// `other`.
|
/// `other`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lcm(&self, other: &Self) -> Self {
|
fn lcm(&self, other: &Self) -> Self {
|
||||||
self.gcd_lcm(other).1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) and
|
|
||||||
/// Lowest Common Multiple (LCM) of the number and `other`.
|
|
||||||
#[inline]
|
|
||||||
fn gcd_lcm(&self, other: &Self) -> (Self, Self) {
|
|
||||||
if self.is_zero() && other.is_zero() {
|
|
||||||
return (Self::zero(), Self::zero());
|
|
||||||
}
|
|
||||||
let gcd = self.gcd(other);
|
|
||||||
// should not have to recalculate abs
|
// should not have to recalculate abs
|
||||||
let lcm = (*self * (*other / gcd)).abs();
|
(*self * (*other / self.gcd(other))).abs()
|
||||||
(gcd, lcm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated, use `is_multiple_of` instead.
|
/// Deprecated, use `is_multiple_of` instead.
|
||||||
|
@ -548,15 +309,11 @@ macro_rules! impl_integer_for_isize {
|
||||||
|
|
||||||
/// Returns `true` if the number is divisible by `2`
|
/// Returns `true` if the number is divisible by `2`
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_even(&self) -> bool {
|
fn is_even(&self) -> bool { (*self) & 1 == 0 }
|
||||||
(*self) & 1 == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the number is not divisible by `2`
|
/// Returns `true` if the number is not divisible by `2`
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_odd(&self) -> bool {
|
fn is_odd(&self) -> bool { !self.is_even() }
|
||||||
!self.is_even()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simultaneous truncated integer division and modulus.
|
/// Simultaneous truncated integer division and modulus.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -567,8 +324,8 @@ macro_rules! impl_integer_for_isize {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod $test_mod {
|
mod $test_mod {
|
||||||
use core::mem;
|
|
||||||
use Integer;
|
use Integer;
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
/// Checks that the division rule holds for:
|
/// Checks that the division rule holds for:
|
||||||
///
|
///
|
||||||
|
@ -576,14 +333,14 @@ macro_rules! impl_integer_for_isize {
|
||||||
/// - `d`: denominator (divisor)
|
/// - `d`: denominator (divisor)
|
||||||
/// - `qr`: quotient and remainder
|
/// - `qr`: quotient and remainder
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn test_division_rule((n, d): ($T, $T), (q, r): ($T, $T)) {
|
fn test_division_rule((n,d): ($T, $T), (q,r): ($T, $T)) {
|
||||||
assert_eq!(d * q + r, n);
|
assert_eq!(d * q + r, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_div_rem() {
|
fn test_div_rem() {
|
||||||
fn test_nd_dr(nd: ($T, $T), qr: ($T, $T)) {
|
fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) {
|
||||||
let (n, d) = nd;
|
let (n,d) = nd;
|
||||||
let separate_div_rem = (n / d, n % d);
|
let separate_div_rem = (n / d, n % d);
|
||||||
let combined_div_rem = n.div_rem(&d);
|
let combined_div_rem = n.div_rem(&d);
|
||||||
|
|
||||||
|
@ -594,21 +351,21 @@ macro_rules! impl_integer_for_isize {
|
||||||
test_division_rule(nd, combined_div_rem);
|
test_division_rule(nd, combined_div_rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
test_nd_dr((8, 3), (2, 2));
|
test_nd_dr(( 8, 3), ( 2, 2));
|
||||||
test_nd_dr((8, -3), (-2, 2));
|
test_nd_dr(( 8, -3), (-2, 2));
|
||||||
test_nd_dr((-8, 3), (-2, -2));
|
test_nd_dr((-8, 3), (-2, -2));
|
||||||
test_nd_dr((-8, -3), (2, -2));
|
test_nd_dr((-8, -3), ( 2, -2));
|
||||||
|
|
||||||
test_nd_dr((1, 2), (0, 1));
|
test_nd_dr(( 1, 2), ( 0, 1));
|
||||||
test_nd_dr((1, -2), (0, 1));
|
test_nd_dr(( 1, -2), ( 0, 1));
|
||||||
test_nd_dr((-1, 2), (0, -1));
|
test_nd_dr((-1, 2), ( 0, -1));
|
||||||
test_nd_dr((-1, -2), (0, -1));
|
test_nd_dr((-1, -2), ( 0, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_div_mod_floor() {
|
fn test_div_mod_floor() {
|
||||||
fn test_nd_dm(nd: ($T, $T), dm: ($T, $T)) {
|
fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) {
|
||||||
let (n, d) = nd;
|
let (n,d) = nd;
|
||||||
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
|
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
|
||||||
let combined_div_mod_floor = n.div_mod_floor(&d);
|
let combined_div_mod_floor = n.div_mod_floor(&d);
|
||||||
|
|
||||||
|
@ -619,15 +376,15 @@ macro_rules! impl_integer_for_isize {
|
||||||
test_division_rule(nd, combined_div_mod_floor);
|
test_division_rule(nd, combined_div_mod_floor);
|
||||||
}
|
}
|
||||||
|
|
||||||
test_nd_dm((8, 3), (2, 2));
|
test_nd_dm(( 8, 3), ( 2, 2));
|
||||||
test_nd_dm((8, -3), (-3, -1));
|
test_nd_dm(( 8, -3), (-3, -1));
|
||||||
test_nd_dm((-8, 3), (-3, 1));
|
test_nd_dm((-8, 3), (-3, 1));
|
||||||
test_nd_dm((-8, -3), (2, -2));
|
test_nd_dm((-8, -3), ( 2, -2));
|
||||||
|
|
||||||
test_nd_dm((1, 2), (0, 1));
|
test_nd_dm(( 1, 2), ( 0, 1));
|
||||||
test_nd_dm((1, -2), (-1, -1));
|
test_nd_dm(( 1, -2), (-1, -1));
|
||||||
test_nd_dm((-1, 2), (-1, 1));
|
test_nd_dm((-1, 2), (-1, 1));
|
||||||
test_nd_dm((-1, -2), (0, -1));
|
test_nd_dm((-1, -2), ( 0, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -657,7 +414,7 @@ macro_rules! impl_integer_for_isize {
|
||||||
// for i8
|
// for i8
|
||||||
for i in -127..127 {
|
for i in -127..127 {
|
||||||
for j in -127..127 {
|
for j in -127..127 {
|
||||||
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
|
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,7 +422,7 @@ macro_rules! impl_integer_for_isize {
|
||||||
// FIXME: Use inclusive ranges for above loop when implemented
|
// FIXME: Use inclusive ranges for above loop when implemented
|
||||||
let i = 127;
|
let i = 127;
|
||||||
for j in -127..127 {
|
for j in -127..127 {
|
||||||
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
|
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
|
||||||
}
|
}
|
||||||
assert_eq!(127.gcd(&127), 127);
|
assert_eq!(127.gcd(&127), 127);
|
||||||
}
|
}
|
||||||
|
@ -716,49 +473,6 @@ macro_rules! impl_integer_for_isize {
|
||||||
assert_eq!((11 as $T).lcm(&5), 55 as $T);
|
assert_eq!((11 as $T).lcm(&5), 55 as $T);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_gcd_lcm() {
|
|
||||||
use core::iter::once;
|
|
||||||
for i in once(0)
|
|
||||||
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
|
|
||||||
.chain(once(-128))
|
|
||||||
{
|
|
||||||
for j in once(0)
|
|
||||||
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
|
|
||||||
.chain(once(-128))
|
|
||||||
{
|
|
||||||
assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_extended_gcd_lcm() {
|
|
||||||
use core::fmt::Debug;
|
|
||||||
use traits::NumAssign;
|
|
||||||
use ExtendedGcd;
|
|
||||||
|
|
||||||
fn check<A: Copy + Debug + Integer + NumAssign>(a: A, b: A) {
|
|
||||||
let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b);
|
|
||||||
assert_eq!(gcd, x * a + y * b);
|
|
||||||
}
|
|
||||||
|
|
||||||
use core::iter::once;
|
|
||||||
for i in once(0)
|
|
||||||
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
|
|
||||||
.chain(once(-128))
|
|
||||||
{
|
|
||||||
for j in once(0)
|
|
||||||
.chain((1..).take(127).flat_map(|a| once(a).chain(once(-a))))
|
|
||||||
.chain(once(-128))
|
|
||||||
{
|
|
||||||
check(i, j);
|
|
||||||
let (ExtendedGcd { gcd, .. }, lcm) = i.extended_gcd_lcm(&j);
|
|
||||||
assert_eq!((gcd, lcm), (i.gcd(&j), i.lcm(&j)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_even() {
|
fn test_even() {
|
||||||
assert_eq!((-4 as $T).is_even(), true);
|
assert_eq!((-4 as $T).is_even(), true);
|
||||||
|
@ -785,7 +499,7 @@ macro_rules! impl_integer_for_isize {
|
||||||
assert_eq!((4 as $T).is_odd(), false);
|
assert_eq!((4 as $T).is_odd(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_integer_for_isize!(i8, test_integer_i8);
|
impl_integer_for_isize!(i8, test_integer_i8);
|
||||||
|
@ -797,7 +511,7 @@ impl_integer_for_isize!(isize, test_integer_isize);
|
||||||
impl_integer_for_isize!(i128, test_integer_i128);
|
impl_integer_for_isize!(i128, test_integer_i128);
|
||||||
|
|
||||||
macro_rules! impl_integer_for_usize {
|
macro_rules! impl_integer_for_usize {
|
||||||
($T:ty, $test_mod:ident) => {
|
($T:ty, $test_mod:ident) => (
|
||||||
impl Integer for $T {
|
impl Integer for $T {
|
||||||
/// Unsigned integer division. Returns the same result as `div` (`/`).
|
/// Unsigned integer division. Returns the same result as `div` (`/`).
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -811,68 +525,34 @@ macro_rules! impl_integer_for_usize {
|
||||||
*self % *other
|
*self % *other
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div_ceil(&self, other: &Self) -> Self {
|
|
||||||
*self / *other + (0 != *self % *other) as Self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`
|
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`
|
||||||
#[inline]
|
#[inline]
|
||||||
fn gcd(&self, other: &Self) -> Self {
|
fn gcd(&self, other: &Self) -> Self {
|
||||||
// Use Stein's algorithm
|
// Use Stein's algorithm
|
||||||
let mut m = *self;
|
let mut m = *self;
|
||||||
let mut n = *other;
|
let mut n = *other;
|
||||||
if m == 0 || n == 0 {
|
if m == 0 || n == 0 { return m | n }
|
||||||
return m | n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find common factors of 2
|
// find common factors of 2
|
||||||
let shift = (m | n).trailing_zeros();
|
let shift = (m | n).trailing_zeros();
|
||||||
|
|
||||||
// divide n and m by 2 until odd
|
// divide n and m by 2 until odd
|
||||||
m >>= m.trailing_zeros();
|
// m inside loop
|
||||||
n >>= n.trailing_zeros();
|
n >>= n.trailing_zeros();
|
||||||
|
|
||||||
while m != n {
|
while m != 0 {
|
||||||
if m > n {
|
m >>= m.trailing_zeros();
|
||||||
m -= n;
|
if n > m { mem::swap(&mut n, &mut m) }
|
||||||
m >>= m.trailing_zeros();
|
m -= n;
|
||||||
} else {
|
|
||||||
n -= m;
|
|
||||||
n >>= n.trailing_zeros();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m << shift
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
n << shift
|
||||||
fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd<Self>, Self) {
|
|
||||||
let egcd = self.extended_gcd(other);
|
|
||||||
// should not have to recalculate abs
|
|
||||||
let lcm = if egcd.gcd.is_zero() {
|
|
||||||
Self::zero()
|
|
||||||
} else {
|
|
||||||
*self * (*other / egcd.gcd)
|
|
||||||
};
|
|
||||||
(egcd, lcm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
|
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn lcm(&self, other: &Self) -> Self {
|
fn lcm(&self, other: &Self) -> Self {
|
||||||
self.gcd_lcm(other).1
|
*self * (*other / self.gcd(other))
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the Greatest Common Divisor (GCD) and
|
|
||||||
/// Lowest Common Multiple (LCM) of the number and `other`.
|
|
||||||
#[inline]
|
|
||||||
fn gcd_lcm(&self, other: &Self) -> (Self, Self) {
|
|
||||||
if self.is_zero() && other.is_zero() {
|
|
||||||
return (Self::zero(), Self::zero());
|
|
||||||
}
|
|
||||||
let gcd = self.gcd(other);
|
|
||||||
let lcm = *self * (*other / gcd);
|
|
||||||
(gcd, lcm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated, use `is_multiple_of` instead.
|
/// Deprecated, use `is_multiple_of` instead.
|
||||||
|
@ -908,8 +588,8 @@ macro_rules! impl_integer_for_usize {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod $test_mod {
|
mod $test_mod {
|
||||||
use core::mem;
|
|
||||||
use Integer;
|
use Integer;
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_div_mod_floor() {
|
fn test_div_mod_floor() {
|
||||||
|
@ -945,7 +625,7 @@ macro_rules! impl_integer_for_usize {
|
||||||
|
|
||||||
for i in 0..255 {
|
for i in 0..255 {
|
||||||
for j in 0..255 {
|
for j in 0..255 {
|
||||||
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
|
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,7 +633,7 @@ macro_rules! impl_integer_for_usize {
|
||||||
// FIXME: Use inclusive ranges for above loop when implemented
|
// FIXME: Use inclusive ranges for above loop when implemented
|
||||||
let i = 255;
|
let i = 255;
|
||||||
for j in 0..255 {
|
for j in 0..255 {
|
||||||
assert_eq!(euclidean_gcd(i, j), i.gcd(&j));
|
assert_eq!(euclidean_gcd(i,j), i.gcd(&j));
|
||||||
}
|
}
|
||||||
assert_eq!(255.gcd(&255), 255);
|
assert_eq!(255.gcd(&255), 255);
|
||||||
}
|
}
|
||||||
|
@ -968,15 +648,6 @@ macro_rules! impl_integer_for_usize {
|
||||||
assert_eq!((15 as $T).lcm(&17), 255 as $T);
|
assert_eq!((15 as $T).lcm(&17), 255 as $T);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_gcd_lcm() {
|
|
||||||
for i in (0..).take(256) {
|
|
||||||
for j in (0..).take(256) {
|
|
||||||
assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_multiple_of() {
|
fn test_is_multiple_of() {
|
||||||
assert!((6 as $T).is_multiple_of(&(6 as $T)));
|
assert!((6 as $T).is_multiple_of(&(6 as $T)));
|
||||||
|
@ -1002,7 +673,7 @@ macro_rules! impl_integer_for_usize {
|
||||||
assert_eq!((4 as $T).is_odd(), false);
|
assert_eq!((4 as $T).is_odd(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_integer_for_usize!(u8, test_integer_u8);
|
impl_integer_for_usize!(u8, test_integer_u8);
|
||||||
|
@ -1021,8 +692,7 @@ pub struct IterBinomial<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IterBinomial<T>
|
impl<T> IterBinomial<T>
|
||||||
where
|
where T: Integer,
|
||||||
T: Integer,
|
|
||||||
{
|
{
|
||||||
/// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n.
|
/// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n.
|
||||||
///
|
///
|
||||||
|
@ -1044,16 +714,13 @@ where
|
||||||
/// For larger n, `T` should be a bigint type.
|
/// For larger n, `T` should be a bigint type.
|
||||||
pub fn new(n: T) -> IterBinomial<T> {
|
pub fn new(n: T) -> IterBinomial<T> {
|
||||||
IterBinomial {
|
IterBinomial {
|
||||||
k: T::zero(),
|
k: T::zero(), a: T::one(), n: n
|
||||||
a: T::one(),
|
|
||||||
n: n,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Iterator for IterBinomial<T>
|
impl<T> Iterator for IterBinomial<T>
|
||||||
where
|
where T: Integer + Clone
|
||||||
T: Integer + Clone,
|
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
|
@ -1065,7 +732,7 @@ where
|
||||||
multiply_and_divide(
|
multiply_and_divide(
|
||||||
self.a.clone(),
|
self.a.clone(),
|
||||||
self.n.clone() - self.k.clone() + T::one(),
|
self.n.clone() - self.k.clone() + T::one(),
|
||||||
self.k.clone(),
|
self.k.clone()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
T::one()
|
T::one()
|
||||||
|
@ -1081,7 +748,7 @@ where
|
||||||
fn multiply_and_divide<T: Integer + Clone>(r: T, a: T, b: T) -> T {
|
fn multiply_and_divide<T: Integer + Clone>(r: T, a: T, b: T) -> T {
|
||||||
// See http://blog.plover.com/math/choose-2.html for the idea.
|
// See http://blog.plover.com/math/choose-2.html for the idea.
|
||||||
let g = gcd(r.clone(), b.clone());
|
let g = gcd(r.clone(), b.clone());
|
||||||
r / g.clone() * (a / (b / g))
|
r/g.clone() * (a / (b/g))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the binomial coefficient.
|
/// Calculate the binomial coefficient.
|
||||||
|
@ -1125,8 +792,7 @@ pub fn binomial<T: Integer + Clone>(mut n: T, k: T) -> T {
|
||||||
|
|
||||||
/// Calculate the multinomial coefficient.
|
/// Calculate the multinomial coefficient.
|
||||||
pub fn multinomial<T: Integer + Clone>(k: &[T]) -> T
|
pub fn multinomial<T: Integer + Clone>(k: &[T]) -> T
|
||||||
where
|
where for<'a> T: Add<&'a T, Output = T>
|
||||||
for<'a> T: Add<&'a T, Output = T>,
|
|
||||||
{
|
{
|
||||||
let mut r = T::one();
|
let mut r = T::one();
|
||||||
let mut p = T::zero();
|
let mut p = T::zero();
|
||||||
|
@ -1140,20 +806,16 @@ where
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lcm_overflow() {
|
fn test_lcm_overflow() {
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($t:ty, $x:expr, $y:expr, $r:expr) => {{
|
($t:ty, $x:expr, $y:expr, $r:expr) => { {
|
||||||
let x: $t = $x;
|
let x: $t = $x;
|
||||||
let y: $t = $y;
|
let y: $t = $y;
|
||||||
let o = x.checked_mul(y);
|
let o = x.checked_mul(y);
|
||||||
assert!(
|
assert!(o.is_none(),
|
||||||
o.is_none(),
|
"sanity checking that {} input {} * {} overflows",
|
||||||
"sanity checking that {} input {} * {} overflows",
|
stringify!($t), x, y);
|
||||||
stringify!($t),
|
|
||||||
x,
|
|
||||||
y
|
|
||||||
);
|
|
||||||
assert_eq!(x.lcm(&y), $r);
|
assert_eq!(x.lcm(&y), $r);
|
||||||
assert_eq!(y.lcm(&x), $r);
|
assert_eq!(y.lcm(&x), $r);
|
||||||
}};
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Original bug (Issue #166)
|
// Original bug (Issue #166)
|
||||||
|
@ -1172,13 +834,13 @@ fn test_lcm_overflow() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter_binomial() {
|
fn test_iter_binomial() {
|
||||||
macro_rules! check_simple {
|
macro_rules! check_simple {
|
||||||
($t:ty) => {{
|
($t:ty) => { {
|
||||||
let n: $t = 3;
|
let n: $t = 3;
|
||||||
let expected = [1, 3, 3, 1];
|
let expected = [1, 3, 3, 1];
|
||||||
for (b, &e) in IterBinomial::new(n).zip(&expected) {
|
for (b, &e) in IterBinomial::new(n).zip(&expected) {
|
||||||
assert_eq!(b, e);
|
assert_eq!(b, e);
|
||||||
}
|
}
|
||||||
}};
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
check_simple!(u8);
|
check_simple!(u8);
|
||||||
|
@ -1191,14 +853,14 @@ fn test_iter_binomial() {
|
||||||
check_simple!(i64);
|
check_simple!(i64);
|
||||||
|
|
||||||
macro_rules! check_binomial {
|
macro_rules! check_binomial {
|
||||||
($t:ty, $n:expr) => {{
|
($t:ty, $n:expr) => { {
|
||||||
let n: $t = $n;
|
let n: $t = $n;
|
||||||
let mut k: $t = 0;
|
let mut k: $t = 0;
|
||||||
for b in IterBinomial::new(n) {
|
for b in IterBinomial::new(n) {
|
||||||
assert_eq!(b, binomial(n, k));
|
assert_eq!(b, binomial(n, k));
|
||||||
k += 1;
|
k += 1;
|
||||||
}
|
}
|
||||||
}};
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the largest n for which there is no overflow.
|
// Check the largest n for which there is no overflow.
|
||||||
|
@ -1215,7 +877,7 @@ fn test_iter_binomial() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_binomial() {
|
fn test_binomial() {
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($t:ty, $x:expr, $y:expr, $r:expr) => {{
|
($t:ty, $x:expr, $y:expr, $r:expr) => { {
|
||||||
let x: $t = $x;
|
let x: $t = $x;
|
||||||
let y: $t = $y;
|
let y: $t = $y;
|
||||||
let expected: $t = $r;
|
let expected: $t = $r;
|
||||||
|
@ -1223,7 +885,7 @@ fn test_binomial() {
|
||||||
if y <= x {
|
if y <= x {
|
||||||
assert_eq!(binomial(x, x - y), expected);
|
assert_eq!(binomial(x, x - y), expected);
|
||||||
}
|
}
|
||||||
}};
|
} }
|
||||||
}
|
}
|
||||||
check!(u8, 9, 4, 126);
|
check!(u8, 9, 4, 126);
|
||||||
check!(u8, 0, 0, 1);
|
check!(u8, 0, 0, 1);
|
||||||
|
@ -1271,12 +933,12 @@ fn test_binomial() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multinomial() {
|
fn test_multinomial() {
|
||||||
macro_rules! check_binomial {
|
macro_rules! check_binomial {
|
||||||
($t:ty, $k:expr) => {{
|
($t:ty, $k:expr) => { {
|
||||||
let n: $t = $k.iter().fold(0, |acc, &x| acc + x);
|
let n: $t = $k.iter().fold(0, |acc, &x| acc + x);
|
||||||
let k: &[$t] = $k;
|
let k: &[$t] = $k;
|
||||||
assert_eq!(k.len(), 2);
|
assert_eq!(k.len(), 2);
|
||||||
assert_eq!(multinomial(k), binomial(n, k[0]));
|
assert_eq!(multinomial(k), binomial(n, k[0]));
|
||||||
}};
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
check_binomial!(u8, &[4, 5]);
|
check_binomial!(u8, &[4, 5]);
|
||||||
|
@ -1306,11 +968,11 @@ fn test_multinomial() {
|
||||||
check_binomial!(i64, &[4, 10]);
|
check_binomial!(i64, &[4, 10]);
|
||||||
|
|
||||||
macro_rules! check_multinomial {
|
macro_rules! check_multinomial {
|
||||||
($t:ty, $k:expr, $r:expr) => {{
|
($t:ty, $k:expr, $r:expr) => { {
|
||||||
let k: &[$t] = $k;
|
let k: &[$t] = $k;
|
||||||
let expected: $t = $r;
|
let expected: $t = $r;
|
||||||
assert_eq!(multinomial(k), expected);
|
assert_eq!(multinomial(k), expected);
|
||||||
}};
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
check_multinomial!(u8, &[2, 1, 2], 30);
|
check_multinomial!(u8, &[2, 1, 2], 30);
|
||||||
|
|
|
@ -202,181 +202,170 @@ fn log2<T: PrimInt>(x: T) -> u32 {
|
||||||
macro_rules! unsigned_roots {
|
macro_rules! unsigned_roots {
|
||||||
($T:ident) => {
|
($T:ident) => {
|
||||||
impl Roots for $T {
|
impl Roots for $T {
|
||||||
#[inline]
|
|
||||||
fn nth_root(&self, n: u32) -> Self {
|
fn nth_root(&self, n: u32) -> Self {
|
||||||
fn go(a: $T, n: u32) -> $T {
|
// Specialize small roots
|
||||||
// Specialize small roots
|
match n {
|
||||||
match n {
|
0 => panic!("can't find a root of degree 0!"),
|
||||||
0 => panic!("can't find a root of degree 0!"),
|
1 => return *self,
|
||||||
1 => return a,
|
2 => return self.sqrt(),
|
||||||
2 => return a.sqrt(),
|
3 => return self.cbrt(),
|
||||||
3 => return a.cbrt(),
|
_ => (),
|
||||||
_ => (),
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// The root of values less than 2ⁿ can only be 0 or 1.
|
// The root of values less than 2ⁿ can only be 0 or 1.
|
||||||
if bits::<$T>() <= n || a < (1 << n) {
|
if bits::<$T>() <= n || *self < (1 << n) {
|
||||||
return (a > 0) as $T;
|
return (*self > 0) as $T;
|
||||||
}
|
}
|
||||||
|
|
||||||
if bits::<$T>() > 64 {
|
if bits::<$T>() > 64 {
|
||||||
// 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
|
// 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
|
||||||
return if a <= core::u64::MAX as $T {
|
return if *self <= core::u64::MAX as $T {
|
||||||
(a as u64).nth_root(n) as $T
|
(*self as u64).nth_root(n) as $T
|
||||||
} else {
|
} else {
|
||||||
let lo = (a >> n).nth_root(n) << 1;
|
let lo = (self >> n).nth_root(n) << 1;
|
||||||
let hi = lo + 1;
|
let hi = lo + 1;
|
||||||
// 128-bit `checked_mul` also involves division, but we can't always
|
// 128-bit `checked_mul` also involves division, but we can't always
|
||||||
// compute `hiⁿ` without risking overflow. Try to avoid it though...
|
// compute `hiⁿ` without risking overflow. Try to avoid it though...
|
||||||
if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() {
|
if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() {
|
||||||
match checked_pow(hi, n as usize) {
|
match checked_pow(hi, n as usize) {
|
||||||
Some(x) if x <= a => hi,
|
Some(x) if x <= *self => hi,
|
||||||
_ => lo,
|
_ => lo,
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if hi.pow(n) <= a {
|
|
||||||
hi
|
|
||||||
} else {
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[inline]
|
|
||||||
fn guess(x: $T, n: u32) -> $T {
|
|
||||||
// for smaller inputs, `f64` doesn't justify its cost.
|
|
||||||
if bits::<$T>() <= 32 || x <= core::u32::MAX as $T {
|
|
||||||
1 << ((log2(x) + n - 1) / n)
|
|
||||||
} else {
|
} else {
|
||||||
((x as f64).ln() / f64::from(n)).exp() as $T
|
if hi.pow(n) <= *self {
|
||||||
|
hi
|
||||||
|
} else {
|
||||||
|
lo
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
#[inline]
|
|
||||||
fn guess(x: $T, n: u32) -> $T {
|
|
||||||
1 << ((log2(x) + n - 1) / n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Nth_root_algorithm
|
|
||||||
let n1 = n - 1;
|
|
||||||
let next = |x: $T| {
|
|
||||||
let y = match checked_pow(x, n1 as usize) {
|
|
||||||
Some(ax) => a / ax,
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
(y + x * n1 as $T) / n as $T
|
|
||||||
};
|
};
|
||||||
fixpoint(guess(a, n), next)
|
|
||||||
}
|
}
|
||||||
go(*self, n)
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[inline]
|
||||||
|
fn guess(x: $T, n: u32) -> $T {
|
||||||
|
// for smaller inputs, `f64` doesn't justify its cost.
|
||||||
|
if bits::<$T>() <= 32 || x <= core::u32::MAX as $T {
|
||||||
|
1 << ((log2(x) + n - 1) / n)
|
||||||
|
} else {
|
||||||
|
((x as f64).ln() / f64::from(n)).exp() as $T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
#[inline]
|
||||||
|
fn guess(x: $T, n: u32) -> $T {
|
||||||
|
1 << ((log2(x) + n - 1) / n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Nth_root_algorithm
|
||||||
|
let n1 = n - 1;
|
||||||
|
let next = |x: $T| {
|
||||||
|
let y = match checked_pow(x, n1 as usize) {
|
||||||
|
Some(ax) => self / ax,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
(y + x * n1 as $T) / n as $T
|
||||||
|
};
|
||||||
|
fixpoint(guess(*self, n), next)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn sqrt(&self) -> Self {
|
fn sqrt(&self) -> Self {
|
||||||
fn go(a: $T) -> $T {
|
if bits::<$T>() > 64 {
|
||||||
if bits::<$T>() > 64 {
|
// 128-bit division is slow, so do a bitwise `sqrt` until it's small enough.
|
||||||
// 128-bit division is slow, so do a bitwise `sqrt` until it's small enough.
|
// https://en.wikipedia.org/wiki/Integer_square_root#Using_bitwise_operations
|
||||||
return if a <= core::u64::MAX as $T {
|
return if *self <= core::u64::MAX as $T {
|
||||||
(a as u64).sqrt() as $T
|
(*self as u64).sqrt() as $T
|
||||||
|
} else {
|
||||||
|
let lo = (self >> 2u32).sqrt() << 1;
|
||||||
|
let hi = lo + 1;
|
||||||
|
if hi * hi <= *self {
|
||||||
|
hi
|
||||||
} else {
|
} else {
|
||||||
let lo = (a >> 2u32).sqrt() << 1;
|
lo
|
||||||
let hi = lo + 1;
|
}
|
||||||
if hi * hi <= a {
|
};
|
||||||
hi
|
|
||||||
} else {
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if a < 4 {
|
|
||||||
return (a > 0) as $T;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[inline]
|
|
||||||
fn guess(x: $T) -> $T {
|
|
||||||
(x as f64).sqrt() as $T
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
#[inline]
|
|
||||||
fn guess(x: $T) -> $T {
|
|
||||||
1 << ((log2(x) + 1) / 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
|
|
||||||
let next = |x: $T| (a / x + x) >> 1;
|
|
||||||
fixpoint(guess(a), next)
|
|
||||||
}
|
}
|
||||||
go(*self)
|
|
||||||
|
if *self < 4 {
|
||||||
|
return (*self > 0) as Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[inline]
|
||||||
|
fn guess(x: $T) -> $T {
|
||||||
|
(x as f64).sqrt() as $T
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
#[inline]
|
||||||
|
fn guess(x: $T) -> $T {
|
||||||
|
1 << ((log2(x) + 1) / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
|
||||||
|
let next = |x: $T| (self / x + x) >> 1;
|
||||||
|
fixpoint(guess(*self), next)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn cbrt(&self) -> Self {
|
fn cbrt(&self) -> Self {
|
||||||
fn go(a: $T) -> $T {
|
if bits::<$T>() > 64 {
|
||||||
if bits::<$T>() > 64 {
|
// 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
|
||||||
// 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
|
return if *self <= core::u64::MAX as $T {
|
||||||
return if a <= core::u64::MAX as $T {
|
(*self as u64).cbrt() as $T
|
||||||
(a as u64).cbrt() as $T
|
} else {
|
||||||
|
let lo = (self >> 3u32).cbrt() << 1;
|
||||||
|
let hi = lo + 1;
|
||||||
|
if hi * hi * hi <= *self {
|
||||||
|
hi
|
||||||
} else {
|
} else {
|
||||||
let lo = (a >> 3u32).cbrt() << 1;
|
lo
|
||||||
let hi = lo + 1;
|
|
||||||
if hi * hi * hi <= a {
|
|
||||||
hi
|
|
||||||
} else {
|
|
||||||
lo
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if bits::<$T>() <= 32 {
|
|
||||||
// Implementation based on Hacker's Delight `icbrt2`
|
|
||||||
let mut x = a;
|
|
||||||
let mut y2 = 0;
|
|
||||||
let mut y = 0;
|
|
||||||
let smax = bits::<$T>() / 3;
|
|
||||||
for s in (0..smax + 1).rev() {
|
|
||||||
let s = s * 3;
|
|
||||||
y2 *= 4;
|
|
||||||
y *= 2;
|
|
||||||
let b = 3 * (y2 + y) + 1;
|
|
||||||
if x >> s >= b {
|
|
||||||
x -= b << s;
|
|
||||||
y2 += 2 * y + 1;
|
|
||||||
y += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return y;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if a < 8 {
|
|
||||||
return (a > 0) as $T;
|
|
||||||
}
|
|
||||||
if a <= core::u32::MAX as $T {
|
|
||||||
return (a as u32).cbrt() as $T;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[inline]
|
|
||||||
fn guess(x: $T) -> $T {
|
|
||||||
(x as f64).cbrt() as $T
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
#[inline]
|
|
||||||
fn guess(x: $T) -> $T {
|
|
||||||
1 << ((log2(x) + 2) / 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
|
|
||||||
let next = |x: $T| (a / (x * x) + x * 2) / 3;
|
|
||||||
fixpoint(guess(a), next)
|
|
||||||
}
|
}
|
||||||
go(*self)
|
|
||||||
|
if bits::<$T>() <= 32 {
|
||||||
|
// Implementation based on Hacker's Delight `icbrt2`
|
||||||
|
let mut x = *self;
|
||||||
|
let mut y2 = 0;
|
||||||
|
let mut y = 0;
|
||||||
|
let smax = bits::<$T>() / 3;
|
||||||
|
for s in (0..smax + 1).rev() {
|
||||||
|
let s = s * 3;
|
||||||
|
y2 *= 4;
|
||||||
|
y *= 2;
|
||||||
|
let b = 3 * (y2 + y) + 1;
|
||||||
|
if x >> s >= b {
|
||||||
|
x -= b << s;
|
||||||
|
y2 += 2 * y + 1;
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if *self < 8 {
|
||||||
|
return (*self > 0) as Self;
|
||||||
|
}
|
||||||
|
if *self <= core::u32::MAX as $T {
|
||||||
|
return (*self as u32).cbrt() as $T;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[inline]
|
||||||
|
fn guess(x: $T) -> $T {
|
||||||
|
(x as f64).cbrt() as $T
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
#[inline]
|
||||||
|
fn guess(x: $T) -> $T {
|
||||||
|
1 << ((log2(x) + 2) / 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
|
||||||
|
let next = |x: $T| (self / (x * x) + x * 2) / 3;
|
||||||
|
fixpoint(guess(*self), next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
extern crate num_integer;
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
macro_rules! test_average {
|
|
||||||
($I:ident, $U:ident) => {
|
|
||||||
mod $I {
|
|
||||||
mod ceil {
|
|
||||||
use num_integer::Average;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn same_sign() {
|
|
||||||
assert_eq!((14 as $I).average_ceil(&16), 15 as $I);
|
|
||||||
assert_eq!((14 as $I).average_ceil(&17), 16 as $I);
|
|
||||||
|
|
||||||
let max = $crate::std::$I::MAX;
|
|
||||||
assert_eq!((max - 3).average_ceil(&(max - 1)), max - 2);
|
|
||||||
assert_eq!((max - 3).average_ceil(&(max - 2)), max - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn different_sign() {
|
|
||||||
assert_eq!((14 as $I).average_ceil(&-4), 5 as $I);
|
|
||||||
assert_eq!((14 as $I).average_ceil(&-5), 5 as $I);
|
|
||||||
|
|
||||||
let min = $crate::std::$I::MIN;
|
|
||||||
let max = $crate::std::$I::MAX;
|
|
||||||
assert_eq!(min.average_ceil(&max), 0 as $I);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod floor {
|
|
||||||
use num_integer::Average;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn same_sign() {
|
|
||||||
assert_eq!((14 as $I).average_floor(&16), 15 as $I);
|
|
||||||
assert_eq!((14 as $I).average_floor(&17), 15 as $I);
|
|
||||||
|
|
||||||
let max = $crate::std::$I::MAX;
|
|
||||||
assert_eq!((max - 3).average_floor(&(max - 1)), max - 2);
|
|
||||||
assert_eq!((max - 3).average_floor(&(max - 2)), max - 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn different_sign() {
|
|
||||||
assert_eq!((14 as $I).average_floor(&-4), 5 as $I);
|
|
||||||
assert_eq!((14 as $I).average_floor(&-5), 4 as $I);
|
|
||||||
|
|
||||||
let min = $crate::std::$I::MIN;
|
|
||||||
let max = $crate::std::$I::MAX;
|
|
||||||
assert_eq!(min.average_floor(&max), -1 as $I);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod $U {
|
|
||||||
mod ceil {
|
|
||||||
use num_integer::Average;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn bounded() {
|
|
||||||
assert_eq!((14 as $U).average_ceil(&16), 15 as $U);
|
|
||||||
assert_eq!((14 as $U).average_ceil(&17), 16 as $U);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn overflow() {
|
|
||||||
let max = $crate::std::$U::MAX;
|
|
||||||
assert_eq!((max - 3).average_ceil(&(max - 1)), max - 2);
|
|
||||||
assert_eq!((max - 3).average_ceil(&(max - 2)), max - 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod floor {
|
|
||||||
use num_integer::Average;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn bounded() {
|
|
||||||
assert_eq!((14 as $U).average_floor(&16), 15 as $U);
|
|
||||||
assert_eq!((14 as $U).average_floor(&17), 15 as $U);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn overflow() {
|
|
||||||
let max = $crate::std::$U::MAX;
|
|
||||||
assert_eq!((max - 3).average_floor(&(max - 1)), max - 2);
|
|
||||||
assert_eq!((max - 3).average_floor(&(max - 2)), max - 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
test_average!(i8, u8);
|
|
||||||
test_average!(i16, u16);
|
|
||||||
test_average!(i32, u32);
|
|
||||||
test_average!(i64, u64);
|
|
||||||
#[cfg(has_i128)]
|
|
||||||
test_average!(i128, u128);
|
|
||||||
test_average!(isize, usize);
|
|
|
@ -10,7 +10,11 @@ use std::mem;
|
||||||
|
|
||||||
trait TestInteger: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static {}
|
trait TestInteger: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static {}
|
||||||
|
|
||||||
impl<T> TestInteger for T where T: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static {}
|
impl<T> TestInteger for T
|
||||||
|
where
|
||||||
|
T: Roots + PrimInt + Debug + AsPrimitive<f64> + 'static,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Check that each root is correct
|
/// Check that each root is correct
|
||||||
///
|
///
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"a4d2d0bbd05ab5a51970062722652bacf4d4e30cff0fcca1fd923939fec2b274","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"57d78cdbd4b4adfac543cc95afb88d34b2415bf074eb1081631210f84cca54f3","RELEASES.md":"f947644ec5b4a6d5e25497dfa3dbdd0d14983b9593e41dad7e12d1218559b4fa","build.rs":"b4b2d0df90ca7570a339ca4d84a72e4ef00d9dced8927350424e666790c752d7","src/lib.rs":"7baa9cfcc89c27a6d16a4be0fe53c0488f3c1c424812219fc47be0918a197d9b"},"package":"7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"}
|
{"files":{"Cargo.toml":"c13da0848b07a604569216fdb430f87d43b83252055ab1f6e237fc4020897b2b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"f3be0ace34d626865f124c492483c30cadc3362c17aabefed45fa2686c67a070","RELEASES.md":"1031b964f47fd9c33e0249d1343b3292c830d7e2e6c8d88931dcbc25a20a0337","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"2aa9e89e4af81ed9da86bdcf7cdabe512287c877248783b69eed1eccf09ad6bb","ci/test_full.sh":"22ab0d413456c350a8a0e62e3614da628dad06eb4c923b4d162aef4cb47b9dd2","src/lib.rs":"e6b0f870ab6e741f15293b76b11e5bc01193aa8e08c13f5f67e2f85c3808636f"},"package":"af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"}
|
|
@ -3,7 +3,7 @@
|
||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
# to registry (e.g., crates.io) dependencies
|
# to registry (e.g. crates.io) dependencies
|
||||||
#
|
#
|
||||||
# If you believe there's an error in this file please file an
|
# If you believe there's an error in this file please file an
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
# issue against the rust-lang/cargo repository. If you're
|
||||||
|
@ -12,10 +12,9 @@
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "num-iter"
|
name = "num-iter"
|
||||||
version = "0.1.41"
|
version = "0.1.37"
|
||||||
authors = ["The Rust Project Developers"]
|
authors = ["The Rust Project Developers"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
|
||||||
description = "External iterators for generic mathematics"
|
description = "External iterators for generic mathematics"
|
||||||
homepage = "https://github.com/rust-num/num-iter"
|
homepage = "https://github.com/rust-num/num-iter"
|
||||||
documentation = "https://docs.rs/num-iter"
|
documentation = "https://docs.rs/num-iter"
|
||||||
|
@ -27,14 +26,12 @@ repository = "https://github.com/rust-num/num-iter"
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["std"]
|
features = ["std"]
|
||||||
[dependencies.num-integer]
|
[dependencies.num-integer]
|
||||||
version = "0.1.42"
|
version = "0.1.38"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.num-traits]
|
[dependencies.num-traits]
|
||||||
version = "0.2.11"
|
version = "0.2.4"
|
||||||
default-features = false
|
default-features = false
|
||||||
[build-dependencies.autocfg]
|
|
||||||
version = "1"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
[![crate](https://img.shields.io/crates/v/num-iter.svg)](https://crates.io/crates/num-iter)
|
[![crate](https://img.shields.io/crates/v/num-iter.svg)](https://crates.io/crates/num-iter)
|
||||||
[![documentation](https://docs.rs/num-iter/badge.svg)](https://docs.rs/num-iter)
|
[![documentation](https://docs.rs/num-iter/badge.svg)](https://docs.rs/num-iter)
|
||||||
[![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
|
![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
|
||||||
[![build status](https://github.com/rust-num/num-iter/workflows/master/badge.svg)](https://github.com/rust-num/num-iter/actions)
|
[![Travis status](https://travis-ci.org/rust-num/num-iter.svg?branch=master)](https://travis-ci.org/rust-num/num-iter)
|
||||||
|
|
||||||
Generic `Range` iterators for Rust.
|
Generic `Range` iterators for Rust.
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче