зеркало из 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"]
|
||||
git = "https://github.com/mozilla/mp4parse-rust"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "6ebb531e1b0381c7a5980279637ef6ae7a3b6bc2"
|
||||
rev = "63325444ae3388599f2f222775eebdde4c2f9f30"
|
||||
|
||||
[source."https://github.com/mozilla/application-services"]
|
||||
git = "https://github.com/mozilla/application-services"
|
||||
|
|
|
@ -2344,7 +2344,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"byteorder",
|
||||
"num-iter",
|
||||
"num-rational 0.2.1",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png",
|
||||
]
|
||||
|
@ -3121,7 +3121,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "mp4parse"
|
||||
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 = [
|
||||
"bitreader",
|
||||
"byteorder",
|
||||
|
@ -3138,12 +3138,12 @@ version = "0.1.0"
|
|||
[[package]]
|
||||
name = "mp4parse_capi"
|
||||
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 = [
|
||||
"byteorder",
|
||||
"log",
|
||||
"mp4parse",
|
||||
"num",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3364,20 +3364,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.3"
|
||||
|
@ -3389,26 +3375,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "num-derive"
|
||||
version = "0.3.0"
|
||||
|
@ -3422,21 +3388,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
checksum = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.41"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
|
||||
checksum = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
@ -3451,25 +3415,13 @@ dependencies = [
|
|||
"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]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
checksum = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"autocfg 0.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3767,7 +3719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c20593a99fe08068cbe2b59001527f36021d6ad53ac5f2d8793fcf2fe94015a0"
|
||||
dependencies = [
|
||||
"libloading 0.5.2",
|
||||
"num-bigint 0.2.3",
|
||||
"num-bigint",
|
||||
]
|
||||
|
||||
[[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(())
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, additional: usize) -> Result<()> {
|
||||
fn reserve(&mut self, additional: usize) -> Result<()> {
|
||||
#[cfg(feature = "mp4parse_fallible")]
|
||||
{
|
||||
let available = self
|
||||
|
|
|
@ -58,7 +58,7 @@ impl ToU64 for 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.
|
||||
pub trait ToUsize {
|
||||
trait ToUsize {
|
||||
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.
|
||||
/// Members are time in scale units and the track id.
|
||||
#[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>
|
||||
where
|
||||
T: num_traits::CheckedAdd,
|
||||
T: Num,
|
||||
{
|
||||
type Output = Option<Self>;
|
||||
type Output = TrackScaledTime<T>;
|
||||
|
||||
fn add(self, other: TrackScaledTime<T>) -> Self::Output {
|
||||
self.0.checked_add(&other.0).map(|sum| Self(sum, self.1))
|
||||
fn add(self, other: TrackScaledTime<T>) -> TrackScaledTime<T> {
|
||||
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.
|
||||
/// See ISO 14496-12:2015 § 4.3
|
||||
fn read_ftyp<T: Read>(src: &mut BMFFBox<T>) -> Result<FileTypeBox> {
|
||||
let major = 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?
|
||||
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 {
|
||||
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.
|
||||
/// See ISO 14496-12:2015 § 8.6.6
|
||||
fn read_elst<T: Read>(src: &mut BMFFBox<T>) -> Result<EditListBox> {
|
||||
let (version, _) = read_fullbox_extra(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 {
|
||||
let (segment_duration, media_time) = match version {
|
||||
1 => {
|
||||
|
@ -2135,11 +2133,10 @@ fn read_mdhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MediaHeaderBox> {
|
|||
}
|
||||
|
||||
/// Parse a stco box.
|
||||
/// See ISO 14496-12:2015 § 8.7.5
|
||||
fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
||||
let (_, _) = read_fullbox_extra(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 {
|
||||
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.
|
||||
/// See ISO 14496-12:2015 § 8.7.5
|
||||
fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
||||
let (_, _) = read_fullbox_extra(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 {
|
||||
offsets.push(be_u64(src)?)?;
|
||||
}
|
||||
|
@ -2167,11 +2163,10 @@ fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
|
|||
}
|
||||
|
||||
/// Parse a stss box.
|
||||
/// See ISO 14496-12:2015 § 8.6.2
|
||||
fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
|
||||
let (_, _) = read_fullbox_extra(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 {
|
||||
samples.push(be_u32(src)?)?;
|
||||
}
|
||||
|
@ -2183,11 +2178,10 @@ fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
|
|||
}
|
||||
|
||||
/// Parse a stsc box.
|
||||
/// See ISO 14496-12:2015 § 8.7.4
|
||||
fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
|
||||
let (_, _) = read_fullbox_extra(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 {
|
||||
let first_chunk = be_u32(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 })
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
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()
|
||||
< counts
|
||||
.checked_mul(8)
|
||||
.expect("counts -> bytes overflow")
|
||||
.into()
|
||||
{
|
||||
if src.bytes_left() < counts.checked_mul(8).expect("counts -> bytes overflow") {
|
||||
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 {
|
||||
let (sample_count, time_offset) = match version {
|
||||
// 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.
|
||||
/// See ISO 14496-12:2015 § 8.7.3.2
|
||||
fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
|
||||
let (_, _) = read_fullbox_extra(src)?;
|
||||
let sample_size = be_u32(src)?;
|
||||
let sample_count = be_u32_with_limit(src)?;
|
||||
let mut sample_sizes = TryVec::new();
|
||||
if sample_size == 0 {
|
||||
sample_sizes.reserve(sample_count.to_usize())?;
|
||||
for _ in 0..sample_count {
|
||||
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.
|
||||
/// See ISO 14496-12:2015 § 8.6.1.2
|
||||
fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
|
||||
let (_, _) = read_fullbox_extra(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 {
|
||||
let sample_count = be_u32_with_limit(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 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.
|
||||
// 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.audio_sample_rate = Some(sample_frequency_value);
|
||||
esds.audio_channel_count = Some(channel_counts);
|
||||
if !esds.decoder_specific_data.is_empty() {
|
||||
return Err(Error::InvalidData(
|
||||
"There can be only one DecSpecificInfoTag descriptor",
|
||||
));
|
||||
}
|
||||
assert!(esds.decoder_specific_data.is_empty());
|
||||
esds.decoder_specific_data.extend_from_slice(data)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -2715,7 +2695,6 @@ fn read_es_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// See ISO 14496-14:2010 § 6.7.2
|
||||
fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
|
||||
let (_, _) = read_fullbox_extra(src)?;
|
||||
|
||||
|
@ -2730,7 +2709,6 @@ fn read_esds<T: Read>(src: &mut BMFFBox<T>) -> Result<ES_Descriptor> {
|
|||
}
|
||||
|
||||
/// 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> {
|
||||
let (version, flags) = read_fullbox_extra(src)?;
|
||||
if version != 0 {
|
||||
|
@ -3157,7 +3135,6 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleEntry>
|
|||
|
||||
/// Parse a stsd box.
|
||||
/// 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> {
|
||||
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"
|
||||
log = "0.4"
|
||||
mp4parse = {version = "0.11.2", path = "../mp4parse"}
|
||||
num = "0.3.0"
|
||||
num-traits = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.7.1"
|
||||
|
|
|
@ -62,7 +62,9 @@ fn dump_file(filename: &str) {
|
|||
for i in 0..counts {
|
||||
let mut track_info = Mp4parseTrackInfo {
|
||||
track_type: Mp4parseTrackType::Audio,
|
||||
..Default::default()
|
||||
track_id: 0,
|
||||
duration: 0,
|
||||
media_time: 0,
|
||||
};
|
||||
match mp4parse_get_track_info(parser, i, &mut track_info) {
|
||||
Mp4parseStatus::Ok => {
|
||||
|
|
|
@ -37,17 +37,11 @@
|
|||
|
||||
extern crate byteorder;
|
||||
extern crate mp4parse;
|
||||
extern crate num;
|
||||
extern crate num_traits;
|
||||
|
||||
use byteorder::WriteBytesExt;
|
||||
use num::{CheckedAdd, CheckedSub};
|
||||
use num::{PrimInt, Zero};
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use num_traits::{PrimInt, Zero};
|
||||
use std::io::Read;
|
||||
use std::ops::Neg;
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
// Symbols we need from our rust api.
|
||||
use mp4parse::read_avif;
|
||||
|
@ -61,7 +55,6 @@ use mp4parse::MediaContext;
|
|||
use mp4parse::MediaScaledTime;
|
||||
use mp4parse::MediaTimeScale;
|
||||
use mp4parse::SampleEntry;
|
||||
use mp4parse::ToUsize;
|
||||
use mp4parse::Track;
|
||||
use mp4parse::TrackScaledTime;
|
||||
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)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Mp4parseTrackInfo {
|
||||
pub track_type: Mp4parseTrackType,
|
||||
pub track_id: u32,
|
||||
pub duration: u64,
|
||||
pub media_time: CheckedInteger<i64>, // wants to be u64? understand how elst adjustment works
|
||||
// TODO(kinetik): include crypto guff
|
||||
// If this changes to u64, we can get rid of the strange
|
||||
// impl Sub for CheckedInteger<u64>
|
||||
pub media_time: i64, // wants to be u64? understand how elst adjustment works
|
||||
// TODO(kinetik): include crypto guff
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, PartialEq)]
|
||||
pub struct Mp4parseIndice {
|
||||
/// 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
|
||||
/// equivalent to `start_offset` + the length in bytes of the indexed
|
||||
/// sample. Typically this will be the `start_offset` of the next sample
|
||||
/// in the file.
|
||||
pub end_offset: CheckedInteger<u64>,
|
||||
pub end_offset: u64,
|
||||
/// The time in microseconds when the indexed sample should be displayed.
|
||||
/// 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
|
||||
/// displayed. Typically this would be the `start_composition` time of the
|
||||
/// 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.
|
||||
/// 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
|
||||
/// somewhat codec specific, but essentially amounts to if the sample is a
|
||||
/// key frame.
|
||||
|
@ -704,7 +599,7 @@ where
|
|||
|
||||
let integer = 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
|
||||
.checked_mul(&s)
|
||||
.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];
|
||||
|
||||
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)
|
||||
}) {
|
||||
Some(time) => time.into(),
|
||||
Some(time) => time as i64,
|
||||
None => return Mp4parseStatus::Invalid,
|
||||
};
|
||||
let empty_duration: CheckedInteger<_> =
|
||||
match track.empty_duration.map_or(Some(0), |empty_duration| {
|
||||
media_time_to_us(empty_duration, context_timescale)
|
||||
}) {
|
||||
Some(time) => time.into(),
|
||||
None => return Mp4parseStatus::Invalid,
|
||||
};
|
||||
info.media_time = match media_time - empty_duration {
|
||||
Some(difference) => difference,
|
||||
let empty_duration = match track.empty_duration.map_or(Some(0), |empty_duration| {
|
||||
media_time_to_us(empty_duration, context_timescale)
|
||||
}) {
|
||||
Some(time) => time as i64,
|
||||
None => return Mp4parseStatus::Invalid,
|
||||
};
|
||||
info.media_time = media_time - empty_duration;
|
||||
|
||||
if let Some(track_duration) = track.duration {
|
||||
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) {
|
||||
(&Some(t), &Some(s)) => track_time_to_us(t, s)
|
||||
.and_then(|v| i64::try_from(v).ok())
|
||||
.map(Into::into),
|
||||
(&Some(t), &Some(s)) => track_time_to_us(t, s).map(|v| v as i64),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let empty_duration: Option<CheckedInteger<_>> =
|
||||
match (&track.empty_duration, &context.timescale) {
|
||||
(&Some(e), &Some(s)) => media_time_to_us(e, s)
|
||||
.and_then(|v| i64::try_from(v).ok())
|
||||
.map(Into::into),
|
||||
_ => None,
|
||||
};
|
||||
let empty_duration = match (&track.empty_duration, &context.timescale) {
|
||||
(&Some(e), &Some(s)) => media_time_to_us(e, s).map(|v| v as i64),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Find the track start offset time from 'elst'.
|
||||
// 'media_time' maps start time onward, 'empty_duration' adds time offset
|
||||
// before first frame is displayed.
|
||||
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,
|
||||
(None, Some(m)) => m,
|
||||
_ => 0.into(),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
if let Some(v) = create_sample_table(track, offset_time) {
|
||||
|
@ -1292,7 +1178,6 @@ struct TimeOffsetIterator<'a> {
|
|||
impl<'a> Iterator for TimeOffsetIterator<'a> {
|
||||
type Item = i64;
|
||||
|
||||
#[allow(clippy::reversed_empty_ranges)]
|
||||
fn next(&mut self) -> Option<i64> {
|
||||
let has_sample = self.cur_sample_range.next().or_else(|| {
|
||||
// At end of current TimeOffset, find the next TimeOffset.
|
||||
|
@ -1349,7 +1234,6 @@ struct TimeToSampleIterator<'a> {
|
|||
impl<'a> Iterator for TimeToSampleIterator<'a> {
|
||||
type Item = u32;
|
||||
|
||||
#[allow(clippy::reversed_empty_ranges)]
|
||||
fn next(&mut self) -> Option<u32> {
|
||||
let has_sample = self.cur_sample_count.next().or_else(|| {
|
||||
self.cur_sample_count = match self.stts_iter.next() {
|
||||
|
@ -1387,21 +1271,6 @@ impl<'a> TimeToSampleIterator<'a> {
|
|||
// For example:
|
||||
// (1, 5), (5, 10), (9, 2) => (1, 5), (2, 5), (3, 5), (4, 5), (5, 10), (6, 10),
|
||||
// (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> {
|
||||
chunks: std::ops::Range<u32>,
|
||||
sample_count: u32,
|
||||
|
@ -1416,12 +1285,7 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
|
|||
let has_chunk = self.chunks.next().or_else(|| {
|
||||
self.chunks = self.locate();
|
||||
self.remain_chunk_count
|
||||
.checked_sub(
|
||||
self.chunks
|
||||
.len()
|
||||
.try_into()
|
||||
.expect("len() of a Range<u32> must fit in u32"),
|
||||
)
|
||||
.checked_sub(self.chunks.len() as u32)
|
||||
.and_then(|res| {
|
||||
self.remain_chunk_count = res;
|
||||
self.chunks.next()
|
||||
|
@ -1433,7 +1297,6 @@ impl<'a> Iterator for SampleToChunkIterator<'a> {
|
|||
}
|
||||
|
||||
impl<'a> SampleToChunkIterator<'a> {
|
||||
#[allow(clippy::reversed_empty_ranges)]
|
||||
fn locate(&mut self) -> std::ops::Range<u32> {
|
||||
loop {
|
||||
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: CheckedInteger<i64>,
|
||||
) -> Option<TryVec<Mp4parseIndice>> {
|
||||
fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<TryVec<Mp4parseIndice>> {
|
||||
let timescale = match track.timescale {
|
||||
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
|
||||
_ => return None,
|
||||
|
@ -1482,32 +1341,31 @@ fn create_sample_table(
|
|||
_ => false,
|
||||
};
|
||||
|
||||
let mut sample_table = TryVec::new();
|
||||
let mut sample_size_iter = stsz.sample_sizes.iter();
|
||||
|
||||
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
|
||||
// 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,
|
||||
// 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) {
|
||||
for i in stsc_iter {
|
||||
let chunk_id = i.0 as usize;
|
||||
let sample_counts = i.1;
|
||||
let mut cur_position = match stco.offsets.get(chunk_id) {
|
||||
Some(&i) => i.into(),
|
||||
Some(&i) => i,
|
||||
_ => return None,
|
||||
};
|
||||
for _ in 0..sample_counts {
|
||||
let start_offset = cur_position;
|
||||
let end_offset = match (stsz.sample_size, sample_size_iter.next()) {
|
||||
(_, Some(t)) => (start_offset + *t)?,
|
||||
(t, _) if t > 0 => (start_offset + t)?,
|
||||
_ => 0.into(),
|
||||
(_, Some(t)) => start_offset + u64::from(*t),
|
||||
(t, _) if t > 0 => start_offset + u64::from(t),
|
||||
_ => 0,
|
||||
};
|
||||
if end_offset == 0 {
|
||||
return None;
|
||||
|
@ -1518,8 +1376,10 @@ fn create_sample_table(
|
|||
.push(Mp4parseIndice {
|
||||
start_offset,
|
||||
end_offset,
|
||||
start_composition: 0,
|
||||
end_composition: 0,
|
||||
start_decode: 0,
|
||||
sync: !has_sync_table,
|
||||
..Default::default()
|
||||
})
|
||||
.ok()?;
|
||||
}
|
||||
|
@ -1529,7 +1389,7 @@ fn create_sample_table(
|
|||
if let Some(ref v) = track.stss {
|
||||
for iter in &v.samples {
|
||||
match iter
|
||||
.checked_sub(&1)
|
||||
.checked_sub(1)
|
||||
.and_then(|idx| sample_table.get_mut(idx as usize))
|
||||
{
|
||||
Some(elem) => elem.sync = true,
|
||||
|
@ -1566,20 +1426,25 @@ fn create_sample_table(
|
|||
let mut sum_delta = TrackScaledTime::<i64>(0, track.id);
|
||||
for sample in sample_table.as_mut_slice() {
|
||||
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.
|
||||
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)?;
|
||||
sample.end_composition = (track_offset_time + end_composition)?;
|
||||
sample.start_decode = start_decode.into();
|
||||
match (start_composition, end_composition, start_decode) {
|
||||
(Some(s_c), Some(e_c), Some(s_d)) => {
|
||||
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.
|
||||
|
@ -1588,15 +1453,14 @@ fn create_sample_table(
|
|||
// calculate to correct the composition end time.
|
||||
if !sample_table.is_empty() {
|
||||
// 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() {
|
||||
sort_table.push(i).ok()?;
|
||||
}
|
||||
|
||||
sort_table.sort_by_key(|i| match sample_table.get(*i) {
|
||||
Some(v) => v.start_composition,
|
||||
_ => 0.into(),
|
||||
_ => 0,
|
||||
});
|
||||
|
||||
for indices in sort_table.windows(2) {
|
||||
|
@ -1736,14 +1600,13 @@ fn get_pssh_info(
|
|||
|
||||
pssh_data.clear();
|
||||
for pssh in &context.psshs {
|
||||
let content_len = pssh
|
||||
.box_content
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| Mp4parseStatus::Invalid)?;
|
||||
let content_len = pssh.box_content.len();
|
||||
if content_len > std::u32::MAX as usize {
|
||||
return Err(Mp4parseStatus::Invalid);
|
||||
}
|
||||
let mut data_len = TryVec::new();
|
||||
if data_len
|
||||
.write_u32::<byteorder::NativeEndian>(content_len)
|
||||
.write_u32::<byteorder::NativeEndian>(content_len as u32)
|
||||
.is_err()
|
||||
{
|
||||
return Err(Mp4parseStatus::Io);
|
||||
|
@ -1821,7 +1684,9 @@ fn arg_validation() {
|
|||
|
||||
let mut dummy_info = Mp4parseTrackInfo {
|
||||
track_type: Mp4parseTrackType::Video,
|
||||
..Default::default()
|
||||
track_id: 0,
|
||||
duration: 0,
|
||||
media_time: 0,
|
||||
};
|
||||
assert_eq!(
|
||||
Mp4parseStatus::BadArg,
|
||||
|
@ -1889,7 +1754,9 @@ fn arg_validation_with_parser() {
|
|||
|
||||
let mut dummy_info = Mp4parseTrackInfo {
|
||||
track_type: Mp4parseTrackType::Video,
|
||||
..Default::default()
|
||||
track_id: 0,
|
||||
duration: 0,
|
||||
media_time: 0,
|
||||
};
|
||||
assert_eq!(
|
||||
Mp4parseStatus::BadArg,
|
||||
|
@ -1961,7 +1828,9 @@ fn minimal_mp4_get_track_info() {
|
|||
|
||||
let mut info = Mp4parseTrackInfo {
|
||||
track_type: Mp4parseTrackType::Video,
|
||||
..Default::default()
|
||||
track_id: 0,
|
||||
duration: 0,
|
||||
media_time: 0,
|
||||
};
|
||||
assert_eq!(Mp4parseStatus::Ok, unsafe {
|
||||
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 {
|
||||
track_type: Mp4parseTrackType::Video,
|
||||
..Default::default()
|
||||
track_id: 0,
|
||||
duration: 0,
|
||||
media_time: 0,
|
||||
};
|
||||
assert_eq!(Mp4parseStatus::BadArg, unsafe {
|
||||
mp4parse_get_track_info(parser, 3, &mut info)
|
||||
|
|
|
@ -48,19 +48,19 @@ fn parse_sample_table() {
|
|||
|
||||
// Compare the value from stagefright.
|
||||
let audio_indice_0 = Mp4parseIndice {
|
||||
start_offset: 27_046.into(),
|
||||
end_offset: 27_052.into(),
|
||||
start_composition: 0.into(),
|
||||
end_composition: 46_439.into(),
|
||||
start_decode: 0.into(),
|
||||
start_offset: 27_046,
|
||||
end_offset: 27_052,
|
||||
start_composition: 0,
|
||||
end_composition: 46_439,
|
||||
start_decode: 0,
|
||||
sync: true,
|
||||
};
|
||||
let audio_indice_215 = Mp4parseIndice {
|
||||
start_offset: 283_550.into(),
|
||||
end_offset: 283_556.into(),
|
||||
start_composition: 9_984_580.into(),
|
||||
end_composition: 10_031_020.into(),
|
||||
start_decode: 9_984_580.into(),
|
||||
start_offset: 283_550,
|
||||
end_offset: 283_556,
|
||||
start_composition: 9_984_580,
|
||||
end_composition: 10_031_020,
|
||||
start_decode: 9_984_580,
|
||||
sync: true,
|
||||
};
|
||||
assert_eq!(indice.length, 216);
|
||||
|
@ -83,19 +83,19 @@ fn parse_sample_table() {
|
|||
|
||||
// Compare the last few data from stagefright.
|
||||
let video_indice_291 = Mp4parseIndice {
|
||||
start_offset: 280_226.into(),
|
||||
end_offset: 280_855.into(),
|
||||
start_composition: 9_838_333.into(),
|
||||
end_composition: 9_871_677.into(),
|
||||
start_decode: 9_710_000.into(),
|
||||
start_offset: 280_226,
|
||||
end_offset: 280_855,
|
||||
start_composition: 9_838_333,
|
||||
end_composition: 9_871_677,
|
||||
start_decode: 9_710_000,
|
||||
sync: false,
|
||||
};
|
||||
let video_indice_292 = Mp4parseIndice {
|
||||
start_offset: 280_855.into(),
|
||||
end_offset: 281_297.into(),
|
||||
start_composition: 9_805_011.into(),
|
||||
end_composition: 9_838_333.into(),
|
||||
start_decode: 9_710_011.into(),
|
||||
start_offset: 280_855,
|
||||
end_offset: 281_297,
|
||||
start_composition: 9_805_011,
|
||||
end_composition: 9_838_333,
|
||||
start_decode: 9_710_011,
|
||||
sync: false,
|
||||
};
|
||||
// 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_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 {
|
||||
start_offset: 282_391.into(),
|
||||
end_offset: 283_032.into(),
|
||||
start_composition: 9_971_666.into(),
|
||||
end_composition: 9_971_677.into(),
|
||||
start_decode: 9_843_333.into(),
|
||||
start_offset: 282_391,
|
||||
end_offset: 283_032,
|
||||
start_composition: 9_971_666,
|
||||
end_composition: 9_971_677,
|
||||
start_decode: 9_843_333,
|
||||
sync: false,
|
||||
};
|
||||
let video_indice_296 = Mp4parseIndice {
|
||||
start_offset: 283_092.into(),
|
||||
end_offset: 283_526.into(),
|
||||
start_composition: 9_938_344.into(),
|
||||
end_composition: 9_971_666.into(),
|
||||
start_decode: 9_843_344.into(),
|
||||
start_offset: 283_092,
|
||||
end_offset: 283_526,
|
||||
start_composition: 9_938_344,
|
||||
end_composition: 9_971_666,
|
||||
start_decode: 9_843_344,
|
||||
sync: false,
|
||||
};
|
||||
|
||||
|
@ -169,27 +169,27 @@ fn parse_sample_table_with_elst() {
|
|||
// Due to 'elst', the start_composition and end_composition are negative
|
||||
// at first two samples.
|
||||
let audio_indice_0 = Mp4parseIndice {
|
||||
start_offset: 6992.into(),
|
||||
end_offset: 7363.into(),
|
||||
start_composition: (-36281).into(),
|
||||
end_composition: (-13062).into(),
|
||||
start_decode: 0.into(),
|
||||
start_offset: 6992,
|
||||
end_offset: 7363,
|
||||
start_composition: -36281,
|
||||
end_composition: -13062,
|
||||
start_decode: 0,
|
||||
sync: true,
|
||||
};
|
||||
let audio_indice_1 = Mp4parseIndice {
|
||||
start_offset: 7363.into(),
|
||||
end_offset: 7735.into(),
|
||||
start_composition: (-13062).into(),
|
||||
end_composition: 10158.into(),
|
||||
start_decode: 23219.into(),
|
||||
start_offset: 7363,
|
||||
end_offset: 7735,
|
||||
start_composition: -13062,
|
||||
end_composition: 10158,
|
||||
start_decode: 23219,
|
||||
sync: true,
|
||||
};
|
||||
let audio_indice_2 = Mp4parseIndice {
|
||||
start_offset: 7735.into(),
|
||||
end_offset: 8106.into(),
|
||||
start_composition: 10158.into(),
|
||||
end_composition: 33378.into(),
|
||||
start_decode: 46439.into(),
|
||||
start_offset: 7735,
|
||||
end_offset: 8106,
|
||||
start_composition: 10158,
|
||||
end_composition: 33378,
|
||||
start_decode: 46439,
|
||||
sync: true,
|
||||
};
|
||||
assert_eq!(indice.length, 21);
|
||||
|
@ -236,35 +236,35 @@ fn parse_sample_table_with_negative_ctts() {
|
|||
|
||||
// There are negative value in 'ctts' table.
|
||||
let video_indice_0 = Mp4parseIndice {
|
||||
start_offset: 48.into(),
|
||||
end_offset: 890.into(),
|
||||
start_composition: 0.into(),
|
||||
end_composition: 33_333.into(),
|
||||
start_decode: 0.into(),
|
||||
start_offset: 48,
|
||||
end_offset: 890,
|
||||
start_composition: 0,
|
||||
end_composition: 33_333,
|
||||
start_decode: 0,
|
||||
sync: true,
|
||||
};
|
||||
let video_indice_1 = Mp4parseIndice {
|
||||
start_offset: 890.into(),
|
||||
end_offset: 913.into(),
|
||||
start_composition: 133_333.into(),
|
||||
end_composition: 166_666.into(),
|
||||
start_decode: 33_333.into(),
|
||||
start_offset: 890,
|
||||
end_offset: 913,
|
||||
start_composition: 133_333,
|
||||
end_composition: 166_666,
|
||||
start_decode: 33_333,
|
||||
sync: false,
|
||||
};
|
||||
let video_indice_2 = Mp4parseIndice {
|
||||
start_offset: 913.into(),
|
||||
end_offset: 934.into(),
|
||||
start_composition: 66_666.into(),
|
||||
end_composition: 100_000.into(),
|
||||
start_decode: 66_666.into(),
|
||||
start_offset: 913,
|
||||
end_offset: 934,
|
||||
start_composition: 66_666,
|
||||
end_composition: 100_000,
|
||||
start_decode: 66_666,
|
||||
sync: false,
|
||||
};
|
||||
let video_indice_3 = Mp4parseIndice {
|
||||
start_offset: 934.into(),
|
||||
end_offset: 955.into(),
|
||||
start_composition: 33_333.into(),
|
||||
end_composition: 66_666.into(),
|
||||
start_decode: 100_000.into(),
|
||||
start_offset: 934,
|
||||
end_offset: 955,
|
||||
start_composition: 33_333,
|
||||
end_composition: 66_666,
|
||||
start_decode: 100_000,
|
||||
sync: false,
|
||||
};
|
||||
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)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "num-bigint"
|
||||
version = "0.3.0"
|
||||
version = "0.2.3"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
||||
description = "Big integer implementation for Rust"
|
||||
homepage = "https://github.com/rust-num/num-bigint"
|
||||
documentation = "https://docs.rs/num-bigint"
|
||||
|
@ -44,32 +42,40 @@ name = "roots"
|
|||
name = "shootout-pidigits"
|
||||
harness = false
|
||||
[dependencies.num-integer]
|
||||
version = "0.1.42"
|
||||
features = ["i128"]
|
||||
version = "0.1.39"
|
||||
default-features = false
|
||||
|
||||
[dependencies.num-traits]
|
||||
version = "0.2.11"
|
||||
features = ["i128"]
|
||||
version = "0.2.7"
|
||||
default-features = false
|
||||
|
||||
[dependencies.quickcheck]
|
||||
version = "0.9"
|
||||
version = "0.8"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.quickcheck_macros]
|
||||
version = "0.8"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.7"
|
||||
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 = "1"
|
||||
version = "0.1.2"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
i128 = ["num-integer/i128", "num-traits/i128"]
|
||||
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)
|
||||
[![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)
|
||||
[![build status](https://github.com/rust-num/num-bigint/workflows/master/badge.svg)](https://github.com/rust-num/num-bigint/actions)
|
||||
![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`.
|
||||
|
||||
|
@ -13,28 +13,25 @@ Add this to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
num-bigint = "0.3"
|
||||
num-bigint = "0.2"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate num_bigint;
|
||||
```
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
### 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`.
|
||||
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
|
||||
|
||||
|
@ -42,7 +39,7 @@ Release notes are available in [RELEASES.md](RELEASES.md).
|
|||
|
||||
## 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
|
||||
|
||||
|
@ -52,9 +49,9 @@ table offers a brief comparison to a few alternatives.
|
|||
|
||||
| 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 |
|
||||
| [`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] |
|
||||
| [`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)
|
||||
|
||||
- [`Pow` is now implemented for `BigUint` exponents][77].
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#![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, Zero};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
use num_traits::{FromPrimitive, Num, One, Pow, Zero};
|
||||
use rand::{SeedableRng, StdRng};
|
||||
use std::mem::replace;
|
||||
use test::Bencher;
|
||||
|
||||
|
@ -18,7 +21,7 @@ fn get_rng() -> StdRng {
|
|||
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 x = rng.gen_bigint(xbits);
|
||||
let y = rng.gen_bigint(ybits);
|
||||
|
@ -26,7 +29,7 @@ fn multiply_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
|||
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 x = rng.gen_bigint(xbits);
|
||||
let y = rng.gen_bigint(ybits);
|
||||
|
@ -34,7 +37,7 @@ fn divide_bench(b: &mut Bencher, xbits: u64, ybits: u64) {
|
|||
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 x = rng.gen_bigint(xbits);
|
||||
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 {
|
||||
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();
|
||||
f += bu;
|
||||
f = f * bu;
|
||||
}
|
||||
f
|
||||
}
|
||||
|
@ -68,7 +71,7 @@ fn fib2(n: usize) -> BigUint {
|
|||
let mut f0: BigUint = Zero::zero();
|
||||
let mut f1: BigUint = One::one();
|
||||
for _ in 0..n {
|
||||
f1 += &f0;
|
||||
f1 = f1 + &f0;
|
||||
f0 = &f1 - f0;
|
||||
}
|
||||
f0
|
||||
|
@ -109,11 +112,6 @@ fn divide_2(b: &mut Bencher) {
|
|||
divide_bench(b, 1 << 16, 1 << 12);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn divide_big_little(b: &mut Bencher) {
|
||||
divide_bench(b, 1 << 16, 1 << 4);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn remainder_0(b: &mut Bencher) {
|
||||
remainder_bench(b, 1 << 8, 1 << 6);
|
||||
|
@ -129,11 +127,6 @@ fn remainder_2(b: &mut Bencher) {
|
|||
remainder_bench(b, 1 << 16, 1 << 12);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn remainder_big_little(b: &mut Bencher) {
|
||||
remainder_bench(b, 1 << 16, 1 << 4);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn factorial_100(b: &mut Bencher) {
|
||||
b.iter(|| factorial(100));
|
||||
|
@ -245,7 +238,7 @@ fn from_str_radix_36(b: &mut Bencher) {
|
|||
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();
|
||||
|
||||
b.iter(|| rng.gen_bigint(bits));
|
||||
|
@ -293,24 +286,22 @@ fn rand_131072(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn shl(b: &mut Bencher) {
|
||||
let n = BigUint::one() << 1000u32;
|
||||
let mut m = n.clone();
|
||||
let n = BigUint::one() << 1000;
|
||||
b.iter(|| {
|
||||
m.clone_from(&n);
|
||||
let mut m = n.clone();
|
||||
for i in 0..50 {
|
||||
m <<= i;
|
||||
m = m << i;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn shr(b: &mut Bencher) {
|
||||
let n = BigUint::one() << 2000u32;
|
||||
let mut m = n.clone();
|
||||
let n = BigUint::one() << 2000;
|
||||
b.iter(|| {
|
||||
m.clone_from(&n);
|
||||
let mut m = n.clone();
|
||||
for i in 0..50 {
|
||||
m >>= i;
|
||||
m = m >> i;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -329,49 +320,31 @@ fn hash(b: &mut Bencher) {
|
|||
#[bench]
|
||||
fn pow_bench(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let upper = 100_u32;
|
||||
let mut i_big = BigUint::from(1u32);
|
||||
for _i in 2..=upper {
|
||||
i_big += 1u32;
|
||||
for j in 2..=upper {
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[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:
|
||||
/// https://tools.ietf.org/html/rfc3526#section-3
|
||||
const RFC3526_2048BIT_MODP_GROUP: &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";
|
||||
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) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
extern crate test;
|
||||
|
||||
use num_bigint::BigUint;
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#![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::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
use rand::{SeedableRng, StdRng};
|
||||
use test::Bencher;
|
||||
|
||||
fn get_rng() -> StdRng {
|
||||
|
@ -18,7 +21,7 @@ fn get_rng() -> StdRng {
|
|||
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 x = rng.gen_biguint(bits);
|
||||
let y = rng.gen_biguint(bits);
|
||||
|
@ -37,7 +40,7 @@ fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
|
|||
m = n % &temp;
|
||||
n = temp;
|
||||
}
|
||||
n
|
||||
return n;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#![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 rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
use num_traits::Pow;
|
||||
use rand::{SeedableRng, StdRng};
|
||||
use test::Bencher;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
fn bench_sqrt(b: &mut Bencher, bits: u64) {
|
||||
fn bench_sqrt(b: &mut Bencher, bits: usize) {
|
||||
let x = get_rng().gen_biguint(bits);
|
||||
eprintln!("bench_sqrt({})", x);
|
||||
|
||||
|
@ -71,7 +74,7 @@ fn big4k_sqrt(b: &mut Bencher) {
|
|||
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);
|
||||
eprintln!("bench_cbrt({})", x);
|
||||
|
||||
|
@ -99,7 +102,7 @@ fn big4k_cbrt(b: &mut Bencher) {
|
|||
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);
|
||||
eprintln!("bench_{}th_root({})", n, x);
|
||||
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
// 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;
|
||||
|
||||
|
@ -94,7 +98,7 @@ 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 {
|
||||
for i in 1..(n + 1) {
|
||||
let mut d;
|
||||
loop {
|
||||
k += 1;
|
||||
|
@ -107,7 +111,7 @@ fn pidigits(n: isize, out: &mut dyn io::Write) -> io::Result<()> {
|
|||
|
||||
write!(out, "{}", d)?;
|
||||
if i % 10 == 0 {
|
||||
writeln!(out, "\t:{}", i)?;
|
||||
write!(out, "\t:{}\n", i)?;
|
||||
}
|
||||
|
||||
context.eliminate_digit(d);
|
||||
|
@ -118,7 +122,7 @@ fn pidigits(n: isize, out: &mut dyn io::Write) -> io::Result<()> {
|
|||
for _ in m..10 {
|
||||
write!(out, " ")?;
|
||||
}
|
||||
writeln!(out, "\t:{}", n)?;
|
||||
write!(out, "\t:{}\n", n)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,71 +1,14 @@
|
|||
extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
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();
|
||||
if ac.probe_path("std::convert::TryFrom") || ac.probe_path("core::convert::TryFrom") {
|
||||
autocfg::emit("has_try_from");
|
||||
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("build.rs");
|
||||
|
||||
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(())
|
||||
autocfg::rerun_path(file!());
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
use crate::std_alloc::{Cow, Vec};
|
||||
use core::cmp;
|
||||
use core::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use core::iter::repeat;
|
||||
use core::mem;
|
||||
use num_traits::{One, PrimInt, Zero};
|
||||
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 crate::biguint::biguint_from_vec;
|
||||
use crate::biguint::BigUint;
|
||||
use biguint::BigUint;
|
||||
|
||||
use crate::bigint::BigInt;
|
||||
use crate::bigint::Sign;
|
||||
use crate::bigint::Sign::{Minus, NoSign, Plus};
|
||||
use bigint::BigInt;
|
||||
use bigint::Sign;
|
||||
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:
|
||||
|
||||
|
@ -37,12 +37,7 @@ fn sbb(a: BigDigit, b: BigDigit, acc: &mut SignedDoubleBigDigit) -> BigDigit {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn mac_with_carry(
|
||||
a: BigDigit,
|
||||
b: BigDigit,
|
||||
c: BigDigit,
|
||||
acc: &mut DoubleBigDigit,
|
||||
) -> BigDigit {
|
||||
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;
|
||||
|
@ -51,7 +46,7 @@ pub(crate) fn mac_with_carry(
|
|||
}
|
||||
|
||||
#[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);
|
||||
let lo = *acc as BigDigit;
|
||||
*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)
|
||||
}
|
||||
|
||||
/// For small divisors, we can divide without promoting to `DoubleBigDigit` by
|
||||
/// 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) {
|
||||
pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
|
||||
let mut rem = 0;
|
||||
|
||||
if b <= big_digit::HALF {
|
||||
for d in a.data.iter_mut().rev() {
|
||||
let (q, r) = div_half(rem, *d, b);
|
||||
*d = q;
|
||||
rem = r;
|
||||
}
|
||||
} else {
|
||||
for d in a.data.iter_mut().rev() {
|
||||
let (q, r) = div_wide(rem, *d, b);
|
||||
*d = q;
|
||||
rem = r;
|
||||
}
|
||||
for d in a.data.iter_mut().rev() {
|
||||
let (q, r) = div_wide(rem, *d, b);
|
||||
*d = q;
|
||||
rem = r;
|
||||
}
|
||||
|
||||
(a.normalized(), rem)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
|
||||
let mut rem = 0;
|
||||
|
||||
if b <= big_digit::HALF {
|
||||
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;
|
||||
}
|
||||
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
|
||||
rem as BigDigit
|
||||
}
|
||||
|
||||
/// Two argument addition of raw slices, `a += b`, returning the carry.
|
||||
///
|
||||
/// 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`.
|
||||
// Only for the Add impl:
|
||||
#[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());
|
||||
|
||||
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
|
||||
/// 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);
|
||||
|
||||
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 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.
|
||||
#[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());
|
||||
|
||||
let mut borrow = 0;
|
||||
|
@ -207,7 +166,7 @@ pub(crate) fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> 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());
|
||||
|
||||
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:
|
||||
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)];
|
||||
|
@ -234,12 +193,12 @@ pub(crate) fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
|||
Greater => {
|
||||
let mut a = a.to_vec();
|
||||
sub2(&mut a, b);
|
||||
(Plus, biguint_from_vec(a))
|
||||
(Plus, BigUint::new(a))
|
||||
}
|
||||
Less => {
|
||||
let mut b = b.to_vec();
|
||||
sub2(&mut b, a);
|
||||
(Minus, biguint_from_vec(b))
|
||||
(Minus, BigUint::new(b))
|
||||
}
|
||||
_ => (NoSign, Zero::zero()),
|
||||
}
|
||||
|
@ -247,7 +206,7 @@ pub(crate) fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
|
|||
|
||||
/// Three argument multiply accumulate:
|
||||
/// 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 {
|
||||
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:
|
||||
/// acc += b * c
|
||||
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.
|
||||
//
|
||||
// x(t) = x2*t^2 + x1*t + x0
|
||||
let x0 = bigint_from_slice(&x[..x0_len]);
|
||||
let x1 = bigint_from_slice(&x[x0_len..x0_len + x1_len]);
|
||||
let x2 = bigint_from_slice(&x[x0_len + x1_len..]);
|
||||
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(&y[..y0_len]);
|
||||
let y1 = bigint_from_slice(&y[y0_len..y0_len + y1_len]);
|
||||
let y2 = bigint_from_slice(&y[y0_len + y1_len..]);
|
||||
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)
|
||||
//
|
||||
|
@ -515,24 +470,23 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|||
let mut comp1: BigInt = (r1 - &r2) / 2;
|
||||
let mut comp2: BigInt = r2 - &r0;
|
||||
comp3 = (&comp2 - comp3) / 2 + &r4 * 2;
|
||||
comp2 += &comp1 - &r4;
|
||||
comp1 -= &comp3;
|
||||
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 bits = u64::from(big_digit::BITS) * i as u64;
|
||||
let result = r0
|
||||
+ (comp1 << bits)
|
||||
+ (comp2 << (2 * bits))
|
||||
+ (comp3 << (3 * bits))
|
||||
+ (r4 << (4 * bits));
|
||||
+ (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(crate) fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
||||
pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
||||
let len = x.len() + y.len() + 1;
|
||||
let mut prod = BigUint { data: vec![0; len] };
|
||||
|
||||
|
@ -540,7 +494,7 @@ pub(crate) fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
|
|||
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;
|
||||
for a in a.iter_mut() {
|
||||
*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
|
||||
}
|
||||
|
||||
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() {
|
||||
panic!("attempt to divide by zero")
|
||||
panic!()
|
||||
}
|
||||
if u.is_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.
|
||||
//
|
||||
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)
|
||||
|
@ -595,9 +548,9 @@ pub(crate) fn div_rem(mut u: BigUint, mut d: BigUint) -> (BigUint, BigUint) {
|
|||
(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() {
|
||||
panic!("attempt to divide by zero")
|
||||
panic!()
|
||||
}
|
||||
if u.is_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;
|
||||
|
||||
while cmp_slice(&prod.data[..], &a.data[j..]) == Greater {
|
||||
q0 -= 1u32;
|
||||
prod -= b;
|
||||
let one: BigUint = One::one();
|
||||
q0 = q0 - one;
|
||||
prod = prod - b;
|
||||
}
|
||||
|
||||
add2(&mut q.data[j..], &q0.data[..]);
|
||||
|
@ -713,53 +667,41 @@ fn div_rem_core(mut a: BigUint, b: &BigUint) -> (BigUint, BigUint) {
|
|||
tmp = q0;
|
||||
}
|
||||
|
||||
debug_assert!(a < *b);
|
||||
debug_assert!(&a < b);
|
||||
|
||||
(q.normalized(), a)
|
||||
}
|
||||
|
||||
/// Find last set bit
|
||||
/// fls(0) == 0, fls(u32::MAX) == 32
|
||||
pub(crate) fn fls<T: PrimInt>(v: T) -> u8 {
|
||||
mem::size_of::<T>() as u8 * 8 - v.leading_zeros() as u8
|
||||
pub fn fls<T: traits::PrimInt>(v: T) -> usize {
|
||||
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
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn biguint_shl<T: PrimInt>(n: Cow<'_, BigUint>, shift: T) -> BigUint {
|
||||
if shift < T::zero() {
|
||||
panic!("attempt to shift left with negative");
|
||||
}
|
||||
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 {
|
||||
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 = digits.saturating_add(n.data.len() + 1);
|
||||
let len = n_unit + n.data.len() + 1;
|
||||
let mut data = Vec::with_capacity(len);
|
||||
data.extend(repeat(0).take(digits));
|
||||
data.extend(n.data.iter());
|
||||
data.extend(repeat(0).take(n_unit));
|
||||
data.extend(n.data.iter().cloned());
|
||||
data
|
||||
}
|
||||
};
|
||||
|
||||
if shift > 0 {
|
||||
let n_bits = bits % big_digit::BITS;
|
||||
if n_bits > 0 {
|
||||
let mut carry = 0;
|
||||
let carry_shift = big_digit::BITS as u8 - shift;
|
||||
for elem in data[digits..].iter_mut() {
|
||||
let new_carry = *elem >> carry_shift;
|
||||
*elem = (*elem << shift) | carry;
|
||||
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 {
|
||||
|
@ -767,65 +709,65 @@ fn biguint_shl2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
|
|||
}
|
||||
}
|
||||
|
||||
biguint_from_vec(data)
|
||||
BigUint::new(data)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn biguint_shr<T: PrimInt>(n: Cow<'_, BigUint>, shift: T) -> BigUint {
|
||||
if shift < T::zero() {
|
||||
panic!("attempt to shift right with negative");
|
||||
}
|
||||
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;
|
||||
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[digits..].to_vec(),
|
||||
Cow::Borrowed(n) => n.data[n_unit..].to_vec(),
|
||||
Cow::Owned(mut n) => {
|
||||
n.data.drain(..digits);
|
||||
n.data.drain(..n_unit);
|
||||
n.data
|
||||
}
|
||||
};
|
||||
|
||||
if shift > 0 {
|
||||
let n_bits = bits % big_digit::BITS;
|
||||
if n_bits > 0 {
|
||||
let mut borrow = 0;
|
||||
let borrow_shift = big_digit::BITS as u8 - shift;
|
||||
for elem in data.iter_mut().rev() {
|
||||
let new_borrow = *elem << borrow_shift;
|
||||
*elem = (*elem >> shift) | borrow;
|
||||
let new_borrow = *elem << (big_digit::BITS - n_bits);
|
||||
*elem = (*elem >> n_bits) | 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!(b.last() != Some(&0));
|
||||
|
||||
match Ord::cmp(&a.len(), &b.len()) {
|
||||
Equal => Iterator::cmp(a.iter().rev(), b.iter().rev()),
|
||||
other => other,
|
||||
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 crate::big_digit::BigDigit;
|
||||
use crate::{BigInt, BigUint};
|
||||
use num_traits::Num;
|
||||
use big_digit::BigDigit;
|
||||
use traits::Num;
|
||||
use Sign::Plus;
|
||||
use {BigInt, BigUint};
|
||||
|
||||
#[test]
|
||||
fn test_sub_sign() {
|
||||
|
@ -838,8 +780,8 @@ mod algorithm_tests {
|
|||
|
||||
let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap();
|
||||
let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap();
|
||||
let a_i = BigInt::from(a.clone());
|
||||
let b_i = BigInt::from(b.clone());
|
||||
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,27 +1,25 @@
|
|||
//! Randomization of big integers
|
||||
|
||||
use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
|
||||
use rand::distributions::uniform::{SampleUniform, UniformSampler};
|
||||
use rand::prelude::*;
|
||||
use rand::AsByteSliceMut;
|
||||
|
||||
use crate::BigInt;
|
||||
use crate::BigUint;
|
||||
use crate::Sign::*;
|
||||
use BigInt;
|
||||
use BigUint;
|
||||
use Sign::*;
|
||||
|
||||
use crate::bigint::{into_magnitude, magnitude};
|
||||
use crate::biguint::biguint_from_vec;
|
||||
use big_digit::BigDigit;
|
||||
use bigint::{into_magnitude, magnitude};
|
||||
|
||||
use num_integer::Integer;
|
||||
use num_traits::{ToPrimitive, Zero};
|
||||
use integer::Integer;
|
||||
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 {
|
||||
/// 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.
|
||||
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
|
||||
/// 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_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 {
|
||||
#[cfg(not(u64_digit))]
|
||||
fn gen_biguint(&mut self, bit_size: u64) -> BigUint {
|
||||
let (digits, rem) = bit_size.div_rem(&32);
|
||||
let len = (digits + (rem > 0) as u64)
|
||||
.to_usize()
|
||||
.expect("capacity overflow");
|
||||
let mut data = vec![0u32; len];
|
||||
gen_bits(self, &mut data, rem);
|
||||
biguint_from_vec(data)
|
||||
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)
|
||||
}
|
||||
|
||||
#[cfg(u64_digit)]
|
||||
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 {
|
||||
fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
|
||||
loop {
|
||||
// Generate a random BigUint...
|
||||
let biguint = self.gen_biguint(bit_size);
|
||||
|
@ -153,28 +121,16 @@ impl UniformSampler for UniformBigUint {
|
|||
type X = BigUint;
|
||||
|
||||
#[inline]
|
||||
fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = low_b.borrow();
|
||||
let high = high_b.borrow();
|
||||
fn new(low: Self::X, high: Self::X) -> Self {
|
||||
assert!(low < high);
|
||||
UniformBigUint {
|
||||
len: high - low,
|
||||
base: low.clone(),
|
||||
len: high - &low,
|
||||
base: low,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = low_b.borrow();
|
||||
let high = high_b.borrow();
|
||||
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
|
||||
assert!(low <= high);
|
||||
Self::new(low, high + 1u32)
|
||||
}
|
||||
|
@ -185,12 +141,8 @@ impl UniformSampler for UniformBigUint {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_single<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R) -> Self::X
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
rng.gen_biguint_range(low.borrow(), high.borrow())
|
||||
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
|
||||
rng.gen_biguint_range(&low, &high)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,28 +161,16 @@ impl UniformSampler for UniformBigInt {
|
|||
type X = BigInt;
|
||||
|
||||
#[inline]
|
||||
fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = low_b.borrow();
|
||||
let high = high_b.borrow();
|
||||
fn new(low: Self::X, high: Self::X) -> Self {
|
||||
assert!(low < high);
|
||||
UniformBigInt {
|
||||
len: into_magnitude(high - low),
|
||||
base: low.clone(),
|
||||
len: into_magnitude(high - &low),
|
||||
base: low,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = low_b.borrow();
|
||||
let high = high_b.borrow();
|
||||
fn new_inclusive(low: Self::X, high: Self::X) -> Self {
|
||||
assert!(low <= high);
|
||||
Self::new(low, high + 1u32)
|
||||
}
|
||||
|
@ -241,12 +181,8 @@ impl UniformSampler for UniformBigInt {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_single<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R) -> Self::X
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
rng.gen_bigint_range(low.borrow(), high.borrow())
|
||||
fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
|
||||
rng.gen_bigint_range(&low, &high)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,16 +191,14 @@ impl SampleUniform for BigInt {
|
|||
}
|
||||
|
||||
/// 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)]
|
||||
pub struct RandomBits {
|
||||
bits: u64,
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl RandomBits {
|
||||
#[inline]
|
||||
pub fn new(bits: u64) -> RandomBits {
|
||||
pub fn new(bits: usize) -> RandomBits {
|
||||
RandomBits { bits }
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,6 +19,9 @@
|
|||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate num_bigint;
|
||||
//! extern crate num_traits;
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! use num_bigint::BigUint;
|
||||
//! use num_traits::{Zero, One};
|
||||
|
@ -43,8 +46,14 @@
|
|||
//!
|
||||
//! It's easy to generate large random numbers:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use num_bigint::{ToBigInt, RandBigInt};
|
||||
//! ```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);
|
||||
|
@ -55,67 +64,34 @@
|
|||
//!
|
||||
//! // Probably an even larger number.
|
||||
//! 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
|
||||
//!
|
||||
//! 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")]
|
||||
#![no_std]
|
||||
#![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 = "std")]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
#[cfg(feature = "rand")]
|
||||
extern crate rand;
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod std_alloc {
|
||||
pub(crate) use std::borrow::Cow;
|
||||
#[cfg(feature = "quickcheck")]
|
||||
pub(crate) use std::boxed::Box;
|
||||
pub(crate) use std::string::String;
|
||||
pub(crate) use std::vec::Vec;
|
||||
}
|
||||
extern crate num_integer as integer;
|
||||
extern crate num_traits as traits;
|
||||
#[cfg(feature = "quickcheck")]
|
||||
extern crate quickcheck;
|
||||
|
||||
#[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::fmt;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -149,7 +125,7 @@ enum BigIntErrorKind {
|
|||
|
||||
impl ParseBigIntError {
|
||||
fn __description(&self) -> &str {
|
||||
use crate::BigIntErrorKind::*;
|
||||
use BigIntErrorKind::*;
|
||||
match self.kind {
|
||||
Empty => "cannot parse integer from empty string",
|
||||
InvalidDigit => "invalid digit found in string",
|
||||
|
@ -170,102 +146,42 @@ impl 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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for ParseBigIntError {
|
||||
fn description(&self) -> &str {
|
||||
self.__description()
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type returned when a checked conversion regarding big integer fails.
|
||||
#[cfg(has_try_from)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct TryFromBigIntError<T> {
|
||||
original: T,
|
||||
}
|
||||
pub use biguint::BigUint;
|
||||
pub use biguint::ToBigUint;
|
||||
|
||||
#[cfg(has_try_from)]
|
||||
impl<T> TryFromBigIntError<T> {
|
||||
fn new(original: T) -> Self {
|
||||
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;
|
||||
pub use bigint::BigInt;
|
||||
pub use bigint::Sign;
|
||||
pub use bigint::ToBigInt;
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
pub use crate::bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint};
|
||||
pub use bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint};
|
||||
|
||||
mod big_digit {
|
||||
/// A `BigDigit` is a `BigUint`'s composing element.
|
||||
#[cfg(not(u64_digit))]
|
||||
pub(crate) type BigDigit = u32;
|
||||
#[cfg(u64_digit)]
|
||||
pub(crate) type BigDigit = u64;
|
||||
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`.
|
||||
#[cfg(not(u64_digit))]
|
||||
pub(crate) type DoubleBigDigit = u64;
|
||||
#[cfg(u64_digit)]
|
||||
pub(crate) type DoubleBigDigit = u128;
|
||||
pub type DoubleBigDigit = u64;
|
||||
|
||||
/// A `SignedDoubleBigDigit` is the signed version of `DoubleBigDigit`.
|
||||
#[cfg(not(u64_digit))]
|
||||
pub(crate) type SignedDoubleBigDigit = i64;
|
||||
#[cfg(u64_digit)]
|
||||
pub(crate) type SignedDoubleBigDigit = i128;
|
||||
pub type SignedDoubleBigDigit = i64;
|
||||
|
||||
// `DoubleBigDigit` size dependent
|
||||
#[cfg(not(u64_digit))]
|
||||
pub(crate) const BITS: u8 = 32;
|
||||
#[cfg(u64_digit)]
|
||||
pub(crate) const BITS: u8 = 64;
|
||||
pub const BITS: usize = 32;
|
||||
|
||||
pub(crate) const HALF_BITS: u8 = BITS / 2;
|
||||
pub(crate) const HALF: BigDigit = (1 << HALF_BITS) - 1;
|
||||
|
||||
const LO_MASK: DoubleBigDigit = (1 << BITS) - 1;
|
||||
const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS;
|
||||
|
||||
#[inline]
|
||||
fn get_hi(n: DoubleBigDigit) -> BigDigit {
|
||||
|
@ -278,13 +194,13 @@ mod big_digit {
|
|||
|
||||
/// Split one `DoubleBigDigit` into two `BigDigit`s.
|
||||
#[inline]
|
||||
pub(crate) fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
|
||||
pub fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
|
||||
(get_hi(n), get_lo(n))
|
||||
}
|
||||
|
||||
/// Join two `BigDigit`s into one `DoubleBigDigit`
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(unknown_lints)] // older rustc doesn't know `unused_macros`
|
||||
#![allow(unused_macros)]
|
||||
|
||||
macro_rules! forward_val_val_binop {
|
||||
|
@ -283,7 +284,8 @@ macro_rules! promote_scalars {
|
|||
impl $imp<$scalar> for $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]
|
||||
fn $method(self, other: $scalar) -> $res {
|
||||
$imp::$method(self, other as $promo)
|
||||
|
@ -293,7 +295,8 @@ macro_rules! promote_scalars {
|
|||
impl $imp<$res> for $scalar {
|
||||
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]
|
||||
fn $method(self, other: $res) -> $res {
|
||||
$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<$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]
|
||||
fn $method(&mut self, other: $scalar) {
|
||||
self.$method(other as $promo);
|
||||
|
@ -340,7 +344,7 @@ macro_rules! promote_signed_scalars {
|
|||
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<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 core::mem;
|
||||
use core::ops::Shl;
|
||||
use num_traits::{One, Zero};
|
||||
use integer::Integer;
|
||||
use traits::Zero;
|
||||
|
||||
use crate::big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit};
|
||||
use crate::biguint::BigUint;
|
||||
use biguint::BigUint;
|
||||
|
||||
struct MontyReducer {
|
||||
n0inv: BigDigit,
|
||||
struct MontyReducer<'a> {
|
||||
n: &'a BigUint,
|
||||
n0inv: u32,
|
||||
}
|
||||
|
||||
// k0 = -m**-1 mod 2**BITS. Algorithm from: Dumas, J.G. "On Newton–Raphson
|
||||
// Iteration for Multiplicative Inverses Modulo Prime Powers".
|
||||
fn inv_mod_alt(b: BigDigit) -> BigDigit {
|
||||
assert_ne!(b & 1, 0);
|
||||
// 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 k0 = 2 - b as SignedDoubleBigDigit;
|
||||
let mut t = (b - 1) as SignedDoubleBigDigit;
|
||||
let mut i = 1;
|
||||
while i < big_digit::BITS {
|
||||
t = t.wrapping_mul(t);
|
||||
k0 = k0.wrapping_mul(t + 1);
|
||||
let mut a: i64 = i64::from(num);
|
||||
let mut b: i64 = i64::from(u32::max_value()) + 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 {
|
||||
fn new(n: &BigUint) -> Self {
|
||||
let n0inv = inv_mod_alt(n.data[0]);
|
||||
MontyReducer { n0inv }
|
||||
impl<'a> MontyReducer<'a> {
|
||||
fn new(n: &'a BigUint) -> Self {
|
||||
let n0inv = inv_mod_u32(n.data[0]);
|
||||
MontyReducer { n: n, n0inv: n0inv }
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes z mod m = x * y * 2 ** (-n*_W) mod m
|
||||
/// assuming k = -1/m mod 2**_W
|
||||
/// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
|
||||
/// https://eprint.iacr.org/2011/239.pdf
|
||||
/// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
|
||||
/// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
|
||||
/// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
|
||||
fn montgomery(x: &BigUint, y: &BigUint, m: &BigUint, k: BigDigit, n: usize) -> BigUint {
|
||||
// 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
|
||||
);
|
||||
// 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();
|
||||
|
||||
let mut z = BigUint::zero();
|
||||
z.data.resize(n * 2, 0);
|
||||
// Allocate sufficient work space
|
||||
c.resize(2 * n_size + 2, 0);
|
||||
|
||||
let mut c: BigDigit = 0;
|
||||
for i in 0..n {
|
||||
let c2 = add_mul_vvw(&mut z.data[i..n + i], &x.data, y.data[i]);
|
||||
let t = z.data[i].wrapping_mul(k);
|
||||
let c3 = add_mul_vvw(&mut z.data[i..n + i], &m.data, t);
|
||||
let cx = c.wrapping_add(c2);
|
||||
let cy = cx.wrapping_add(c3);
|
||||
z.data[n + i] = cy;
|
||||
if cx < c2 || cy < c3 {
|
||||
c = 1;
|
||||
} else {
|
||||
c = 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);
|
||||
}
|
||||
|
||||
if c == 0 {
|
||||
z.data = z.data[n..].to_vec();
|
||||
// 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 {
|
||||
{
|
||||
let (mut first, second) = z.data.split_at_mut(n);
|
||||
sub_vv(&mut first, &second, &m.data);
|
||||
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);
|
||||
}
|
||||
z.data = z.data[..n].to_vec();
|
||||
apri = monty_sqr(apri, &mr);
|
||||
e = e >> 1;
|
||||
}
|
||||
|
||||
z
|
||||
}
|
||||
|
||||
#[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
|
||||
// Map the result back to the residues domain
|
||||
monty_redc(ans, &mr)
|
||||
}
|
||||
|
|
|
@ -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::Sign::{Minus, NoSign, Plus};
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
|
@ -8,15 +14,16 @@ use std::hash::{BuildHasher, Hash, Hasher};
|
|||
use std::iter::repeat;
|
||||
use std::ops::Neg;
|
||||
use std::{f32, f64};
|
||||
#[cfg(has_i128)]
|
||||
use std::{i128, u128};
|
||||
use std::{i16, i32, i64, i8, isize};
|
||||
use std::{u16, u32, u64, u8, usize};
|
||||
|
||||
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;
|
||||
use crate::consts::*;
|
||||
use consts::*;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -33,8 +40,8 @@ fn test_from_bytes_be() {
|
|||
check("AA", "16705");
|
||||
check("AB", "16706");
|
||||
check("Hello world!", "22405534230753963835153736737");
|
||||
assert_eq!(BigInt::from_bytes_be(Plus, &[]), BigInt::zero());
|
||||
assert_eq!(BigInt::from_bytes_be(Minus, &[]), BigInt::zero());
|
||||
assert_eq!(BigInt::from_bytes_be(Plus, &[]), Zero::zero());
|
||||
assert_eq!(BigInt::from_bytes_be(Minus, &[]), Zero::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -68,8 +75,8 @@ fn test_from_bytes_le() {
|
|||
check("AA", "16705");
|
||||
check("BA", "16706");
|
||||
check("!dlrow olleH", "22405534230753963835153736737");
|
||||
assert_eq!(BigInt::from_bytes_le(Plus, &[]), BigInt::zero());
|
||||
assert_eq!(BigInt::from_bytes_le(Minus, &[]), BigInt::zero());
|
||||
assert_eq!(BigInt::from_bytes_le(Plus, &[]), Zero::zero());
|
||||
assert_eq!(BigInt::from_bytes_le(Minus, &[]), Zero::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -287,6 +294,7 @@ fn test_convert_i64() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn test_convert_i128() {
|
||||
fn check(b1: BigInt, i: i128) {
|
||||
let b2: BigInt = FromPrimitive::from_i128(i).unwrap();
|
||||
|
@ -344,6 +352,7 @@ fn test_convert_u64() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn test_convert_u128() {
|
||||
fn check(b1: BigInt, u: u128) {
|
||||
let b2: BigInt = FromPrimitive::from_u128(u).unwrap();
|
||||
|
@ -370,7 +379,6 @@ fn test_convert_u128() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn test_convert_f32() {
|
||||
fn check(b1: &BigInt, f: f32) {
|
||||
let b2 = BigInt::from_f32(f).unwrap();
|
||||
|
@ -384,14 +392,14 @@ fn test_convert_f32() {
|
|||
|
||||
check(&BigInt::zero(), 0.0);
|
||||
check(&BigInt::one(), 1.0);
|
||||
check(&BigInt::from(u16::MAX), pow(2.0_f32, 16) - 1.0);
|
||||
check(&BigInt::from(1u64 << 32), pow(2.0_f32, 32));
|
||||
check(&BigInt::from_slice(Plus, &[0, 0, 1]), pow(2.0_f32, 64));
|
||||
check(&BigInt::from(u16::MAX), 2.0.powi(16) - 1.0);
|
||||
check(&BigInt::from(1u64 << 32), 2.0.powi(32));
|
||||
check(&BigInt::from_slice(Plus, &[0, 0, 1]), 2.0.powi(64));
|
||||
check(
|
||||
&((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);
|
||||
|
||||
// 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 {
|
||||
check(&b, f);
|
||||
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
|
||||
|
@ -418,7 +426,7 @@ fn test_convert_f32() {
|
|||
for _ in 0..64 {
|
||||
assert_eq!(b.to_f32(), Some(f));
|
||||
f *= 2.0;
|
||||
b <<= 1;
|
||||
b = b << 1;
|
||||
}
|
||||
|
||||
// rounding
|
||||
|
@ -446,20 +454,19 @@ fn test_convert_f32() {
|
|||
assert_eq!(BigInt::from_f32(f32::NEG_INFINITY), None);
|
||||
|
||||
// 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 + 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) - 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() << 128u8).to_f32(), None);
|
||||
assert_eq!((-((BigInt::one() << 128u8) - 1u8)).to_f32(), None);
|
||||
assert_eq!((-(BigInt::one() << 128u8)).to_f32(), None);
|
||||
assert_eq!(((BigInt::one() << 128) - BigInt::one()).to_f32(), None);
|
||||
assert_eq!((BigInt::one() << 128).to_f32(), None);
|
||||
assert_eq!((-((BigInt::one() << 128) - BigInt::one())).to_f32(), None);
|
||||
assert_eq!((-(BigInt::one() << 128)).to_f32(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn test_convert_f64() {
|
||||
fn check(b1: &BigInt, f: f64) {
|
||||
let b2 = BigInt::from_f64(f).unwrap();
|
||||
|
@ -473,14 +480,14 @@ fn test_convert_f64() {
|
|||
|
||||
check(&BigInt::zero(), 0.0);
|
||||
check(&BigInt::one(), 1.0);
|
||||
check(&BigInt::from(u32::MAX), pow(2.0_f64, 32) - 1.0);
|
||||
check(&BigInt::from(1u64 << 32), pow(2.0_f64, 32));
|
||||
check(&BigInt::from_slice(Plus, &[0, 0, 1]), pow(2.0_f64, 64));
|
||||
check(&BigInt::from(u32::MAX), 2.0.powi(32) - 1.0);
|
||||
check(&BigInt::from(1u64 << 32), 2.0.powi(32));
|
||||
check(&BigInt::from_slice(Plus, &[0, 0, 1]), 2.0.powi(64));
|
||||
check(
|
||||
&((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);
|
||||
|
||||
// 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 {
|
||||
check(&b, f);
|
||||
f *= 2.0;
|
||||
b <<= 1;
|
||||
b = b << 1;
|
||||
}
|
||||
|
||||
// test rounding up with the bits at different offsets to the BigDigits
|
||||
|
@ -499,7 +506,7 @@ fn test_convert_f64() {
|
|||
for _ in 0..128 {
|
||||
assert_eq!(b.to_f64(), Some(f));
|
||||
f *= 2.0;
|
||||
b <<= 1;
|
||||
b = b << 1;
|
||||
}
|
||||
|
||||
// rounding
|
||||
|
@ -527,16 +534,16 @@ fn test_convert_f64() {
|
|||
assert_eq!(BigInt::from_f64(f64::NEG_INFINITY), None);
|
||||
|
||||
// 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 + 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) - 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() << 1024u16).to_f64(), None);
|
||||
assert_eq!((-((BigInt::one() << 1024u16) - 1u8)).to_f64(), None);
|
||||
assert_eq!((-(BigInt::one() << 1024u16)).to_f64(), None);
|
||||
assert_eq!(((BigInt::one() << 1024) - BigInt::one()).to_f64(), None);
|
||||
assert_eq!((BigInt::one() << 1024).to_f64(), None);
|
||||
assert_eq!((-((BigInt::one() << 1024) - BigInt::one())).to_f64(), None);
|
||||
assert_eq!((-(BigInt::one() << 1024)).to_f64(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -571,6 +578,7 @@ fn test_convert_from_uint() {
|
|||
check!(u16, BigInt::from_slice(Plus, &[u16::MAX as u32]));
|
||||
check!(u32, BigInt::from_slice(Plus, &[u32::MAX]));
|
||||
check!(u64, BigInt::from_slice(Plus, &[u32::MAX, u32::MAX]));
|
||||
#[cfg(has_i128)]
|
||||
check!(
|
||||
u128,
|
||||
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(Plus, &[u32::MAX, i32::MAX as u32])
|
||||
);
|
||||
#[cfg(has_i128)]
|
||||
check!(
|
||||
i128,
|
||||
BigInt::from_slice(Minus, &[0, 0, 0, 1 << 31]),
|
||||
|
@ -650,7 +659,7 @@ fn test_add() {
|
|||
assert_op!(a + nc == nb);
|
||||
assert_op!(b + nc == na);
|
||||
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!(b += a == c);
|
||||
|
@ -659,7 +668,7 @@ fn test_add() {
|
|||
assert_assign_op!(a += nc == nb);
|
||||
assert_assign_op!(b += nc == na);
|
||||
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!(a - nb == c);
|
||||
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 -= b == a);
|
||||
|
@ -688,7 +697,7 @@ fn test_sub() {
|
|||
assert_assign_op!(b -= na == c);
|
||||
assert_assign_op!(a -= nb == c);
|
||||
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 check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) {
|
||||
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() {
|
||||
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]
|
||||
fn test_checked_add() {
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -899,7 +859,7 @@ fn test_checked_add() {
|
|||
assert!(a.checked_add(&(-&c)).unwrap() == (-&b));
|
||||
assert!(b.checked_add(&(-&c)).unwrap() == (-&a));
|
||||
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!(a.checked_sub(&(-&b)).unwrap() == c);
|
||||
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();
|
||||
|
||||
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);
|
||||
|
@ -1003,8 +960,6 @@ fn test_lcm() {
|
|||
let big_c: BigInt = FromPrimitive::from_isize(c).unwrap();
|
||||
|
||||
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);
|
||||
|
@ -1018,78 +973,6 @@ fn test_lcm() {
|
|||
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]
|
||||
fn test_abs_sub() {
|
||||
let zero: BigInt = Zero::zero();
|
||||
|
@ -1139,7 +1022,7 @@ fn test_from_str_radix() {
|
|||
#[test]
|
||||
fn test_lower_hex() {
|
||||
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}", hello), "-48656c6c6f20776f726c6421");
|
||||
|
@ -1149,7 +1032,7 @@ fn test_lower_hex() {
|
|||
#[test]
|
||||
fn test_upper_hex() {
|
||||
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}", hello), "-48656C6C6F20776F726C6421");
|
||||
|
@ -1159,7 +1042,7 @@ fn test_upper_hex() {
|
|||
#[test]
|
||||
fn test_binary() {
|
||||
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!(
|
||||
|
@ -1172,7 +1055,7 @@ fn test_binary() {
|
|||
#[test]
|
||||
fn test_octal() {
|
||||
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}", hello), "-22062554330674403566756233062041");
|
||||
|
@ -1182,7 +1065,7 @@ fn test_octal() {
|
|||
#[test]
|
||||
fn test_display() {
|
||||
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!("{}", hello), "-22405534230753963835153736737");
|
||||
|
@ -1205,6 +1088,25 @@ fn test_negative_shr() {
|
|||
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]
|
||||
fn test_iter_sum() {
|
||||
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
||||
|
@ -1218,8 +1120,8 @@ fn test_iter_sum() {
|
|||
FromPrimitive::from_i32(-7).unwrap(),
|
||||
];
|
||||
|
||||
assert_eq!(result, data.iter().sum::<BigInt>());
|
||||
assert_eq!(result, data.into_iter().sum::<BigInt>());
|
||||
assert_eq!(result, data.iter().sum());
|
||||
assert_eq!(result, data.into_iter().sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1237,8 +1139,8 @@ fn test_iter_product() {
|
|||
* data.get(3).unwrap()
|
||||
* data.get(4).unwrap();
|
||||
|
||||
assert_eq!(result, data.iter().product::<BigInt>());
|
||||
assert_eq!(result, data.into_iter().product::<BigInt>());
|
||||
assert_eq!(result, data.iter().product());
|
||||
assert_eq!(result, data.into_iter().product());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1246,8 +1148,8 @@ fn test_iter_sum_generic() {
|
|||
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
||||
let data = vec![-1000000, -200000, -30000, -4000, -500, -60, -7];
|
||||
|
||||
assert_eq!(result, data.iter().sum::<BigInt>());
|
||||
assert_eq!(result, data.into_iter().sum::<BigInt>());
|
||||
assert_eq!(result, data.iter().sum());
|
||||
assert_eq!(result, data.into_iter().sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1259,8 +1161,8 @@ fn test_iter_product_generic() {
|
|||
* data[3].to_bigint().unwrap()
|
||||
* data[4].to_bigint().unwrap();
|
||||
|
||||
assert_eq!(result, data.iter().product::<BigInt>());
|
||||
assert_eq!(result, data.into_iter().product::<BigInt>());
|
||||
assert_eq!(result, data.iter().product());
|
||||
assert_eq!(result, data.into_iter().product());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1272,15 +1174,15 @@ fn test_pow() {
|
|||
let minus_two = BigInt::from(-2i32);
|
||||
macro_rules! check {
|
||||
($t:ty) => {
|
||||
assert_eq!(Pow::pow(&two, 0 as $t), one);
|
||||
assert_eq!(Pow::pow(&two, 1 as $t), two);
|
||||
assert_eq!(Pow::pow(&two, 2 as $t), four);
|
||||
assert_eq!(Pow::pow(&two, 3 as $t), eight);
|
||||
assert_eq!(Pow::pow(&two, &(3 as $t)), eight);
|
||||
assert_eq!(Pow::pow(&minus_two, 0 as $t), one, "-2^0");
|
||||
assert_eq!(Pow::pow(&minus_two, 1 as $t), minus_two, "-2^1");
|
||||
assert_eq!(Pow::pow(&minus_two, 2 as $t), four, "-2^2");
|
||||
assert_eq!(Pow::pow(&minus_two, 3 as $t), -&eight, "-2^3");
|
||||
assert_eq!(two.pow(0 as $t), one);
|
||||
assert_eq!(two.pow(1 as $t), two);
|
||||
assert_eq!(two.pow(2 as $t), four);
|
||||
assert_eq!(two.pow(3 as $t), eight);
|
||||
assert_eq!(two.pow(&(3 as $t)), eight);
|
||||
assert_eq!(minus_two.pow(0 as $t), one, "-2^0");
|
||||
assert_eq!(minus_two.pow(1 as $t), minus_two, "-2^1");
|
||||
assert_eq!(minus_two.pow(2 as $t), four, "-2^2");
|
||||
assert_eq!(minus_two.pow(3 as $t), -&eight, "-2^3");
|
||||
};
|
||||
}
|
||||
check!(u8);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
|
||||
use num_bigint::{BigInt, Sign, ToBigInt};
|
||||
use num_traits::ToPrimitive;
|
||||
use std::{i32, i64, u32};
|
||||
|
@ -8,7 +11,7 @@ enum ValueVec {
|
|||
M(&'static [u32]),
|
||||
}
|
||||
|
||||
use crate::ValueVec::*;
|
||||
use ValueVec::*;
|
||||
|
||||
impl ToBigInt for ValueVec {
|
||||
fn to_bigint(&self) -> Option<BigInt> {
|
||||
|
@ -21,7 +24,7 @@ impl ToBigInt for ValueVec {
|
|||
}
|
||||
|
||||
// a, !a
|
||||
const NOT_VALUES: &[(ValueVec, ValueVec)] = &[
|
||||
const NOT_VALUES: &'static [(ValueVec, ValueVec)] = &[
|
||||
(N, M(&[1])),
|
||||
(P(&[1]), M(&[2])),
|
||||
(P(&[2]), M(&[3])),
|
||||
|
@ -33,7 +36,7 @@ const NOT_VALUES: &[(ValueVec, ValueVec)] = &[
|
|||
];
|
||||
|
||||
// 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, P(&[1]), N, P(&[1]), P(&[1])),
|
||||
(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;
|
||||
|
||||
// some corner cases
|
||||
const I64_VALUES: &[i64] = &[
|
||||
const I64_VALUES: &'static [i64] = &[
|
||||
i64::MIN,
|
||||
i64::MIN + 1,
|
||||
i64::MIN + 2,
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_bigint::Sign::Plus;
|
||||
use num_traits::{Signed, ToPrimitive, Zero};
|
||||
|
@ -5,7 +8,7 @@ use num_traits::{Signed, ToPrimitive, Zero};
|
|||
use std::ops::Neg;
|
||||
|
||||
mod consts;
|
||||
use crate::consts::*;
|
||||
use consts::*;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -15,7 +18,6 @@ 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);
|
||||
assert_signed_scalar_assign_op!(x += y == z);
|
||||
}
|
||||
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -41,7 +43,6 @@ 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);
|
||||
assert_signed_scalar_assign_op!(x -= y == z);
|
||||
}
|
||||
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -67,7 +68,6 @@ 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);
|
||||
assert_signed_scalar_assign_op!(x *= y == z);
|
||||
}
|
||||
|
||||
for elm in MUL_TRIPLES.iter() {
|
||||
|
@ -93,23 +93,20 @@ fn test_scalar_div_rem() {
|
|||
if !r.is_zero() {
|
||||
assert_eq!(r.sign(), a.sign());
|
||||
}
|
||||
assert!(r.abs() <= BigInt::from(b));
|
||||
assert!(r.abs() <= From::from(b));
|
||||
assert!(*a == b * &q + &r);
|
||||
assert!(q == *ans_q);
|
||||
assert!(r == *ans_r);
|
||||
|
||||
let b = BigInt::from(b);
|
||||
let (a, ans_q, ans_r) = (a.clone(), ans_q.clone(), ans_r.clone());
|
||||
assert_signed_scalar_op!(a / b == ans_q);
|
||||
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 (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);
|
||||
|
||||
let nb = -b;
|
||||
assert_signed_scalar_op!(a / nb == -ans_q.clone());
|
||||
assert_signed_scalar_op!(a % nb == ans_r);
|
||||
assert_signed_scalar_assign_op!(a /= nb == -ans_q.clone());
|
||||
assert_signed_scalar_assign_op!(a %= nb == 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) {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
extern crate num_bigint;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
|
||||
use num_bigint::Sign::Plus;
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
use num_bigint::{BigUint, ToBigUint};
|
||||
|
@ -10,16 +14,17 @@ use std::i64;
|
|||
use std::iter::repeat;
|
||||
use std::str::FromStr;
|
||||
use std::{f32, f64};
|
||||
#[cfg(has_i128)]
|
||||
use std::{i128, u128};
|
||||
use std::{u16, u32, u64, u8, usize};
|
||||
|
||||
use num_traits::{
|
||||
pow, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Num, One, Pow, ToPrimitive,
|
||||
Zero,
|
||||
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Float, FromPrimitive, Num, One, Pow,
|
||||
ToPrimitive, Zero,
|
||||
};
|
||||
|
||||
mod consts;
|
||||
use crate::consts::*;
|
||||
use consts::*;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -36,7 +41,7 @@ fn test_from_bytes_be() {
|
|||
check("AA", "16705");
|
||||
check("AB", "16706");
|
||||
check("Hello world!", "22405534230753963835153736737");
|
||||
assert_eq!(BigUint::from_bytes_be(&[]), BigUint::zero());
|
||||
assert_eq!(BigUint::from_bytes_be(&[]), Zero::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -69,7 +74,7 @@ fn test_from_bytes_le() {
|
|||
check("AA", "16705");
|
||||
check("BA", "16706");
|
||||
check("!dlrow olleH", "22405534230753963835153736737");
|
||||
assert_eq!(BigUint::from_bytes_le(&[]), BigUint::zero());
|
||||
assert_eq!(BigUint::from_bytes_le(&[]), Zero::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -135,7 +140,7 @@ fn hash<T: Hash>(x: &T) -> u64 {
|
|||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
use crate::hash;
|
||||
use hash;
|
||||
|
||||
let a = BigUint::new(vec![]);
|
||||
let b = BigUint::new(vec![0]);
|
||||
|
@ -149,7 +154,13 @@ fn test_hash() {
|
|||
}
|
||||
|
||||
// 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], &[0, 1, 1], &[0, 0, 1], &[1, 1, 1], &[1, 1]),
|
||||
|
@ -531,6 +542,7 @@ fn test_convert_i64() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn test_convert_i128() {
|
||||
fn check(b1: BigUint, i: i128) {
|
||||
let b2: BigUint = FromPrimitive::from_i128(i).unwrap();
|
||||
|
@ -579,6 +591,7 @@ fn test_convert_u64() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn test_convert_u128() {
|
||||
fn check(b1: BigUint, u: u128) {
|
||||
let b2: BigUint = FromPrimitive::from_u128(u).unwrap();
|
||||
|
@ -602,7 +615,6 @@ fn test_convert_u128() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn test_convert_f32() {
|
||||
fn check(b1: &BigUint, f: f32) {
|
||||
let b2 = BigUint::from_f32(f).unwrap();
|
||||
|
@ -612,14 +624,14 @@ fn test_convert_f32() {
|
|||
|
||||
check(&BigUint::zero(), 0.0);
|
||||
check(&BigUint::one(), 1.0);
|
||||
check(&BigUint::from(u16::MAX), pow(2.0_f32, 16) - 1.0);
|
||||
check(&BigUint::from(1u64 << 32), pow(2.0_f32, 32));
|
||||
check(&BigUint::from_slice(&[0, 0, 1]), pow(2.0_f32, 64));
|
||||
check(&BigUint::from(u16::MAX), 2.0.powi(16) - 1.0);
|
||||
check(&BigUint::from(1u64 << 32), 2.0.powi(32));
|
||||
check(&BigUint::from_slice(&[0, 0, 1]), 2.0.powi(64));
|
||||
check(
|
||||
&((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);
|
||||
|
||||
// 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 {
|
||||
check(&b, f);
|
||||
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
|
||||
|
@ -643,7 +655,7 @@ fn test_convert_f32() {
|
|||
for _ in 0..64 {
|
||||
assert_eq!(b.to_f32(), Some(f));
|
||||
f *= 2.0;
|
||||
b <<= 1;
|
||||
b = b << 1;
|
||||
}
|
||||
|
||||
// rounding
|
||||
|
@ -671,16 +683,15 @@ fn test_convert_f32() {
|
|||
assert_eq!(BigUint::from_f32(f32::MIN), None);
|
||||
|
||||
// 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 + 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() << 128u8).to_f32(), None);
|
||||
assert_eq!(((BigUint::one() << 128) - BigUint::one()).to_f32(), None);
|
||||
assert_eq!((BigUint::one() << 128).to_f32(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn test_convert_f64() {
|
||||
fn check(b1: &BigUint, f: f64) {
|
||||
let b2 = BigUint::from_f64(f).unwrap();
|
||||
|
@ -690,14 +701,14 @@ fn test_convert_f64() {
|
|||
|
||||
check(&BigUint::zero(), 0.0);
|
||||
check(&BigUint::one(), 1.0);
|
||||
check(&BigUint::from(u32::MAX), pow(2.0_f64, 32) - 1.0);
|
||||
check(&BigUint::from(1u64 << 32), pow(2.0_f64, 32));
|
||||
check(&BigUint::from_slice(&[0, 0, 1]), pow(2.0_f64, 64));
|
||||
check(&BigUint::from(u32::MAX), 2.0.powi(32) - 1.0);
|
||||
check(&BigUint::from(1u64 << 32), 2.0.powi(32));
|
||||
check(&BigUint::from_slice(&[0, 0, 1]), 2.0.powi(64));
|
||||
check(
|
||||
&((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);
|
||||
|
||||
// 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 {
|
||||
check(&b, f);
|
||||
f *= 2.0;
|
||||
b <<= 1;
|
||||
b = b << 1;
|
||||
}
|
||||
|
||||
// test rounding up with the bits at different offsets to the BigDigits
|
||||
|
@ -716,7 +727,7 @@ fn test_convert_f64() {
|
|||
for _ in 0..128 {
|
||||
assert_eq!(b.to_f64(), Some(f));
|
||||
f *= 2.0;
|
||||
b <<= 1;
|
||||
b = b << 1;
|
||||
}
|
||||
|
||||
// rounding
|
||||
|
@ -744,12 +755,12 @@ fn test_convert_f64() {
|
|||
assert_eq!(BigUint::from_f64(f64::MIN), None);
|
||||
|
||||
// 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 + 1u8).to_f64(), None);
|
||||
assert_eq!((big_num + BigUint::one()).to_f64(), None);
|
||||
|
||||
assert_eq!(((BigUint::one() << 1024u16) - 1u8).to_f64(), None);
|
||||
assert_eq!((BigUint::one() << 1024u16).to_f64(), None);
|
||||
assert_eq!(((BigInt::one() << 1024) - BigInt::one()).to_f64(), None);
|
||||
assert_eq!((BigUint::one() << 1024).to_f64(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -780,6 +791,7 @@ fn test_convert_from_uint() {
|
|||
check!(u16, BigUint::from_slice(&[u16::MAX as u32]));
|
||||
check!(u32, BigUint::from_slice(&[u32::MAX]));
|
||||
check!(u64, BigUint::from_slice(&[u32::MAX, u32::MAX]));
|
||||
#[cfg(has_i128)]
|
||||
check!(
|
||||
u128,
|
||||
BigUint::from_slice(&[u32::MAX, u32::MAX, u32::MAX, u32::MAX])
|
||||
|
@ -860,17 +872,17 @@ fn test_div_rem() {
|
|||
|
||||
if !a.is_zero() {
|
||||
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 == BigUint::zero());
|
||||
assert_eq!(c.div_rem(&a), (b.clone(), BigUint::zero()));
|
||||
assert_assign_op!(c %= a == Zero::zero());
|
||||
assert_eq!(c.div_rem(&a), (b.clone(), Zero::zero()));
|
||||
}
|
||||
if !b.is_zero() {
|
||||
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 == BigUint::zero());
|
||||
assert_eq!(c.div_rem(&b), (a.clone(), BigUint::zero()));
|
||||
assert_assign_op!(c %= b == Zero::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]
|
||||
fn test_checked_add() {
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -1021,7 +996,6 @@ fn test_gcd() {
|
|||
let big_c: BigUint = FromPrimitive::from_usize(c).unwrap();
|
||||
|
||||
assert_eq!(big_a.gcd(&big_b), big_c);
|
||||
assert_eq!(big_a.gcd_lcm(&big_b).0, big_c);
|
||||
}
|
||||
|
||||
check(10, 2, 2);
|
||||
|
@ -1039,7 +1013,6 @@ fn test_lcm() {
|
|||
let big_c: BigUint = FromPrimitive::from_usize(c).unwrap();
|
||||
|
||||
assert_eq!(big_a.lcm(&big_b), big_c);
|
||||
assert_eq!(big_a.gcd_lcm(&big_b).1, big_c);
|
||||
}
|
||||
|
||||
check(0, 0, 0);
|
||||
|
@ -1051,30 +1024,6 @@ fn test_lcm() {
|
|||
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]
|
||||
fn test_is_even() {
|
||||
let one: BigUint = FromStr::from_str("1").unwrap();
|
||||
|
@ -1087,8 +1036,8 @@ fn test_is_even() {
|
|||
assert!(thousand.is_even());
|
||||
assert!(big.is_even());
|
||||
assert!(bigger.is_odd());
|
||||
assert!((&one << 64u8).is_even());
|
||||
assert!(((&one << 64u8) + one).is_odd());
|
||||
assert!((&one << 64).is_even());
|
||||
assert!(((&one << 64) + one).is_odd());
|
||||
}
|
||||
|
||||
fn to_str_pairs() -> Vec<(BigUint, Vec<(u32, String)>)> {
|
||||
|
@ -1216,7 +1165,7 @@ fn test_to_str_radix() {
|
|||
|
||||
#[test]
|
||||
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"ffffeeffbb",
|
||||
|
@ -1566,6 +1515,9 @@ fn test_from_str_radix() {
|
|||
|
||||
#[test]
|
||||
fn test_all_str_radix() {
|
||||
#[allow(deprecated, unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
let n = BigUint::new((0..10).collect());
|
||||
for radix in 2..37 {
|
||||
let s = n.to_str_radix(radix);
|
||||
|
@ -1581,7 +1533,7 @@ fn test_all_str_radix() {
|
|||
#[test]
|
||||
fn test_lower_hex() {
|
||||
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}", hello), "48656c6c6f20776f726c6421");
|
||||
|
@ -1591,7 +1543,7 @@ fn test_lower_hex() {
|
|||
#[test]
|
||||
fn test_upper_hex() {
|
||||
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}", hello), "48656C6C6F20776F726C6421");
|
||||
|
@ -1601,7 +1553,7 @@ fn test_upper_hex() {
|
|||
#[test]
|
||||
fn test_binary() {
|
||||
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!(
|
||||
|
@ -1614,7 +1566,7 @@ fn test_binary() {
|
|||
#[test]
|
||||
fn test_octal() {
|
||||
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}", hello), "22062554330674403566756233062041");
|
||||
|
@ -1624,7 +1576,7 @@ fn test_octal() {
|
|||
#[test]
|
||||
fn test_display() {
|
||||
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!("{}", hello), "22405534230753963835153736737");
|
||||
|
@ -1635,18 +1587,21 @@ fn test_display() {
|
|||
fn test_factor() {
|
||||
fn factor(n: usize) -> BigUint {
|
||||
let mut f: BigUint = One::one();
|
||||
for i in 2..=n {
|
||||
for i in 2..n + 1 {
|
||||
// FIXME(#5992): assignment operator overloads
|
||||
// f *= FromPrimitive::from_usize(i);
|
||||
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
||||
f *= bu;
|
||||
f = f * bu;
|
||||
}
|
||||
f
|
||||
return f;
|
||||
}
|
||||
|
||||
fn check(n: usize, s: &str) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1668,7 +1623,7 @@ fn test_bits() {
|
|||
let n: BigUint = BigUint::from_str_radix("4000000000", 16).unwrap();
|
||||
assert_eq!(n.bits(), 39);
|
||||
let one: BigUint = One::one();
|
||||
assert_eq!((one << 426u16).bits(), 427);
|
||||
assert_eq!((one << 426).bits(), 427);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1684,8 +1639,8 @@ fn test_iter_sum() {
|
|||
FromPrimitive::from_u32(7).unwrap(),
|
||||
];
|
||||
|
||||
assert_eq!(result, data.iter().sum::<BigUint>());
|
||||
assert_eq!(result, data.into_iter().sum::<BigUint>());
|
||||
assert_eq!(result, data.iter().sum());
|
||||
assert_eq!(result, data.into_iter().sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1703,8 +1658,8 @@ fn test_iter_product() {
|
|||
* data.get(3).unwrap()
|
||||
* data.get(4).unwrap();
|
||||
|
||||
assert_eq!(result, data.iter().product::<BigUint>());
|
||||
assert_eq!(result, data.into_iter().product::<BigUint>());
|
||||
assert_eq!(result, data.iter().product());
|
||||
assert_eq!(result, data.into_iter().product());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1712,8 +1667,8 @@ fn test_iter_sum_generic() {
|
|||
let result: BigUint = FromPrimitive::from_isize(1234567).unwrap();
|
||||
let data = vec![1000000_u32, 200000, 30000, 4000, 500, 60, 7];
|
||||
|
||||
assert_eq!(result, data.iter().sum::<BigUint>());
|
||||
assert_eq!(result, data.into_iter().sum::<BigUint>());
|
||||
assert_eq!(result, data.iter().sum());
|
||||
assert_eq!(result, data.into_iter().sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1725,8 +1680,8 @@ fn test_iter_product_generic() {
|
|||
* data[3].to_biguint().unwrap()
|
||||
* data[4].to_biguint().unwrap();
|
||||
|
||||
assert_eq!(result, data.iter().product::<BigUint>());
|
||||
assert_eq!(result, data.into_iter().product::<BigUint>());
|
||||
assert_eq!(result, data.iter().product());
|
||||
assert_eq!(result, data.into_iter().product());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1739,19 +1694,20 @@ fn test_pow() {
|
|||
let twentyfourtyeight = BigUint::from(2048u32);
|
||||
macro_rules! check {
|
||||
($t:ty) => {
|
||||
assert_eq!(Pow::pow(&two, 0 as $t), one);
|
||||
assert_eq!(Pow::pow(&two, 1 as $t), two);
|
||||
assert_eq!(Pow::pow(&two, 2 as $t), four);
|
||||
assert_eq!(Pow::pow(&two, 3 as $t), eight);
|
||||
assert_eq!(Pow::pow(&two, 10 as $t), tentwentyfour);
|
||||
assert_eq!(Pow::pow(&two, 11 as $t), twentyfourtyeight);
|
||||
assert_eq!(Pow::pow(&two, &(11 as $t)), twentyfourtyeight);
|
||||
assert_eq!(two.pow(0 as $t), one);
|
||||
assert_eq!(two.pow(1 as $t), two);
|
||||
assert_eq!(two.pow(2 as $t), four);
|
||||
assert_eq!(two.pow(3 as $t), eight);
|
||||
assert_eq!(two.pow(10 as $t), tentwentyfour);
|
||||
assert_eq!(two.pow(11 as $t), twentyfourtyeight);
|
||||
assert_eq!(two.pow(&(11 as $t)), twentyfourtyeight);
|
||||
};
|
||||
}
|
||||
check!(u8);
|
||||
check!(u16);
|
||||
check!(u32);
|
||||
check!(u64);
|
||||
check!(u128);
|
||||
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_traits::{ToPrimitive, Zero};
|
||||
|
||||
mod consts;
|
||||
use crate::consts::*;
|
||||
use consts::*;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
@ -12,7 +15,6 @@ 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);
|
||||
assert_unsigned_scalar_assign_op!(x += y == z);
|
||||
}
|
||||
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -31,7 +33,6 @@ 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);
|
||||
assert_unsigned_scalar_assign_op!(x -= y == z);
|
||||
}
|
||||
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -50,7 +51,6 @@ 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);
|
||||
assert_unsigned_scalar_assign_op!(x *= y == z);
|
||||
}
|
||||
|
||||
for elm in MUL_TRIPLES.iter() {
|
||||
|
@ -66,8 +66,8 @@ fn test_scalar_mul() {
|
|||
|
||||
#[test]
|
||||
fn test_scalar_rem_noncommutative() {
|
||||
assert_eq!(5u8 % BigUint::from(7u8), BigUint::from(5u8));
|
||||
assert_eq!(BigUint::from(5u8) % 7u8, BigUint::from(5u8));
|
||||
assert_eq!(5u8 % BigUint::from(7u8), 5u8.into());
|
||||
assert_eq!(BigUint::from(5u8) % 7u8, 5u8.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -76,8 +76,6 @@ fn test_scalar_div_rem() {
|
|||
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);
|
||||
assert_unsigned_scalar_assign_op!(x /= y == z);
|
||||
assert_unsigned_scalar_assign_op!(x %= y == r);
|
||||
}
|
||||
|
||||
for elm in MUL_TRIPLES.iter() {
|
||||
|
@ -106,8 +104,6 @@ fn test_scalar_div_rem() {
|
|||
check(&a, &b, &c, &d);
|
||||
assert_unsigned_scalar_op!(a / b == c);
|
||||
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 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], &[2]),
|
||||
|
@ -17,7 +17,7 @@ pub const SUM_TRIPLES: &[(&[u32], &[u32], &[u32])] = &[
|
|||
];
|
||||
|
||||
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], &[]),
|
||||
(&[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]),
|
||||
];
|
||||
|
||||
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]),
|
||||
(&[3], &[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 {
|
||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
||||
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 {
|
||||
($left:ident $op:tt $right:ident == $expected:expr) => {
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
/// 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 = "\
|
||||
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";
|
||||
extern crate num_bigint;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
|
||||
static BIG_E: &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";
|
||||
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: &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_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: &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";
|
||||
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;
|
||||
|
@ -72,24 +76,11 @@ mod biguint {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_modpow_single() {
|
||||
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);
|
||||
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]
|
||||
|
@ -111,13 +102,13 @@ mod biguint {
|
|||
mod bigint {
|
||||
use num_bigint::BigInt;
|
||||
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(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);
|
||||
assert!(even_modpow.abs() < even_m.abs());
|
||||
assert_eq!(&even_modpow.mod_floor(&m), r);
|
||||
|
@ -131,18 +122,12 @@ mod bigint {
|
|||
let m: BigInt = m.into();
|
||||
let r: BigInt = r.into();
|
||||
|
||||
let neg_b_r = if e.is_odd() {
|
||||
(-&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);
|
||||
let neg_r = if r.is_zero() { BigInt::zero() } else { &m - &r };
|
||||
|
||||
check(&b, &e, &m, &r);
|
||||
check(&-&b, &e, &m, &neg_b_r);
|
||||
check(&b, &e, &-&m, &neg_m_r);
|
||||
check(&-b, &e, &-&m, &neg_bm_r);
|
||||
check(&-&b, &e, &m, &neg_r);
|
||||
check(&b, &e, &-&m, &-neg_r);
|
||||
check(&-b, &e, &-m, &-r);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -151,22 +136,6 @@ mod bigint {
|
|||
check_modpow(0, 15, 11, 0);
|
||||
check_modpow(3, 7, 11, 9);
|
||||
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]
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
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, Zero};
|
||||
use num_traits::{One, Pow, Zero};
|
||||
use std::{i32, u32};
|
||||
|
||||
fn check<T: Into<BigUint>>(x: T, n: u32) {
|
||||
|
@ -81,7 +88,7 @@ mod biguint {
|
|||
let x = BigUint::one() << LOG2;
|
||||
|
||||
// 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 expected = BigUint::one() << (LOG2 / n as usize);
|
||||
assert_eq!(x.nth_root(n), expected);
|
||||
|
@ -94,6 +101,25 @@ mod biguint {
|
|||
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
|
||||
|
@ -108,13 +134,13 @@ mod biguint {
|
|||
check(x.clone(), 2);
|
||||
check(x.clone(), 3);
|
||||
check(x.clone(), 10);
|
||||
check(x, 100);
|
||||
check(x.clone(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
mod bigint {
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::Signed;
|
||||
use num_traits::{Pow, Signed};
|
||||
|
||||
fn check(x: i64, n: u32) {
|
||||
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
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# 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
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
|
@ -12,10 +12,9 @@
|
|||
|
||||
[package]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
version = "0.1.39"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
||||
description = "Integer traits and functions"
|
||||
homepage = "https://github.com/rust-num/num-integer"
|
||||
documentation = "https://docs.rs/num-integer"
|
||||
|
@ -27,10 +26,8 @@ repository = "https://github.com/rust-num/num-integer"
|
|||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
[dependencies.num-traits]
|
||||
version = "0.2.11"
|
||||
version = "0.2.4"
|
||||
default-features = false
|
||||
[build-dependencies.autocfg]
|
||||
version = "1"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
[![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)
|
||||
[![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)
|
||||
[![build status](https://github.com/rust-num/num-integer/workflows/master/badge.svg)](https://github.com/rust-num/num-integer/actions)
|
||||
![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
|
||||
[![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.
|
||||
|
||||
|
|
|
@ -1,43 +1,4 @@
|
|||
# Release 0.1.43 (2020-06-11)
|
||||
|
||||
- [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)
|
||||
# Release 0.1.39
|
||||
|
||||
- [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9],
|
||||
calculating an `Integer`'s principal roots rounded toward zero.
|
||||
|
@ -46,7 +7,7 @@
|
|||
|
||||
[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]
|
||||
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
|
||||
|
||||
# Release 0.1.37 (2018-05-10)
|
||||
# Release 0.1.37
|
||||
|
||||
- [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust
|
||||
1.26, enabled by the new `i128` crate feature.
|
||||
|
@ -65,7 +26,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].
|
||||
- [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 {}
|
||||
|
||||
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)
|
||||
where
|
||||
|
|
|
@ -1,14 +1,35 @@
|
|||
extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
let ac = autocfg::new();
|
||||
if ac.probe_type("i128") {
|
||||
if probe("fn main() { 0i128; }") {
|
||||
println!("cargo:rustc-cfg=has_i128");
|
||||
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
||||
panic!("i128 support was not detected!");
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/num-integer/0.1")]
|
||||
|
||||
#![no_std]
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
extern crate num_traits as traits;
|
||||
|
||||
use core::mem;
|
||||
use core::ops::Add;
|
||||
use core::mem;
|
||||
|
||||
use traits::{Num, Signed, Zero};
|
||||
use traits::{Num, Signed};
|
||||
|
||||
mod roots;
|
||||
pub use roots::Roots;
|
||||
pub use roots::{cbrt, nth_root, sqrt};
|
||||
|
||||
mod average;
|
||||
pub use average::Average;
|
||||
pub use average::{average_ceil, average_floor};
|
||||
pub use roots::{sqrt, cbrt, nth_root};
|
||||
|
||||
pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
||||
/// Floored integer division.
|
||||
|
@ -77,31 +74,6 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
|||
/// ~~~
|
||||
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).
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -121,93 +93,9 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq {
|
|||
/// # use num_integer::Integer;
|
||||
/// assert_eq!(7.lcm(&3), 21);
|
||||
/// assert_eq!(2.lcm(&4), 4);
|
||||
/// assert_eq!(0.lcm(&0), 0);
|
||||
/// ~~~
|
||||
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.
|
||||
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));
|
||||
/// ~~~
|
||||
#[inline]
|
||||
fn div_rem(&self, other: &Self) -> (Self, Self);
|
||||
|
||||
/// 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) {
|
||||
(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
|
||||
|
@ -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) {
|
||||
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
|
||||
/// result is always positive.
|
||||
|
@ -397,26 +207,18 @@ pub fn lcm<T: Integer>(x: T, y: T) -> T {
|
|||
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 {
|
||||
($T:ty, $test_mod:ident) => {
|
||||
($T:ty, $test_mod:ident) => (
|
||||
impl Integer for $T {
|
||||
/// Floored integer division
|
||||
#[inline]
|
||||
fn div_floor(&self, other: &Self) -> Self {
|
||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||
let (d, r) = self.div_rem(other);
|
||||
if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
|
||||
d - 1
|
||||
} else {
|
||||
d
|
||||
match self.div_rem(other) {
|
||||
(d, r) if (r > 0 && *other < 0)
|
||||
|| (r < 0 && *other > 0) => d - 1,
|
||||
(d, _) => d,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,11 +227,10 @@ macro_rules! impl_integer_for_isize {
|
|||
fn mod_floor(&self, other: &Self) -> Self {
|
||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||
let r = *self % *other;
|
||||
if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
|
||||
r + *other
|
||||
} else {
|
||||
r
|
||||
match *self % *other {
|
||||
r if (r > 0 && *other < 0)
|
||||
|| (r < 0 && *other > 0) => r + *other,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,21 +239,10 @@ macro_rules! impl_integer_for_isize {
|
|||
fn div_mod_floor(&self, other: &Self) -> (Self, Self) {
|
||||
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
|
||||
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
|
||||
let (d, r) = self.div_rem(other);
|
||||
if (r > 0 && *other < 0) || (r < 0 && *other > 0) {
|
||||
(d - 1, r + *other)
|
||||
} else {
|
||||
(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
|
||||
match self.div_rem(other) {
|
||||
(d, r) if (r > 0 && *other < 0)
|
||||
|| (r < 0 && *other > 0) => (d - 1, r + *other),
|
||||
(d, r) => (d, r),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,9 +253,7 @@ macro_rules! impl_integer_for_isize {
|
|||
// Use Stein's algorithm
|
||||
let mut m = *self;
|
||||
let mut n = *other;
|
||||
if m == 0 || n == 0 {
|
||||
return (m | n).abs();
|
||||
}
|
||||
if m == 0 || n == 0 { return (m | n).abs() }
|
||||
|
||||
// find common factors of 2
|
||||
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)
|
||||
// The call to .abs() causes a panic in debug mode
|
||||
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
|
||||
|
@ -487,51 +275,24 @@ macro_rules! impl_integer_for_isize {
|
|||
n = n.abs();
|
||||
|
||||
// divide n and m by 2 until odd
|
||||
m >>= m.trailing_zeros();
|
||||
// m inside loop
|
||||
n >>= n.trailing_zeros();
|
||||
|
||||
while m != n {
|
||||
if m > n {
|
||||
m -= n;
|
||||
m >>= m.trailing_zeros();
|
||||
} else {
|
||||
n -= m;
|
||||
n >>= n.trailing_zeros();
|
||||
}
|
||||
while m != 0 {
|
||||
m >>= m.trailing_zeros();
|
||||
if n > m { mem::swap(&mut n, &mut m) }
|
||||
m -= n;
|
||||
}
|
||||
m << shift
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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)
|
||||
n << shift
|
||||
}
|
||||
|
||||
/// Calculates the Lowest Common Multiple (LCM) of the number and
|
||||
/// `other`.
|
||||
#[inline]
|
||||
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
|
||||
let lcm = (*self * (*other / gcd)).abs();
|
||||
(gcd, lcm)
|
||||
(*self * (*other / self.gcd(other))).abs()
|
||||
}
|
||||
|
||||
/// 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`
|
||||
#[inline]
|
||||
fn is_even(&self) -> bool {
|
||||
(*self) & 1 == 0
|
||||
}
|
||||
fn is_even(&self) -> bool { (*self) & 1 == 0 }
|
||||
|
||||
/// Returns `true` if the number is not divisible by `2`
|
||||
#[inline]
|
||||
fn is_odd(&self) -> bool {
|
||||
!self.is_even()
|
||||
}
|
||||
fn is_odd(&self) -> bool { !self.is_even() }
|
||||
|
||||
/// Simultaneous truncated integer division and modulus.
|
||||
#[inline]
|
||||
|
@ -567,8 +324,8 @@ macro_rules! impl_integer_for_isize {
|
|||
|
||||
#[cfg(test)]
|
||||
mod $test_mod {
|
||||
use core::mem;
|
||||
use Integer;
|
||||
use core::mem;
|
||||
|
||||
/// Checks that the division rule holds for:
|
||||
///
|
||||
|
@ -576,14 +333,14 @@ macro_rules! impl_integer_for_isize {
|
|||
/// - `d`: denominator (divisor)
|
||||
/// - `qr`: quotient and remainder
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div_rem() {
|
||||
fn test_nd_dr(nd: ($T, $T), qr: ($T, $T)) {
|
||||
let (n, d) = nd;
|
||||
fn test_nd_dr(nd: ($T,$T), qr: ($T,$T)) {
|
||||
let (n,d) = nd;
|
||||
let separate_div_rem = (n / d, n % d);
|
||||
let combined_div_rem = n.div_rem(&d);
|
||||
|
||||
|
@ -594,21 +351,21 @@ macro_rules! impl_integer_for_isize {
|
|||
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]
|
||||
fn test_div_mod_floor() {
|
||||
fn test_nd_dm(nd: ($T, $T), dm: ($T, $T)) {
|
||||
let (n, d) = nd;
|
||||
fn test_nd_dm(nd: ($T,$T), dm: ($T,$T)) {
|
||||
let (n,d) = nd;
|
||||
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
|
||||
let combined_div_mod_floor = n.div_mod_floor(&d);
|
||||
|
||||
|
@ -619,15 +376,15 @@ macro_rules! impl_integer_for_isize {
|
|||
test_division_rule(nd, combined_div_mod_floor);
|
||||
}
|
||||
|
||||
test_nd_dm((8, 3), (2, 2));
|
||||
test_nd_dm((8, -3), (-3, -1));
|
||||
test_nd_dm((-8, 3), (-3, 1));
|
||||
test_nd_dm((-8, -3), (2, -2));
|
||||
test_nd_dm(( 8, 3), ( 2, 2));
|
||||
test_nd_dm(( 8, -3), (-3, -1));
|
||||
test_nd_dm((-8, 3), (-3, 1));
|
||||
test_nd_dm((-8, -3), ( 2, -2));
|
||||
|
||||
test_nd_dm((1, 2), (0, 1));
|
||||
test_nd_dm((1, -2), (-1, -1));
|
||||
test_nd_dm((-1, 2), (-1, 1));
|
||||
test_nd_dm((-1, -2), (0, -1));
|
||||
test_nd_dm(( 1, 2), ( 0, 1));
|
||||
test_nd_dm(( 1, -2), (-1, -1));
|
||||
test_nd_dm((-1, 2), (-1, 1));
|
||||
test_nd_dm((-1, -2), ( 0, -1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -657,7 +414,7 @@ macro_rules! impl_integer_for_isize {
|
|||
// for i8
|
||||
for i 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
|
||||
let i = 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);
|
||||
}
|
||||
|
@ -716,49 +473,6 @@ macro_rules! impl_integer_for_isize {
|
|||
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]
|
||||
fn test_even() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
macro_rules! impl_integer_for_usize {
|
||||
($T:ty, $test_mod:ident) => {
|
||||
($T:ty, $test_mod:ident) => (
|
||||
impl Integer for $T {
|
||||
/// Unsigned integer division. Returns the same result as `div` (`/`).
|
||||
#[inline]
|
||||
|
@ -811,68 +525,34 @@ macro_rules! impl_integer_for_usize {
|
|||
*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`
|
||||
#[inline]
|
||||
fn gcd(&self, other: &Self) -> Self {
|
||||
// Use Stein's algorithm
|
||||
let mut m = *self;
|
||||
let mut n = *other;
|
||||
if m == 0 || n == 0 {
|
||||
return m | n;
|
||||
}
|
||||
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 >>= m.trailing_zeros();
|
||||
// m inside loop
|
||||
n >>= n.trailing_zeros();
|
||||
|
||||
while m != n {
|
||||
if m > n {
|
||||
m -= n;
|
||||
m >>= m.trailing_zeros();
|
||||
} else {
|
||||
n -= m;
|
||||
n >>= n.trailing_zeros();
|
||||
}
|
||||
while m != 0 {
|
||||
m >>= m.trailing_zeros();
|
||||
if n > m { mem::swap(&mut n, &mut m) }
|
||||
m -= n;
|
||||
}
|
||||
m << shift
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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)
|
||||
n << shift
|
||||
}
|
||||
|
||||
/// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
|
||||
#[inline]
|
||||
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);
|
||||
let lcm = *self * (*other / gcd);
|
||||
(gcd, lcm)
|
||||
*self * (*other / self.gcd(other))
|
||||
}
|
||||
|
||||
/// Deprecated, use `is_multiple_of` instead.
|
||||
|
@ -908,8 +588,8 @@ macro_rules! impl_integer_for_usize {
|
|||
|
||||
#[cfg(test)]
|
||||
mod $test_mod {
|
||||
use core::mem;
|
||||
use Integer;
|
||||
use core::mem;
|
||||
|
||||
#[test]
|
||||
fn test_div_mod_floor() {
|
||||
|
@ -945,7 +625,7 @@ macro_rules! impl_integer_for_usize {
|
|||
|
||||
for i 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
|
||||
let i = 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);
|
||||
}
|
||||
|
@ -968,15 +648,6 @@ macro_rules! impl_integer_for_usize {
|
|||
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]
|
||||
fn test_is_multiple_of() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
impl_integer_for_usize!(u8, test_integer_u8);
|
||||
|
@ -1021,8 +692,7 @@ pub struct IterBinomial<T> {
|
|||
}
|
||||
|
||||
impl<T> IterBinomial<T>
|
||||
where
|
||||
T: Integer,
|
||||
where T: Integer,
|
||||
{
|
||||
/// 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.
|
||||
pub fn new(n: T) -> IterBinomial<T> {
|
||||
IterBinomial {
|
||||
k: T::zero(),
|
||||
a: T::one(),
|
||||
n: n,
|
||||
k: T::zero(), a: T::one(), n: n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for IterBinomial<T>
|
||||
where
|
||||
T: Integer + Clone,
|
||||
where T: Integer + Clone
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
|
@ -1065,7 +732,7 @@ where
|
|||
multiply_and_divide(
|
||||
self.a.clone(),
|
||||
self.n.clone() - self.k.clone() + T::one(),
|
||||
self.k.clone(),
|
||||
self.k.clone()
|
||||
)
|
||||
} else {
|
||||
T::one()
|
||||
|
@ -1081,7 +748,7 @@ where
|
|||
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.
|
||||
let g = gcd(r.clone(), b.clone());
|
||||
r / g.clone() * (a / (b / g))
|
||||
r/g.clone() * (a / (b/g))
|
||||
}
|
||||
|
||||
/// Calculate the binomial coefficient.
|
||||
|
@ -1125,8 +792,7 @@ pub fn binomial<T: Integer + Clone>(mut n: T, k: T) -> T {
|
|||
|
||||
/// Calculate the multinomial coefficient.
|
||||
pub fn multinomial<T: Integer + Clone>(k: &[T]) -> T
|
||||
where
|
||||
for<'a> T: Add<&'a T, Output = T>,
|
||||
where for<'a> T: Add<&'a T, Output = T>
|
||||
{
|
||||
let mut r = T::one();
|
||||
let mut p = T::zero();
|
||||
|
@ -1140,20 +806,16 @@ where
|
|||
#[test]
|
||||
fn test_lcm_overflow() {
|
||||
macro_rules! check {
|
||||
($t:ty, $x:expr, $y:expr, $r:expr) => {{
|
||||
($t:ty, $x:expr, $y:expr, $r:expr) => { {
|
||||
let x: $t = $x;
|
||||
let y: $t = $y;
|
||||
let o = x.checked_mul(y);
|
||||
assert!(
|
||||
o.is_none(),
|
||||
"sanity checking that {} input {} * {} overflows",
|
||||
stringify!($t),
|
||||
x,
|
||||
y
|
||||
);
|
||||
assert!(o.is_none(),
|
||||
"sanity checking that {} input {} * {} overflows",
|
||||
stringify!($t), x, y);
|
||||
assert_eq!(x.lcm(&y), $r);
|
||||
assert_eq!(y.lcm(&x), $r);
|
||||
}};
|
||||
} }
|
||||
}
|
||||
|
||||
// Original bug (Issue #166)
|
||||
|
@ -1172,13 +834,13 @@ fn test_lcm_overflow() {
|
|||
#[test]
|
||||
fn test_iter_binomial() {
|
||||
macro_rules! check_simple {
|
||||
($t:ty) => {{
|
||||
($t:ty) => { {
|
||||
let n: $t = 3;
|
||||
let expected = [1, 3, 3, 1];
|
||||
for (b, &e) in IterBinomial::new(n).zip(&expected) {
|
||||
assert_eq!(b, e);
|
||||
}
|
||||
}};
|
||||
} }
|
||||
}
|
||||
|
||||
check_simple!(u8);
|
||||
|
@ -1191,14 +853,14 @@ fn test_iter_binomial() {
|
|||
check_simple!(i64);
|
||||
|
||||
macro_rules! check_binomial {
|
||||
($t:ty, $n:expr) => {{
|
||||
($t:ty, $n:expr) => { {
|
||||
let n: $t = $n;
|
||||
let mut k: $t = 0;
|
||||
for b in IterBinomial::new(n) {
|
||||
assert_eq!(b, binomial(n, k));
|
||||
k += 1;
|
||||
}
|
||||
}};
|
||||
} }
|
||||
}
|
||||
|
||||
// Check the largest n for which there is no overflow.
|
||||
|
@ -1215,7 +877,7 @@ fn test_iter_binomial() {
|
|||
#[test]
|
||||
fn test_binomial() {
|
||||
macro_rules! check {
|
||||
($t:ty, $x:expr, $y:expr, $r:expr) => {{
|
||||
($t:ty, $x:expr, $y:expr, $r:expr) => { {
|
||||
let x: $t = $x;
|
||||
let y: $t = $y;
|
||||
let expected: $t = $r;
|
||||
|
@ -1223,7 +885,7 @@ fn test_binomial() {
|
|||
if y <= x {
|
||||
assert_eq!(binomial(x, x - y), expected);
|
||||
}
|
||||
}};
|
||||
} }
|
||||
}
|
||||
check!(u8, 9, 4, 126);
|
||||
check!(u8, 0, 0, 1);
|
||||
|
@ -1271,12 +933,12 @@ fn test_binomial() {
|
|||
#[test]
|
||||
fn test_multinomial() {
|
||||
macro_rules! check_binomial {
|
||||
($t:ty, $k:expr) => {{
|
||||
($t:ty, $k:expr) => { {
|
||||
let n: $t = $k.iter().fold(0, |acc, &x| acc + x);
|
||||
let k: &[$t] = $k;
|
||||
assert_eq!(k.len(), 2);
|
||||
assert_eq!(multinomial(k), binomial(n, k[0]));
|
||||
}};
|
||||
} }
|
||||
}
|
||||
|
||||
check_binomial!(u8, &[4, 5]);
|
||||
|
@ -1306,11 +968,11 @@ fn test_multinomial() {
|
|||
check_binomial!(i64, &[4, 10]);
|
||||
|
||||
macro_rules! check_multinomial {
|
||||
($t:ty, $k:expr, $r:expr) => {{
|
||||
($t:ty, $k:expr, $r:expr) => { {
|
||||
let k: &[$t] = $k;
|
||||
let expected: $t = $r;
|
||||
assert_eq!(multinomial(k), expected);
|
||||
}};
|
||||
} }
|
||||
}
|
||||
|
||||
check_multinomial!(u8, &[2, 1, 2], 30);
|
||||
|
|
|
@ -202,181 +202,170 @@ fn log2<T: PrimInt>(x: T) -> u32 {
|
|||
macro_rules! unsigned_roots {
|
||||
($T:ident) => {
|
||||
impl Roots for $T {
|
||||
#[inline]
|
||||
fn nth_root(&self, n: u32) -> Self {
|
||||
fn go(a: $T, n: u32) -> $T {
|
||||
// Specialize small roots
|
||||
match n {
|
||||
0 => panic!("can't find a root of degree 0!"),
|
||||
1 => return a,
|
||||
2 => return a.sqrt(),
|
||||
3 => return a.cbrt(),
|
||||
_ => (),
|
||||
}
|
||||
// Specialize small roots
|
||||
match n {
|
||||
0 => panic!("can't find a root of degree 0!"),
|
||||
1 => return *self,
|
||||
2 => return self.sqrt(),
|
||||
3 => return self.cbrt(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// The root of values less than 2ⁿ can only be 0 or 1.
|
||||
if bits::<$T>() <= n || a < (1 << n) {
|
||||
return (a > 0) as $T;
|
||||
}
|
||||
// The root of values less than 2ⁿ can only be 0 or 1.
|
||||
if bits::<$T>() <= n || *self < (1 << n) {
|
||||
return (*self > 0) as $T;
|
||||
}
|
||||
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
|
||||
return if a <= core::u64::MAX as $T {
|
||||
(a as u64).nth_root(n) as $T
|
||||
} else {
|
||||
let lo = (a >> n).nth_root(n) << 1;
|
||||
let hi = lo + 1;
|
||||
// 128-bit `checked_mul` also involves division, but we can't always
|
||||
// compute `hiⁿ` without risking overflow. Try to avoid it though...
|
||||
if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() {
|
||||
match checked_pow(hi, n as usize) {
|
||||
Some(x) if x <= a => hi,
|
||||
_ => lo,
|
||||
}
|
||||
} else {
|
||||
if hi.pow(n) <= a {
|
||||
hi
|
||||
} else {
|
||||
lo
|
||||
}
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `nth_root` until it's small enough.
|
||||
return if *self <= core::u64::MAX as $T {
|
||||
(*self as u64).nth_root(n) as $T
|
||||
} else {
|
||||
let lo = (self >> n).nth_root(n) << 1;
|
||||
let hi = lo + 1;
|
||||
// 128-bit `checked_mul` also involves division, but we can't always
|
||||
// compute `hiⁿ` without risking overflow. Try to avoid it though...
|
||||
if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() {
|
||||
match checked_pow(hi, n as usize) {
|
||||
Some(x) if x <= *self => hi,
|
||||
_ => 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 {
|
||||
((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 go(a: $T) -> $T {
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `sqrt` until it's small enough.
|
||||
return if a <= core::u64::MAX as $T {
|
||||
(a as u64).sqrt() as $T
|
||||
if bits::<$T>() > 64 {
|
||||
// 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 *self <= core::u64::MAX 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 {
|
||||
let lo = (a >> 2u32).sqrt() << 1;
|
||||
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)
|
||||
lo
|
||||
}
|
||||
};
|
||||
}
|
||||
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 go(a: $T) -> $T {
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
|
||||
return if a <= core::u64::MAX as $T {
|
||||
(a as u64).cbrt() as $T
|
||||
if bits::<$T>() > 64 {
|
||||
// 128-bit division is slow, so do a bitwise `cbrt` until it's small enough.
|
||||
return if *self <= core::u64::MAX as $T {
|
||||
(*self as u64).cbrt() as $T
|
||||
} else {
|
||||
let lo = (self >> 3u32).cbrt() << 1;
|
||||
let hi = lo + 1;
|
||||
if hi * hi * hi <= *self {
|
||||
hi
|
||||
} else {
|
||||
let lo = (a >> 3u32).cbrt() << 1;
|
||||
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;
|
||||
}
|
||||
lo
|
||||
}
|
||||
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 {}
|
||||
|
||||
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
|
||||
///
|
||||
|
|
|
@ -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
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# 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
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
|
@ -12,10 +12,9 @@
|
|||
|
||||
[package]
|
||||
name = "num-iter"
|
||||
version = "0.1.41"
|
||||
version = "0.1.37"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
exclude = ["/bors.toml", "/ci/*", "/.github/*"]
|
||||
description = "External iterators for generic mathematics"
|
||||
homepage = "https://github.com/rust-num/num-iter"
|
||||
documentation = "https://docs.rs/num-iter"
|
||||
|
@ -27,14 +26,12 @@ repository = "https://github.com/rust-num/num-iter"
|
|||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
[dependencies.num-integer]
|
||||
version = "0.1.42"
|
||||
version = "0.1.38"
|
||||
default-features = false
|
||||
|
||||
[dependencies.num-traits]
|
||||
version = "0.2.11"
|
||||
version = "0.2.4"
|
||||
default-features = false
|
||||
[build-dependencies.autocfg]
|
||||
version = "1"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
[![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)
|
||||
[![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)
|
||||
[![build status](https://github.com/rust-num/num-iter/workflows/master/badge.svg)](https://github.com/rust-num/num-iter/actions)
|
||||
![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
|
||||
[![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.
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче