зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1600433 - Update pkcs11 to get rid of rustc-serialize and old rand version. r=keeler
I want to start updating gecko to rand 0.7, and it'd be silly having three rand versions in tree. This uses my git repo while I wait for upstream to merge my PR (https://github.com/mheese/rust-pkcs11/pull/16). That PR is the only difference from upstream. Differential Revision: https://phabricator.services.mozilla.com/D55351 --HG-- rename : third_party/rust/num-bigint/src/tests/bigint.rs => third_party/rust/num-bigint/tests/bigint.rs rename : third_party/rust/num-bigint/src/tests/biguint.rs => third_party/rust/num-bigint/tests/biguint.rs extra : moz-landing-system : lando
This commit is contained in:
Родитель
7229b5803b
Коммит
b0f38aab88
|
@ -32,6 +32,11 @@ branch = "rust_1_32"
|
|||
git = "https://github.com/hsivonen/packed_simd"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."https://github.com/emilio/rust-pkcs11"]
|
||||
branch = "master"
|
||||
git = "https://github.com/emilio/rust-pkcs11"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."https://github.com/alexcrichton/mio-named-pipes"]
|
||||
branch = "master"
|
||||
git = "https://github.com/alexcrichton/mio-named-pipes"
|
||||
|
|
|
@ -35,7 +35,7 @@ name = "app_units"
|
|||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -468,7 +468,7 @@ version = "0.4.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1086,7 +1086,7 @@ name = "euclid"
|
|||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1272,7 +1272,7 @@ dependencies = [
|
|||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"nsstring 0.1.0",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.21.0",
|
||||
"servo_arc 0.1.1",
|
||||
|
@ -1678,7 +1678,7 @@ dependencies = [
|
|||
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"png 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1729,7 +1729,7 @@ dependencies = [
|
|||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs_sys 0.0.0",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1916,7 +1916,7 @@ dependencies = [
|
|||
"cranelift-entity 0.41.0 (git+https://github.com/PLSysSec/lucet_sandbox_compiler)",
|
||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"object 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1932,7 +1932,7 @@ dependencies = [
|
|||
"lucet-module 0.1.1 (git+https://github.com/PLSysSec/lucet_sandbox_compiler)",
|
||||
"lucet-runtime-internals 0.1.1 (git+https://github.com/PLSysSec/lucet_sandbox_compiler)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1953,7 +1953,7 @@ dependencies = [
|
|||
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.13.1 (git+https://github.com/shravanrn/nix/?branch=r0.13.1)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2296,7 +2296,7 @@ dependencies = [
|
|||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2310,7 +2310,7 @@ dependencies = [
|
|||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mp4parse 0.11.3",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2340,7 +2340,7 @@ dependencies = [
|
|||
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2366,7 +2366,7 @@ dependencies = [
|
|||
"neqo-crypto 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-qpack 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"neqo-transport 0.1.6 (git+https://github.com/mozilla/neqo?tag=v0.1.6)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2485,13 +2485,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.1.44"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2519,7 +2518,7 @@ name = "num-integer"
|
|||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2528,7 +2527,7 @@ version = "0.1.37"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2537,13 +2536,16 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
|
@ -2598,7 +2600,7 @@ name = "ordered-float"
|
|||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2610,7 +2612,7 @@ dependencies = [
|
|||
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkcs11 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkcs11 0.4.1 (git+https://github.com/emilio/rust-pkcs11)",
|
||||
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -2744,11 +2746,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pkcs11"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/emilio/rust-pkcs11#c8d620f89f1611c3ad76b6d6a0c042c6e882ec42"
|
||||
dependencies = [
|
||||
"libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2769,7 +2771,7 @@ dependencies = [
|
|||
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2884,18 +2886,6 @@ dependencies = [
|
|||
"proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.6.5"
|
||||
|
@ -3240,7 +3230,7 @@ dependencies = [
|
|||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3256,11 +3246,6 @@ dependencies = [
|
|||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
|
@ -3632,7 +3617,7 @@ dependencies = [
|
|||
"nsstring 0.1.0",
|
||||
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3702,7 +3687,7 @@ dependencies = [
|
|||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.21.0",
|
||||
"size_of_test 0.0.1",
|
||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -4325,7 +4310,7 @@ dependencies = [
|
|||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plane-split 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -4828,13 +4813,13 @@ dependencies = [
|
|||
"checksum nix 0.13.1 (git+https://github.com/shravanrn/nix/?branch=r0.13.1)" = "<none>"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
|
||||
"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
|
||||
"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
|
||||
"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
|
||||
"checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
|
||||
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
|
||||
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
|
||||
"checksum objc_exception 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
|
||||
|
@ -4855,7 +4840,7 @@ dependencies = [
|
|||
"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
|
||||
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
|
||||
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
|
||||
"checksum pkcs11 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff403ab0d15638fc795f4e2122e77e007fdcf17db7fee38f225f173c6e4cc1c3"
|
||||
"checksum pkcs11 0.4.1 (git+https://github.com/emilio/rust-pkcs11)" = "<none>"
|
||||
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
|
||||
"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
"checksum plane-split 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe16a646a08f4b4dd74035b9ff8e378eb1a4012a74f14f5889e7001cdbece33"
|
||||
|
@ -4870,7 +4855,6 @@ dependencies = [
|
|||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
|
@ -4906,7 +4890,6 @@ dependencies = [
|
|||
"checksum rust_cascade 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f3fe4900d38dab1ad21a515e44687dd0711e6b0ec5b214a3b1aa8857343bcf3a"
|
||||
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
|
||||
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
|
||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
|
|
|
@ -12,7 +12,8 @@ byteorder = "1.3"
|
|||
env_logger = {version = "0.6", default-features = false } # disable `regex` to reduce code size
|
||||
lazy_static = "1"
|
||||
log = "0.4"
|
||||
pkcs11 = "0.4"
|
||||
# Waiting for https://github.com/mheese/rust-pkcs11/pull/16
|
||||
pkcs11 = {git = "https://github.com/emilio/rust-pkcs11"}
|
||||
sha2 = "0.8"
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies.winapi]
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"c366b169296b5639dc6a208154c1650928171039335967a32cccbb495f430a46","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"4e91d304e421fe6c8307312ef5420459fbf6b466c20ba827453f53e5ad8af2b2","RELEASES.md":"802a9d92097422fa89b12f65407af793578d5789a126875b2c9675091f8949cf","benches/bigint.rs":"e62ad970f1cf33c44a5a6ac6ac035059c4bd8416bbad1ddf3d8cfbef4f80b9a0","benches/factorial.rs":"67e50bca067764c5d9dfd2e2bbb75835087437c509b73d6206bbe5c6f797f469","benches/gcd.rs":"4d4ec3ef7bfc7a04867713f68d91f595030c188af6f5144224471d64b8bc3cab","benches/shootout-pidigits.rs":"a071146410ed87dd5ccc8ec1d6fd84e454146a8b067ec0825f397400c9f707e3","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","ci/rustup.sh":"d746c6b56162295462759a44803c8db9d78ec5b96f78814de149cddd3726ee85","ci/test_full.sh":"02101eb79026a9edc7dc257d5793fd85880a86e0fa888491caf1d571654ad51d","src/algorithms.rs":"640e974a76b3b8c3da4a5f55aada828b9cf3888ab6ccb4c71e0e04f52d96f029","src/bigint.rs":"a23460bd5dfb5743df0609db2b21152c388bba7b826abcba336648b04e6e5e55","src/biguint.rs":"e10b53f100bc63496f0adbbf13dba5fabbbacea621406f0f837d1605e2ca5f2d","src/lib.rs":"44d89304877858812cbce8e3db43d189a9776910955b6888b8322cb9ad1dfe12","src/macros.rs":"68831bd0165ddfd46d39ed69ef9cbce2ae7116872e59cd2b798562f0b72cbafb","src/monty.rs":"408d3871716537ab8726b5da0deb81dcb8782a73500f0c75039be552a5b50414","src/tests/bigint.rs":"fd1e6170cb217ccbf078574d02ade1c19c1d48c5e675f0bcd3584fc54083f0b7","src/tests/biguint.rs":"797a2409dd2e35b1ac794789300bcad19c9fde7633b115b811f6a2a10ced2a3b","tests/modpow.rs":"81c5e53ff27a9bc1b7ef0fd5375c408cf8621b40f0d36a4cc30b4df9656187d8"},"package":"e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"}
|
||||
{"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"}
|
|
@ -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,8 +12,9 @@
|
|||
|
||||
[package]
|
||||
name = "num-bigint"
|
||||
version = "0.1.44"
|
||||
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"
|
||||
|
@ -22,6 +23,8 @@ 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"
|
||||
|
@ -32,31 +35,47 @@ name = "factorial"
|
|||
[[bench]]
|
||||
name = "gcd"
|
||||
|
||||
[[bench]]
|
||||
name = "roots"
|
||||
|
||||
[[bench]]
|
||||
name = "shootout-pidigits"
|
||||
harness = false
|
||||
[dependencies.num-integer]
|
||||
version = "0.1.36"
|
||||
version = "0.1.39"
|
||||
default-features = false
|
||||
|
||||
[dependencies.num-traits]
|
||||
version = "0.2.0"
|
||||
features = ["std"]
|
||||
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.3.14, < 0.5.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.rustc-serialize]
|
||||
version = "0.3.19"
|
||||
version = "0.5"
|
||||
features = ["std"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
version = ">= 0.7.0, < 0.9.0"
|
||||
version = "1.0"
|
||||
features = ["std"]
|
||||
optional = true
|
||||
[dev-dependencies.rand]
|
||||
version = ">= 0.3.14, < 0.5.0"
|
||||
default-features = false
|
||||
[dev-dependencies.serde_test]
|
||||
version = "1.0"
|
||||
[build-dependencies.autocfg]
|
||||
version = "0.1.2"
|
||||
|
||||
[features]
|
||||
default = ["rand", "rustc-serialize"]
|
||||
default = ["std"]
|
||||
i128 = ["num-integer/i128", "num-traits/i128"]
|
||||
std = ["num-integer/std", "num-traits/std"]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[![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.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
|
||||
![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,7 +13,7 @@ Add this to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
num-bigint = "0.1"
|
||||
num-bigint = "0.2"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
@ -22,13 +22,24 @@ and this to your crate root:
|
|||
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.8 and greater.
|
||||
The `num-bigint` crate is tested for rustc 1.15 and greater.
|
||||
|
||||
## Alternatives
|
||||
|
||||
|
@ -38,11 +49,11 @@ table offers a brief comparison to a few alternatives.
|
|||
|
||||
| Crate | License | Min rustc | Implementation |
|
||||
| :--------------- | :------------- | :-------- | :------------- |
|
||||
| **`num-bigint`** | MIT/Apache-2.0 | 1.8 | 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.18 | 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 | nightly | pure rust (unfinished) |
|
||||
| [`apint`] | MIT/Apache-2.0 | 1.26 | pure rust (unfinished) |
|
||||
|
||||
[GMP]: https://gmplib.org/
|
||||
[`gmp-mpfr-sys`]: https://crates.io/crates/gmp-mpfr-sys
|
||||
|
|
|
@ -1,4 +1,96 @@
|
|||
# Release 0.1.44
|
||||
# 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].
|
||||
|
@ -9,7 +101,7 @@
|
|||
[21]: https://github.com/rust-num/num-bigint/pull/21
|
||||
[42]: https://github.com/rust-num/num-bigint/pull/42
|
||||
|
||||
# Release 0.1.43
|
||||
# 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`.
|
||||
|
@ -18,7 +110,8 @@
|
|||
|
||||
[18]: https://github.com/rust-num/num-bigint/pull/18
|
||||
|
||||
# Release 0.1.42
|
||||
|
||||
# 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].
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
#![feature(test)]
|
||||
#![cfg(feature = "rand")]
|
||||
|
||||
extern crate test;
|
||||
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;
|
||||
use num_bigint::{BigInt, BigUint, RandBigInt};
|
||||
use num_traits::{Zero, One, FromPrimitive, Num};
|
||||
use rand::{SeedableRng, StdRng};
|
||||
|
||||
fn get_rng() -> StdRng {
|
||||
let seed: &[_] = &[1, 2, 3, 4];
|
||||
let mut seed = [0; 32];
|
||||
for i in 1..32 {
|
||||
seed[usize::from(i)] = i;
|
||||
}
|
||||
SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
|
@ -32,9 +37,17 @@ fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
|
|||
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) {
|
||||
for i in 1..(n + 1) {
|
||||
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
|
||||
f = f * bu;
|
||||
}
|
||||
|
@ -99,6 +112,21 @@ 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));
|
||||
|
@ -210,6 +238,52 @@ 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;
|
||||
|
@ -250,27 +324,27 @@ fn pow_bench(b: &mut Bencher) {
|
|||
for i in 2..upper + 1 {
|
||||
for j in 2..upper + 1 {
|
||||
let i_big = BigUint::from_usize(i).unwrap();
|
||||
num_traits::pow(i_big, j);
|
||||
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";
|
||||
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) {
|
||||
|
|
|
@ -11,7 +11,11 @@ use test::Bencher;
|
|||
|
||||
#[bench]
|
||||
fn factorial_mul_biguint(b: &mut Bencher) {
|
||||
b.iter(|| (1u32..1000).map(BigUint::from).fold(BigUint::one(), Mul::mul));
|
||||
b.iter(|| {
|
||||
(1u32..1000)
|
||||
.map(BigUint::from)
|
||||
.fold(BigUint::one(), Mul::mul)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -25,7 +29,12 @@ fn factorial_mul_u32(b: &mut Bencher) {
|
|||
#[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));
|
||||
b.iter(|| {
|
||||
(1u32..1000)
|
||||
.rev()
|
||||
.map(BigUint::from)
|
||||
.fold(n.clone(), Div::div)
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
#![feature(test)]
|
||||
#![cfg(feature = "rand")]
|
||||
|
||||
extern crate test;
|
||||
extern crate num_bigint;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
extern crate rand;
|
||||
extern crate test;
|
||||
|
||||
use test::Bencher;
|
||||
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 seed: &[_] = &[1, 2, 3, 4];
|
||||
let mut seed = [0; 32];
|
||||
for i in 1..32 {
|
||||
seed[usize::from(i)] = i;
|
||||
}
|
||||
SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
|
@ -27,7 +31,6 @@ fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
|
|||
b.iter(|| gcd(&x, &y));
|
||||
}
|
||||
|
||||
|
||||
fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
|
||||
// Use Euclid's algorithm
|
||||
let mut m = x.clone();
|
||||
|
@ -60,7 +63,6 @@ fn gcd_euclid_4096(b: &mut Bencher) {
|
|||
bench(b, 4096, euclid);
|
||||
}
|
||||
|
||||
|
||||
// Integer for BigUint now uses Stein for gcd
|
||||
|
||||
#[bench]
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
#![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);
|
||||
}
|
|
@ -42,12 +42,12 @@ extern crate num_bigint;
|
|||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::io;
|
||||
use std::str::FromStr;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_integer::Integer;
|
||||
use num_traits::{FromPrimitive, ToPrimitive, One, Zero};
|
||||
use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
|
||||
|
||||
struct Context {
|
||||
numer: BigInt,
|
||||
|
@ -69,11 +69,13 @@ impl Context {
|
|||
}
|
||||
|
||||
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;}
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -92,29 +94,35 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
|
||||
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) {
|
||||
for i in 1..(n + 1) {
|
||||
let mut d;
|
||||
loop {
|
||||
k += 1;
|
||||
context.next_term(k);
|
||||
d = context.extract_digit();
|
||||
if d != -1 {break;}
|
||||
if d != -1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try!(write!(out, "{}", d));
|
||||
if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }
|
||||
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 { try!(write!(out, " ")); }
|
||||
try!(write!(out, "\t:{}\n", n));
|
||||
for _ in m..10 {
|
||||
write!(out, " ")?;
|
||||
}
|
||||
write!(out, "\t:{}\n", n)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -126,7 +134,7 @@ fn main() {
|
|||
let n = if args.len() < 2 {
|
||||
DEFAULT_DIGITS
|
||||
} else if args[1] == "--bench" {
|
||||
return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
|
||||
return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap();
|
||||
} else {
|
||||
FromStr::from_str(&args[1]).unwrap()
|
||||
};
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let ac = autocfg::new();
|
||||
if ac.probe_type("i128") {
|
||||
println!("cargo:rustc-cfg=has_i128");
|
||||
} else if env::var_os("CARGO_FEATURE_I128").is_some() {
|
||||
panic!("i128 support was not detected!");
|
||||
}
|
||||
|
||||
autocfg::rerun_path(file!());
|
||||
}
|
|
@ -1,19 +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.)
|
||||
# (You should first install/update all versions listed below.)
|
||||
|
||||
set -ex
|
||||
|
||||
export TRAVIS_RUST_VERSION
|
||||
for TRAVIS_RUST_VERSION in 1.8.0 stable beta nightly; do
|
||||
for TRAVIS_RUST_VERSION in 1.15.0 1.22.0 1.26.0 stable beta nightly; do
|
||||
run="rustup run $TRAVIS_RUST_VERSION"
|
||||
if [ "$TRAVIS_RUST_VERSION" = 1.8.0 ]; then
|
||||
# rand 0.3.22 started depending on rand 0.4, which requires rustc 1.15
|
||||
# manually hacking the lockfile due to the limitations of cargo#2773
|
||||
$run cargo generate-lockfile
|
||||
$run sed -i -e 's/"rand 0.[34].[0-9]\+/"rand 0.3.20/' Cargo.lock
|
||||
$run sed -i -e '/^name = "rand"/,/^$/s/version = "0.3.[0-9]\+"/version = "0.3.20"/' Cargo.lock
|
||||
fi
|
||||
$run cargo build --verbose
|
||||
$run $PWD/ci/test_full.sh
|
||||
done
|
||||
|
|
|
@ -4,20 +4,36 @@ set -ex
|
|||
|
||||
echo Testing num-bigint on rustc ${TRAVIS_RUST_VERSION}
|
||||
|
||||
FEATURES="serde"
|
||||
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.31.0|1.26.0|1.22.0)$ ]]; then
|
||||
FEATURES="$FEATURES rand"
|
||||
fi
|
||||
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.31.0|1.26.0)$ ]]; then
|
||||
FEATURES="$FEATURES i128"
|
||||
fi
|
||||
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable|1.31.0)$ ]]; then
|
||||
FEATURES="$FEATURES quickcheck quickcheck_macros"
|
||||
fi
|
||||
|
||||
# num-bigint should build and test everywhere.
|
||||
cargo build --verbose
|
||||
cargo test --verbose
|
||||
|
||||
# It should build with minimal features too.
|
||||
cargo build --no-default-features
|
||||
cargo test --no-default-features
|
||||
cargo build --no-default-features --features="std"
|
||||
cargo test --no-default-features --features="std"
|
||||
|
||||
# Each isolated feature should also work everywhere.
|
||||
for feature in rand rustc-serialize serde; do
|
||||
cargo build --verbose --no-default-features --features="$feature"
|
||||
cargo test --verbose --no-default-features --features="$feature"
|
||||
for feature in $FEATURES; do
|
||||
cargo build --verbose --no-default-features --features="std $feature"
|
||||
cargo test --verbose --no-default-features --features="std $feature"
|
||||
done
|
||||
|
||||
# Downgrade serde and build test the 0.7.0 channel as well
|
||||
cargo update -p serde --precise 0.7.0
|
||||
cargo build --verbose --no-default-features --features "serde"
|
||||
# test all supported features together
|
||||
cargo build --features="std $FEATURES"
|
||||
cargo test --features="std $FEATURES"
|
||||
|
||||
# make sure benchmarks can be built
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||
cargo bench --all-features --no-run
|
||||
fi
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::cmp;
|
||||
use std::cmp::Ordering::{self, Less, Greater, Equal};
|
||||
use std::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use std::iter::repeat;
|
||||
use std::mem;
|
||||
use traits;
|
||||
use traits::{Zero, One};
|
||||
use traits::{One, Zero};
|
||||
|
||||
use biguint::BigUint;
|
||||
|
||||
|
@ -12,86 +12,44 @@ use bigint::BigInt;
|
|||
use bigint::Sign;
|
||||
use bigint::Sign::{Minus, NoSign, Plus};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub 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;
|
||||
|
||||
pub const ZERO_BIG_DIGIT: BigDigit = 0;
|
||||
|
||||
// `DoubleBigDigit` size dependent
|
||||
pub const BITS: usize = 32;
|
||||
|
||||
pub const BASE: DoubleBigDigit = 1 << BITS;
|
||||
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 {
|
||||
(lo as DoubleBigDigit) | ((hi as DoubleBigDigit) << BITS)
|
||||
}
|
||||
}
|
||||
|
||||
use big_digit::{BigDigit, DoubleBigDigit};
|
||||
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, carry: &mut BigDigit) -> BigDigit {
|
||||
let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) + (b as DoubleBigDigit) +
|
||||
(*carry as DoubleBigDigit));
|
||||
|
||||
*carry = hi;
|
||||
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, borrow: &mut BigDigit) -> BigDigit {
|
||||
let (hi, lo) = big_digit::from_doublebigdigit(big_digit::BASE + (a as DoubleBigDigit) -
|
||||
(b as DoubleBigDigit) -
|
||||
(*borrow as DoubleBigDigit));
|
||||
// hi * (base) + lo == 1*(base) + ai - bi - borrow
|
||||
// => ai - bi - borrow < 0 <=> hi == 0
|
||||
*borrow = (hi == 0) as BigDigit;
|
||||
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, carry: &mut BigDigit) -> BigDigit {
|
||||
let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) +
|
||||
(b as DoubleBigDigit) * (c as DoubleBigDigit) +
|
||||
(*carry as DoubleBigDigit));
|
||||
*carry = hi;
|
||||
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, carry: &mut BigDigit) -> BigDigit {
|
||||
let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) * (b as DoubleBigDigit) +
|
||||
(*carry as DoubleBigDigit));
|
||||
|
||||
*carry = hi;
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -106,7 +64,7 @@ fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigi
|
|||
debug_assert!(hi < divisor);
|
||||
|
||||
let lhs = big_digit::to_doublebigdigit(hi, lo);
|
||||
let rhs = divisor as DoubleBigDigit;
|
||||
let rhs = DoubleBigDigit::from(divisor);
|
||||
((lhs / rhs) as BigDigit, (lhs % rhs) as BigDigit)
|
||||
}
|
||||
|
||||
|
@ -122,6 +80,16 @@ pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
|
|||
(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 {
|
||||
|
@ -137,14 +105,16 @@ pub fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
|||
if carry != 0 {
|
||||
for a in a_hi {
|
||||
*a = adc(*a, 0, &mut carry);
|
||||
if carry == 0 { break }
|
||||
if carry == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
carry
|
||||
carry as BigDigit
|
||||
}
|
||||
|
||||
/// /Two argument addition of raw slices:
|
||||
/// Two argument addition of raw slices:
|
||||
/// a += b
|
||||
///
|
||||
/// The caller _must_ ensure that a is big enough to store the result - typically this means
|
||||
|
@ -169,33 +139,49 @@ pub fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
|||
if borrow != 0 {
|
||||
for a in a_hi {
|
||||
*a = sbb(*a, 0, &mut borrow);
|
||||
if borrow == 0 { break }
|
||||
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.");
|
||||
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 mut borrow = 0;
|
||||
|
||||
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);
|
||||
|
||||
for (a, b) in a_lo.iter().zip(b_lo) {
|
||||
*b = sbb(*a, *b, &mut borrow);
|
||||
}
|
||||
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.");
|
||||
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) {
|
||||
|
@ -242,11 +228,7 @@ pub fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
|
|||
/// 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)
|
||||
};
|
||||
let (x, y) = if b.len() < c.len() { (b, c) } else { (c, b) };
|
||||
|
||||
// We use three algorithms for different input sizes.
|
||||
//
|
||||
|
@ -349,8 +331,8 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|||
// 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[..]);
|
||||
add2(&mut acc[b..], &p.data[..]);
|
||||
add2(&mut acc[b * 2..], &p.data[..]);
|
||||
|
||||
// Zero out p before the next multiply:
|
||||
p.data.truncate(0);
|
||||
|
@ -360,8 +342,8 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|||
mac3(&mut p.data[..], x0, y0);
|
||||
p.normalize();
|
||||
|
||||
add2(&mut acc[..], &p.data[..]);
|
||||
add2(&mut acc[b..], &p.data[..]);
|
||||
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:
|
||||
|
@ -369,7 +351,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|||
let (j1_sign, j1) = sub_sign(y1, y0);
|
||||
|
||||
match j0_sign * j1_sign {
|
||||
Plus => {
|
||||
Plus => {
|
||||
p.data.truncate(0);
|
||||
p.data.extend(repeat(0).take(len));
|
||||
|
||||
|
@ -377,22 +359,22 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|||
p.normalize();
|
||||
|
||||
sub2(&mut acc[b..], &p.data[..]);
|
||||
},
|
||||
Minus => {
|
||||
}
|
||||
Minus => {
|
||||
mac3(&mut acc[b..], &j0.data[..], &j1.data[..]);
|
||||
},
|
||||
NoSign => (),
|
||||
}
|
||||
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.
|
||||
//
|
||||
// FIXME: It would be nice to have comments breaking down the operations below.
|
||||
|
||||
let i = y.len()/3 + 1;
|
||||
// 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);
|
||||
|
@ -400,34 +382,105 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
|
|||
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;
|
||||
let r4 = &x2 * &y2;
|
||||
let r1 = (p + x1) * (q + y1);
|
||||
let r2 = &p2 * &q2;
|
||||
let r3 = ((p2 + x2)*2 - x0) * ((q2 + y2)*2 - 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;
|
||||
comp3 = (&comp2 - comp3) / 2 + &r4 * 2;
|
||||
comp2 = comp2 + &comp1 - &r4;
|
||||
comp1 = comp1 - &comp3;
|
||||
|
||||
let result = r0 + (comp1 << 32*i) + (comp2 << 2*32*i) + (comp3 << 3*32*i) + (r4 << 4*32*i);
|
||||
// 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);
|
||||
}
|
||||
|
@ -446,20 +499,68 @@ pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
|
|||
for a in a.iter_mut() {
|
||||
*a = mul_with_carry(*a, b, &mut carry);
|
||||
}
|
||||
carry
|
||||
carry as BigDigit
|
||||
}
|
||||
|
||||
pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
||||
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 == [1] {
|
||||
return (u.clone(), 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());
|
||||
}
|
||||
|
@ -478,9 +579,27 @@ pub fn div_rem(u: &BigUint, 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 mut a = u << shift;
|
||||
let b = d << shift;
|
||||
|
||||
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
|
||||
//
|
||||
|
@ -497,13 +616,17 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
|||
|
||||
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] };
|
||||
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) };
|
||||
let mut tmp = BigUint {
|
||||
data: Vec::with_capacity(2),
|
||||
};
|
||||
|
||||
for j in (0..q_len).rev() {
|
||||
/*
|
||||
|
@ -529,12 +652,12 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
|||
* smaller numbers.
|
||||
*/
|
||||
let (mut q0, _) = div_rem_digit(a0, bn);
|
||||
let mut prod = &b * &q0;
|
||||
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;
|
||||
prod = prod - b;
|
||||
}
|
||||
|
||||
add2(&mut q.data[j..], &q0.data[..]);
|
||||
|
@ -544,9 +667,9 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
|
|||
tmp = q0;
|
||||
}
|
||||
|
||||
debug_assert!(a < b);
|
||||
debug_assert!(&a < b);
|
||||
|
||||
(q.normalized(), a >> shift)
|
||||
(q.normalized(), a)
|
||||
}
|
||||
|
||||
/// Find last set bit
|
||||
|
@ -641,9 +764,10 @@ pub fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
|
|||
|
||||
#[cfg(test)]
|
||||
mod algorithm_tests {
|
||||
use {BigDigit, BigUint, BigInt};
|
||||
use Sign::Plus;
|
||||
use big_digit::BigDigit;
|
||||
use traits::Num;
|
||||
use Sign::Plus;
|
||||
use {BigInt, BigUint};
|
||||
|
||||
#[test]
|
||||
fn test_sub_sign() {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,218 @@
|
|||
//! 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)
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -47,6 +47,7 @@
|
|||
//! It's easy to generate large random numbers:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #[cfg(feature = "rand")]
|
||||
//! extern crate rand;
|
||||
//! extern crate num_bigint as bigint;
|
||||
//!
|
||||
|
@ -72,24 +73,35 @@
|
|||
//!
|
||||
//! ## Compatibility
|
||||
//!
|
||||
//! The `num-bigint` crate is tested for rustc 1.8 and greater.
|
||||
//! The `num-bigint` crate is tested for rustc 1.15 and greater.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/num-bigint/0.1")]
|
||||
#![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(any(feature = "rand", test))]
|
||||
#[cfg(feature = "rand")]
|
||||
extern crate rand;
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
extern crate rustc_serialize;
|
||||
#[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::num::ParseIntError;
|
||||
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")]
|
||||
|
@ -100,57 +112,95 @@ type IsizePromotion = i32;
|
|||
#[cfg(target_pointer_width = "64")]
|
||||
type IsizePromotion = i64;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ParseBigIntError {
|
||||
ParseInt(ParseIntError),
|
||||
Other,
|
||||
#[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 {
|
||||
match self {
|
||||
&ParseBigIntError::ParseInt(ref e) => e.fmt(f),
|
||||
&ParseBigIntError::Other => "failed to parse provided string".fmt(f),
|
||||
}
|
||||
self.__description().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseBigIntError {
|
||||
fn description(&self) -> &str {
|
||||
"failed to parse bigint/biguint"
|
||||
self.__description()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for ParseBigIntError {
|
||||
fn from(err: ParseIntError) -> ParseBigIntError {
|
||||
ParseBigIntError::ParseInt(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use std::hash;
|
||||
|
||||
#[cfg(test)]
|
||||
fn hash<T: hash::Hash>(x: &T) -> u64 {
|
||||
use std::hash::{BuildHasher, Hasher};
|
||||
use std::collections::hash_map::RandomState;
|
||||
let mut hasher = <RandomState as BuildHasher>::Hasher::new();
|
||||
x.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod biguint;
|
||||
mod bigint;
|
||||
|
||||
pub use biguint::BigUint;
|
||||
pub use biguint::ToBigUint;
|
||||
pub use biguint::big_digit;
|
||||
pub use biguint::big_digit::{BigDigit, DoubleBigDigit, ZERO_BIG_DIGIT};
|
||||
|
||||
pub use bigint::Sign;
|
||||
pub use bigint::BigInt;
|
||||
pub use bigint::Sign;
|
||||
pub use bigint::ToBigInt;
|
||||
pub use bigint::RandBigInt;
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ macro_rules! forward_val_val_binop {
|
|||
$imp::$method(self, &other)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_val_val_binop_commutative {
|
||||
|
@ -23,14 +23,14 @@ macro_rules! forward_val_val_binop_commutative {
|
|||
#[inline]
|
||||
fn $method(self, other: $res) -> $res {
|
||||
// forward to val-ref, with the larger capacity as val
|
||||
if self.data.capacity() >= other.data.capacity() {
|
||||
if self.capacity() >= other.capacity() {
|
||||
$imp::$method(self, &other)
|
||||
} else {
|
||||
$imp::$method(other, &self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_ref_val_binop {
|
||||
|
@ -44,7 +44,7 @@ macro_rules! forward_ref_val_binop {
|
|||
$imp::$method(self, &other)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_ref_val_binop_commutative {
|
||||
|
@ -58,7 +58,7 @@ macro_rules! forward_ref_val_binop_commutative {
|
|||
$imp::$method(other, self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_val_ref_binop {
|
||||
|
@ -72,7 +72,7 @@ macro_rules! forward_val_ref_binop {
|
|||
$imp::$method(&self, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_ref_ref_binop {
|
||||
|
@ -86,7 +86,7 @@ macro_rules! forward_ref_ref_binop {
|
|||
$imp::$method(self.clone(), other)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_ref_ref_binop_commutative {
|
||||
|
@ -97,14 +97,14 @@ macro_rules! forward_ref_ref_binop_commutative {
|
|||
#[inline]
|
||||
fn $method(self, other: &$res) -> $res {
|
||||
// forward to val-ref, choosing the larger to clone
|
||||
if self.data.len() >= other.data.len() {
|
||||
if self.len() >= other.len() {
|
||||
$imp::$method(self.clone(), other)
|
||||
} else {
|
||||
$imp::$method(other.clone(), self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_val_assign {
|
||||
|
@ -115,8 +115,9 @@ macro_rules! forward_val_assign {
|
|||
self.$method(&other);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_val_assign_scalar {
|
||||
(impl $imp:ident for $res:ty, $scalar:ty, $method:ident) => {
|
||||
impl $imp<$res> for $scalar {
|
||||
|
@ -125,11 +126,12 @@ macro_rules! forward_val_assign_scalar {
|
|||
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:ident < $scalar:ty > for $res:ty, $method:ident) => {
|
||||
impl $imp<$res> for $scalar {
|
||||
type Output = $res;
|
||||
|
||||
|
@ -138,10 +140,77 @@ macro_rules! forward_scalar_val_val_binop_commutative {
|
|||
$imp::$method(other, self)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_scalar_val_ref_binop {
|
||||
// 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;
|
||||
|
@ -160,11 +229,11 @@ macro_rules! forward_scalar_val_ref_binop {
|
|||
$imp::$method(*self, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_scalar_ref_val_binop {
|
||||
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
|
||||
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;
|
||||
|
||||
|
@ -182,10 +251,10 @@ macro_rules! forward_scalar_ref_val_binop {
|
|||
$imp::$method(self, other.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_scalar_ref_ref_binop {
|
||||
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;
|
||||
|
@ -204,7 +273,7 @@ macro_rules! forward_scalar_ref_ref_binop {
|
|||
$imp::$method(*self, other.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! promote_scalars {
|
||||
|
@ -215,6 +284,8 @@ macro_rules! promote_scalars {
|
|||
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)
|
||||
|
@ -224,6 +295,8 @@ macro_rules! promote_scalars {
|
|||
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)
|
||||
|
@ -236,6 +309,8 @@ 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);
|
||||
|
@ -266,6 +341,13 @@ 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<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) => {
|
||||
|
@ -293,11 +375,19 @@ macro_rules! forward_all_binop_to_val_ref_commutative {
|
|||
};
|
||||
}
|
||||
|
||||
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!(impl $imp<$scalar> for $res, $method);
|
||||
forward_scalar_ref_val_binop!(impl $imp<$scalar> for $res, $method);
|
||||
forward_scalar_ref_ref_binop!(impl $imp<$scalar> for $res, $method);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,3 +404,42 @@ macro_rules! promote_all_scalars {
|
|||
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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use biguint::BigUint;
|
|||
|
||||
struct MontyReducer<'a> {
|
||||
n: &'a BigUint,
|
||||
n0inv: u32
|
||||
n0inv: u32,
|
||||
}
|
||||
|
||||
// Calculate the modular inverse of `num`, using Extended GCD.
|
||||
|
@ -16,8 +16,8 @@ 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 = num as i64;
|
||||
let mut b: i64 = (u32::max_value() as i64) + 1;
|
||||
let mut a: i64 = i64::from(num);
|
||||
let mut b: i64 = i64::from(u32::max_value()) + 1;
|
||||
|
||||
// ExtendedGcd
|
||||
// Input: positive integers a and b
|
||||
|
@ -33,10 +33,12 @@ fn inv_mod_u32(num: u32) -> u32 {
|
|||
let q = a / b;
|
||||
let r = a % b;
|
||||
// 5: (a, b) <- (b, r)
|
||||
a = b; b = r;
|
||||
a = b;
|
||||
b = r;
|
||||
// 6: (u, w) <- (w, u - qw)
|
||||
let m = u - w*q;
|
||||
u = w; w = m;
|
||||
let m = u - w * q;
|
||||
u = w;
|
||||
w = m;
|
||||
}
|
||||
|
||||
assert!(a == 1);
|
||||
|
@ -100,7 +102,7 @@ fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint {
|
|||
monty_redc(&a * &a, mr)
|
||||
}
|
||||
|
||||
pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint{
|
||||
pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
|
||||
let mr = MontyReducer::new(modulus);
|
||||
|
||||
// Calculate the Montgomery parameter
|
||||
|
|
|
@ -1,102 +1,40 @@
|
|||
use {BigDigit, BigUint, big_digit};
|
||||
use {Sign, BigInt, RandBigInt, ToBigInt};
|
||||
use Sign::{Minus, NoSign, Plus};
|
||||
extern crate num_bigint;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
#[cfg(feature = "rand")]
|
||||
extern crate rand;
|
||||
|
||||
use std::cmp::Ordering::{Less, Equal, Greater};
|
||||
use std::{f32, f64};
|
||||
use std::{i8, i16, i32, i64, isize};
|
||||
use num_bigint::BigUint;
|
||||
use num_bigint::Sign::{Minus, NoSign, Plus};
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use std::collections::hash_map::RandomState;
|
||||
use std::hash::{BuildHasher, Hash, Hasher};
|
||||
use std::iter::repeat;
|
||||
use std::{u8, u16, u32, u64, usize};
|
||||
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 rand::thread_rng;
|
||||
use num_integer::Integer;
|
||||
use num_traits::{Float, FromPrimitive, Num, One, Pow, Signed, ToPrimitive, Zero};
|
||||
|
||||
use integer::Integer;
|
||||
use traits::{Zero, One, Signed, ToPrimitive, FromPrimitive, Num, Float};
|
||||
mod consts;
|
||||
use consts::*;
|
||||
|
||||
/// 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 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);
|
||||
}
|
||||
)*
|
||||
};
|
||||
($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);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_biguint() {
|
||||
fn check(inp_s: Sign, inp_n: usize, ans_s: Sign, ans_n: usize) {
|
||||
let inp = BigInt::from_biguint(inp_s, FromPrimitive::from_usize(inp_n).unwrap());
|
||||
let ans = BigInt {
|
||||
sign: ans_s,
|
||||
data: FromPrimitive::from_usize(ans_n).unwrap(),
|
||||
};
|
||||
assert_eq!(inp, ans);
|
||||
}
|
||||
check(Plus, 1, Plus, 1);
|
||||
check(Plus, 0, NoSign, 0);
|
||||
check(Minus, 1, Minus, 1);
|
||||
check(NoSign, 1, NoSign, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_slice() {
|
||||
fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) {
|
||||
let inp = BigInt::from_slice(inp_s, &[inp_n]);
|
||||
let ans = BigInt {
|
||||
sign: ans_s,
|
||||
data: FromPrimitive::from_u32(ans_n).unwrap(),
|
||||
};
|
||||
assert_eq!(inp, ans);
|
||||
}
|
||||
check(Plus, 1, Plus, 1);
|
||||
check(Plus, 0, NoSign, 0);
|
||||
check(Minus, 1, Minus, 1);
|
||||
check(NoSign, 1, NoSign, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_assign_from_slice() {
|
||||
fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) {
|
||||
let mut inp = BigInt::from_slice(Minus, &[2627_u32, 0_u32, 9182_u32, 42_u32]);
|
||||
inp.assign_from_slice(inp_s, &[inp_n]);
|
||||
let ans = BigInt {
|
||||
sign: ans_s,
|
||||
data: FromPrimitive::from_u32(ans_n).unwrap(),
|
||||
};
|
||||
assert_eq!(inp, ans);
|
||||
}
|
||||
check(Plus, 1, Plus, 1);
|
||||
check(Plus, 0, NoSign, 0);
|
||||
check(Minus, 1, Minus, 1);
|
||||
check(NoSign, 1, NoSign, 0);
|
||||
}
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
#[test]
|
||||
fn test_from_bytes_be() {
|
||||
fn check(s: &str, result: &str) {
|
||||
assert_eq!(BigInt::from_bytes_be(Plus, s.as_bytes()),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap());
|
||||
assert_eq!(
|
||||
BigInt::from_bytes_be(Plus, s.as_bytes()),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap()
|
||||
);
|
||||
}
|
||||
check("A", "65");
|
||||
check("AA", "16705");
|
||||
|
@ -128,8 +66,10 @@ fn test_to_bytes_be() {
|
|||
#[test]
|
||||
fn test_from_bytes_le() {
|
||||
fn check(s: &str, result: &str) {
|
||||
assert_eq!(BigInt::from_bytes_le(Plus, s.as_bytes()),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap());
|
||||
assert_eq!(
|
||||
BigInt::from_bytes_le(Plus, s.as_bytes()),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap()
|
||||
);
|
||||
}
|
||||
check("A", "65");
|
||||
check("AA", "16705");
|
||||
|
@ -161,8 +101,12 @@ fn test_to_bytes_le() {
|
|||
#[test]
|
||||
fn test_to_signed_bytes_le() {
|
||||
fn check(s: &str, result: Vec<u8>) {
|
||||
assert_eq!(BigInt::parse_bytes(s.as_bytes(), 10).unwrap().to_signed_bytes_le(),
|
||||
result);
|
||||
assert_eq!(
|
||||
BigInt::parse_bytes(s.as_bytes(), 10)
|
||||
.unwrap()
|
||||
.to_signed_bytes_le(),
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
check("0", vec![0]);
|
||||
|
@ -172,13 +116,16 @@ fn test_to_signed_bytes_le() {
|
|||
check("-100", vec![156]);
|
||||
check("-8388608", vec![0, 0, 0x80]);
|
||||
check("-192", vec![0x40, 0xff]);
|
||||
check("128", vec![0x80, 0])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_signed_bytes_le() {
|
||||
fn check(s: &[u8], result: &str) {
|
||||
assert_eq!(BigInt::from_signed_bytes_le(s),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap());
|
||||
assert_eq!(
|
||||
BigInt::from_signed_bytes_le(s),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
check(&[], "0");
|
||||
|
@ -196,8 +143,12 @@ fn test_from_signed_bytes_le() {
|
|||
#[test]
|
||||
fn test_to_signed_bytes_be() {
|
||||
fn check(s: &str, result: Vec<u8>) {
|
||||
assert_eq!(BigInt::parse_bytes(s.as_bytes(), 10).unwrap().to_signed_bytes_be(),
|
||||
result);
|
||||
assert_eq!(
|
||||
BigInt::parse_bytes(s.as_bytes(), 10)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
check("0", vec![0]);
|
||||
|
@ -207,13 +158,16 @@ fn test_to_signed_bytes_be() {
|
|||
check("-100", vec![156]);
|
||||
check("-8388608", vec![128, 0, 0]);
|
||||
check("-192", vec![0xff, 0x40]);
|
||||
check("128", vec![0, 0x80]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_signed_bytes_be() {
|
||||
fn check(s: &[u8], result: &str) {
|
||||
assert_eq!(BigInt::from_signed_bytes_be(s),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap());
|
||||
assert_eq!(
|
||||
BigInt::from_signed_bytes_be(s),
|
||||
BigInt::parse_bytes(result.as_bytes(), 10).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
check(&[], "0");
|
||||
|
@ -228,9 +182,25 @@ fn test_from_signed_bytes_be() {
|
|||
check(&[0xff, 0x40], "-192");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signed_bytes_be_round_trip() {
|
||||
for i in -0x1FFFF..0x20000 {
|
||||
let n = BigInt::from(i);
|
||||
assert_eq!(n, BigInt::from_signed_bytes_be(&n.to_signed_bytes_be()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signed_bytes_le_round_trip() {
|
||||
for i in -0x1FFFF..0x20000 {
|
||||
let n = BigInt::from(i);
|
||||
assert_eq!(n, BigInt::from_signed_bytes_le(&n.to_signed_bytes_le()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cmp() {
|
||||
let vs: [&[BigDigit]; 4] = [&[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1]];
|
||||
let vs: [&[u32]; 4] = [&[2 as u32], &[1, 1], &[2, 1], &[1, 1, 1]];
|
||||
let mut nums = Vec::new();
|
||||
for s in vs.iter().rev() {
|
||||
nums.push(BigInt::from_slice(Minus, *s));
|
||||
|
@ -271,11 +241,14 @@ fn test_cmp() {
|
|||
}
|
||||
}
|
||||
|
||||
fn hash<T: Hash>(x: &T) -> u64 {
|
||||
let mut hasher = <RandomState as BuildHasher>::Hasher::new();
|
||||
x.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
use hash;
|
||||
|
||||
let a = BigInt::new(NoSign, vec![]);
|
||||
let b = BigInt::new(NoSign, vec![0]);
|
||||
let c = BigInt::new(Plus, vec![1]);
|
||||
|
@ -304,16 +277,52 @@ fn test_convert_i64() {
|
|||
|
||||
assert_eq!((i64::MAX as u64 + 1).to_bigint().unwrap().to_i64(), None);
|
||||
|
||||
assert_eq!(BigInt::from_biguint(Plus, BigUint::new(vec![1, 2, 3, 4, 5])).to_i64(),
|
||||
None);
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Plus, BigUint::new(vec![1, 2, 3, 4, 5])).to_i64(),
|
||||
None
|
||||
);
|
||||
|
||||
assert_eq!(BigInt::from_biguint(Minus,
|
||||
BigUint::new(vec![1, 0, 0, 1 << (big_digit::BITS - 1)]))
|
||||
.to_i64(),
|
||||
None);
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Minus, BigUint::new(vec![1, 0, 0, 1 << 31])).to_i64(),
|
||||
None
|
||||
);
|
||||
|
||||
assert_eq!(BigInt::from_biguint(Minus, BigUint::new(vec![1, 2, 3, 4, 5])).to_i64(),
|
||||
None);
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Minus, BigUint::new(vec![1, 2, 3, 4, 5])).to_i64(),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn test_convert_i128() {
|
||||
fn check(b1: BigInt, i: i128) {
|
||||
let b2: BigInt = FromPrimitive::from_i128(i).unwrap();
|
||||
assert!(b1 == b2);
|
||||
assert!(b1.to_i128().unwrap() == i);
|
||||
}
|
||||
|
||||
check(Zero::zero(), 0);
|
||||
check(One::one(), 1);
|
||||
check(i128::MIN.to_bigint().unwrap(), i128::MIN);
|
||||
check(i128::MAX.to_bigint().unwrap(), i128::MAX);
|
||||
|
||||
assert_eq!((i128::MAX as u128 + 1).to_bigint().unwrap().to_i128(), None);
|
||||
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Plus, BigUint::new(vec![1, 2, 3, 4, 5])).to_i128(),
|
||||
None
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Minus, BigUint::new(vec![1, 0, 0, 1 << 31])).to_i128(),
|
||||
None
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Minus, BigUint::new(vec![1, 2, 3, 4, 5])).to_i128(),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -329,13 +338,44 @@ fn test_convert_u64() {
|
|||
check(u64::MIN.to_bigint().unwrap(), u64::MIN);
|
||||
check(u64::MAX.to_bigint().unwrap(), u64::MAX);
|
||||
|
||||
assert_eq!(BigInt::from_biguint(Plus, BigUint::new(vec![1, 2, 3, 4, 5])).to_u64(),
|
||||
None);
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Plus, BigUint::new(vec![1, 2, 3, 4, 5])).to_u64(),
|
||||
None
|
||||
);
|
||||
|
||||
let max_value: BigUint = FromPrimitive::from_u64(u64::MAX).unwrap();
|
||||
assert_eq!(BigInt::from_biguint(Minus, max_value).to_u64(), None);
|
||||
assert_eq!(BigInt::from_biguint(Minus, BigUint::new(vec![1, 2, 3, 4, 5])).to_u64(),
|
||||
None);
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Minus, BigUint::new(vec![1, 2, 3, 4, 5])).to_u64(),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(has_i128)]
|
||||
fn test_convert_u128() {
|
||||
fn check(b1: BigInt, u: u128) {
|
||||
let b2: BigInt = FromPrimitive::from_u128(u).unwrap();
|
||||
assert!(b1 == b2);
|
||||
assert!(b1.to_u128().unwrap() == u);
|
||||
}
|
||||
|
||||
check(Zero::zero(), 0);
|
||||
check(One::one(), 1);
|
||||
check(u128::MIN.to_bigint().unwrap(), u128::MIN);
|
||||
check(u128::MAX.to_bigint().unwrap(), u128::MAX);
|
||||
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Plus, BigUint::new(vec![1, 2, 3, 4, 5])).to_u128(),
|
||||
None
|
||||
);
|
||||
|
||||
let max_value: BigUint = FromPrimitive::from_u128(u128::MAX).unwrap();
|
||||
assert_eq!(BigInt::from_biguint(Minus, max_value).to_u128(), None);
|
||||
assert_eq!(
|
||||
BigInt::from_biguint(Minus, BigUint::new(vec![1, 2, 3, 4, 5])).to_u128(),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -355,8 +395,10 @@ fn test_convert_f32() {
|
|||
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)),
|
||||
2.0.powi(100) + 2.0.powi(123));
|
||||
check(
|
||||
&((BigInt::one() << 100) + (BigInt::one() << 123)),
|
||||
2.0.powi(100) + 2.0.powi(123),
|
||||
);
|
||||
check(&(BigInt::one() << 127), 2.0.powi(127));
|
||||
check(&(BigInt::from((1u64 << 24) - 1) << (128 - 24)), f32::MAX);
|
||||
|
||||
|
@ -388,14 +430,18 @@ fn test_convert_f32() {
|
|||
}
|
||||
|
||||
// rounding
|
||||
assert_eq!(BigInt::from_f32(-f32::consts::PI),
|
||||
Some(BigInt::from(-3i32)));
|
||||
assert_eq!(
|
||||
BigInt::from_f32(-f32::consts::PI),
|
||||
Some(BigInt::from(-3i32))
|
||||
);
|
||||
assert_eq!(BigInt::from_f32(-f32::consts::E), Some(BigInt::from(-2i32)));
|
||||
assert_eq!(BigInt::from_f32(-0.99999), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f32(-0.5), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f32(-0.0), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f32(f32::MIN_POSITIVE / 2.0),
|
||||
Some(BigInt::zero()));
|
||||
assert_eq!(
|
||||
BigInt::from_f32(f32::MIN_POSITIVE / 2.0),
|
||||
Some(BigInt::zero())
|
||||
);
|
||||
assert_eq!(BigInt::from_f32(f32::MIN_POSITIVE), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f32(0.5), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f32(0.99999), Some(BigInt::zero()));
|
||||
|
@ -437,8 +483,10 @@ fn test_convert_f64() {
|
|||
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)),
|
||||
2.0.powi(100) + 2.0.powi(152));
|
||||
check(
|
||||
&((BigInt::one() << 100) + (BigInt::one() << 152)),
|
||||
2.0.powi(100) + 2.0.powi(152),
|
||||
);
|
||||
check(&(BigInt::one() << 1023), 2.0.powi(1023));
|
||||
check(&(BigInt::from((1u64 << 53) - 1) << (1024 - 53)), f64::MAX);
|
||||
|
||||
|
@ -462,14 +510,18 @@ fn test_convert_f64() {
|
|||
}
|
||||
|
||||
// rounding
|
||||
assert_eq!(BigInt::from_f64(-f64::consts::PI),
|
||||
Some(BigInt::from(-3i32)));
|
||||
assert_eq!(
|
||||
BigInt::from_f64(-f64::consts::PI),
|
||||
Some(BigInt::from(-3i32))
|
||||
);
|
||||
assert_eq!(BigInt::from_f64(-f64::consts::E), Some(BigInt::from(-2i32)));
|
||||
assert_eq!(BigInt::from_f64(-0.99999), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f64(-0.5), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f64(-0.0), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f64(f64::MIN_POSITIVE / 2.0),
|
||||
Some(BigInt::zero()));
|
||||
assert_eq!(
|
||||
BigInt::from_f64(f64::MIN_POSITIVE / 2.0),
|
||||
Some(BigInt::zero())
|
||||
);
|
||||
assert_eq!(BigInt::from_f64(f64::MIN_POSITIVE), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f64(0.5), Some(BigInt::zero()));
|
||||
assert_eq!(BigInt::from_f64(0.99999), Some(BigInt::zero()));
|
||||
|
@ -519,14 +571,18 @@ fn test_convert_from_uint() {
|
|||
assert_eq!(BigInt::from($ty::one()), BigInt::one());
|
||||
assert_eq!(BigInt::from($ty::MAX - $ty::one()), $max - BigInt::one());
|
||||
assert_eq!(BigInt::from($ty::MAX), $max);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
check!(u8, BigInt::from_slice(Plus, &[u8::MAX as BigDigit]));
|
||||
check!(u16, BigInt::from_slice(Plus, &[u16::MAX as BigDigit]));
|
||||
check!(u32, BigInt::from_slice(Plus, &[u32::MAX as BigDigit]));
|
||||
check!(u64,
|
||||
BigInt::from_slice(Plus, &[u32::MAX as BigDigit, u32::MAX as BigDigit]));
|
||||
check!(u8, BigInt::from_slice(Plus, &[u8::MAX as u32]));
|
||||
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])
|
||||
);
|
||||
check!(usize, BigInt::from(usize::MAX as u64));
|
||||
}
|
||||
|
||||
|
@ -541,49 +597,52 @@ fn test_convert_from_int() {
|
|||
assert_eq!(BigInt::from($ty::one()), BigInt::one());
|
||||
assert_eq!(BigInt::from($ty::MAX - $ty::one()), $max - BigInt::one());
|
||||
assert_eq!(BigInt::from($ty::MAX), $max);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
check!(i8,
|
||||
BigInt::from_slice(Minus, &[1 << 7]),
|
||||
BigInt::from_slice(Plus, &[i8::MAX as BigDigit]));
|
||||
check!(i16,
|
||||
BigInt::from_slice(Minus, &[1 << 15]),
|
||||
BigInt::from_slice(Plus, &[i16::MAX as BigDigit]));
|
||||
check!(i32,
|
||||
BigInt::from_slice(Minus, &[1 << 31]),
|
||||
BigInt::from_slice(Plus, &[i32::MAX as BigDigit]));
|
||||
check!(i64,
|
||||
BigInt::from_slice(Minus, &[0, 1 << 31]),
|
||||
BigInt::from_slice(Plus, &[u32::MAX as BigDigit, i32::MAX as BigDigit]));
|
||||
check!(isize,
|
||||
BigInt::from(isize::MIN as i64),
|
||||
BigInt::from(isize::MAX as i64));
|
||||
check!(
|
||||
i8,
|
||||
BigInt::from_slice(Minus, &[1 << 7]),
|
||||
BigInt::from_slice(Plus, &[i8::MAX as u32])
|
||||
);
|
||||
check!(
|
||||
i16,
|
||||
BigInt::from_slice(Minus, &[1 << 15]),
|
||||
BigInt::from_slice(Plus, &[i16::MAX as u32])
|
||||
);
|
||||
check!(
|
||||
i32,
|
||||
BigInt::from_slice(Minus, &[1 << 31]),
|
||||
BigInt::from_slice(Plus, &[i32::MAX as u32])
|
||||
);
|
||||
check!(
|
||||
i64,
|
||||
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]),
|
||||
BigInt::from_slice(Plus, &[u32::MAX, u32::MAX, u32::MAX, i32::MAX as u32])
|
||||
);
|
||||
check!(
|
||||
isize,
|
||||
BigInt::from(isize::MIN as i64),
|
||||
BigInt::from(isize::MAX as i64)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_convert_from_biguint() {
|
||||
assert_eq!(BigInt::from(BigUint::zero()), BigInt::zero());
|
||||
assert_eq!(BigInt::from(BigUint::one()), BigInt::one());
|
||||
assert_eq!(BigInt::from(BigUint::from_slice(&[1, 2, 3])),
|
||||
BigInt::from_slice(Plus, &[1, 2, 3]));
|
||||
assert_eq!(
|
||||
BigInt::from(BigUint::from_slice(&[1, 2, 3])),
|
||||
BigInt::from_slice(Plus, &[1, 2, 3])
|
||||
);
|
||||
}
|
||||
|
||||
const N1: BigDigit = -1i32 as BigDigit;
|
||||
const N2: BigDigit = -2i32 as BigDigit;
|
||||
|
||||
const SUM_TRIPLES: &'static [(&'static [BigDigit],
|
||||
&'static [BigDigit],
|
||||
&'static [BigDigit])] = &[(&[], &[], &[]),
|
||||
(&[], &[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])];
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -601,26 +660,15 @@ fn test_add() {
|
|||
assert_op!(b + nc == na);
|
||||
assert_op!(na + nb == nc);
|
||||
assert_op!(a + na == Zero::zero());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_add() {
|
||||
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);
|
||||
|
||||
assert_scalar_op!(a + b == c);
|
||||
assert_scalar_op!(b + a == c);
|
||||
assert_scalar_op!(c + na == b);
|
||||
assert_scalar_op!(c + nb == a);
|
||||
assert_scalar_op!(a + nc == nb);
|
||||
assert_scalar_op!(b + nc == na);
|
||||
assert_scalar_op!(na + nb == nc);
|
||||
assert_scalar_op!(a + na == Zero::zero());
|
||||
assert_assign_op!(a += b == c);
|
||||
assert_assign_op!(b += a == c);
|
||||
assert_assign_op!(c += na == b);
|
||||
assert_assign_op!(c += nb == a);
|
||||
assert_assign_op!(a += nc == nb);
|
||||
assert_assign_op!(b += nc == na);
|
||||
assert_assign_op!(na += nb == nc);
|
||||
assert_assign_op!(a += na == Zero::zero());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,66 +689,18 @@ fn test_sub() {
|
|||
assert_op!(a - nb == c);
|
||||
assert_op!(nc - na == nb);
|
||||
assert_op!(a - a == Zero::zero());
|
||||
|
||||
assert_assign_op!(c -= a == b);
|
||||
assert_assign_op!(c -= b == a);
|
||||
assert_assign_op!(nb -= a == nc);
|
||||
assert_assign_op!(na -= b == nc);
|
||||
assert_assign_op!(b -= na == c);
|
||||
assert_assign_op!(a -= nb == c);
|
||||
assert_assign_op!(nc -= na == nb);
|
||||
assert_assign_op!(a -= a == Zero::zero());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_sub() {
|
||||
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);
|
||||
|
||||
assert_scalar_op!(c - a == b);
|
||||
assert_scalar_op!(c - b == a);
|
||||
assert_scalar_op!(nb - a == nc);
|
||||
assert_scalar_op!(na - b == nc);
|
||||
assert_scalar_op!(b - na == c);
|
||||
assert_scalar_op!(a - nb == c);
|
||||
assert_scalar_op!(nc - na == nb);
|
||||
assert_scalar_op!(a - a == Zero::zero());
|
||||
}
|
||||
}
|
||||
|
||||
const M: u32 = ::std::u32::MAX;
|
||||
static MUL_TRIPLES: &'static [(&'static [BigDigit],
|
||||
&'static [BigDigit],
|
||||
&'static [BigDigit])] = &[(&[], &[], &[]),
|
||||
(&[], &[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])];
|
||||
|
||||
static DIV_REM_QUADRUPLES: &'static [(&'static [BigDigit],
|
||||
&'static [BigDigit],
|
||||
&'static [BigDigit],
|
||||
&'static [BigDigit])] = &[(&[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])];
|
||||
|
||||
#[test]
|
||||
fn test_mul() {
|
||||
for elm in MUL_TRIPLES.iter() {
|
||||
|
@ -716,6 +716,13 @@ fn test_mul() {
|
|||
|
||||
assert_op!(na * b == nc);
|
||||
assert_op!(nb * a == nc);
|
||||
|
||||
assert_assign_op!(a *= b == c);
|
||||
assert_assign_op!(b *= a == c);
|
||||
assert_assign_op!(na *= nb == c);
|
||||
|
||||
assert_assign_op!(na *= b == nc);
|
||||
assert_assign_op!(nb *= a == nc);
|
||||
}
|
||||
|
||||
for elm in DIV_REM_QUADRUPLES.iter() {
|
||||
|
@ -730,30 +737,12 @@ fn test_mul() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_mul() {
|
||||
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);
|
||||
|
||||
assert_scalar_op!(a * b == c);
|
||||
assert_scalar_op!(b * a == c);
|
||||
assert_scalar_op!(na * nb == c);
|
||||
|
||||
assert_scalar_op!(na * b == nc);
|
||||
assert_scalar_op!(nb * a == nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
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);
|
||||
if !m.is_zero() {
|
||||
assert_eq!(m.sign, b.sign);
|
||||
assert_eq!(m.sign(), b.sign());
|
||||
}
|
||||
assert!(m.abs() <= b.abs());
|
||||
assert!(*a == b * &d + &m);
|
||||
|
@ -803,13 +792,12 @@ fn test_div_mod_floor() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_div_rem() {
|
||||
fn check_sub(a: &BigInt, b: &BigInt, ans_q: &BigInt, ans_r: &BigInt) {
|
||||
let (q, r) = a.div_rem(b);
|
||||
if !r.is_zero() {
|
||||
assert_eq!(r.sign, a.sign);
|
||||
assert_eq!(r.sign(), a.sign());
|
||||
}
|
||||
assert!(r.abs() <= b.abs());
|
||||
assert!(*a == b * &q + &r);
|
||||
|
@ -819,6 +807,8 @@ fn test_div_rem() {
|
|||
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);
|
||||
assert_assign_op!(a /= b == ans_q);
|
||||
assert_assign_op!(a %= b == ans_r);
|
||||
}
|
||||
|
||||
fn check(a: &BigInt, b: &BigInt, q: &BigInt, r: &BigInt) {
|
||||
|
@ -854,65 +844,6 @@ fn test_div_rem() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_div_rem() {
|
||||
fn check_sub(a: &BigInt, b: BigDigit, 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: BigDigit, 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_checked_add() {
|
||||
for elm in SUM_TRIPLES.iter() {
|
||||
|
@ -1031,6 +962,7 @@ fn test_lcm() {
|
|||
assert_eq!(big_a.lcm(&big_b), big_c);
|
||||
}
|
||||
|
||||
check(0, 0, 0);
|
||||
check(1, 0, 0);
|
||||
check(0, 1, 0);
|
||||
check(1, 1, 1);
|
||||
|
@ -1081,7 +1013,9 @@ fn test_from_str_radix() {
|
|||
|
||||
// issue 10522, this hit an edge case that caused it to
|
||||
// attempt to allocate a vector of size (-1u) == huge.
|
||||
let x: BigInt = format!("1{}", repeat("0").take(36).collect::<String>()).parse().unwrap();
|
||||
let x: BigInt = format!("1{}", repeat("0").take(36).collect::<String>())
|
||||
.parse()
|
||||
.unwrap();
|
||||
let _y = x.to_string();
|
||||
}
|
||||
|
||||
|
@ -1111,8 +1045,10 @@ fn test_binary() {
|
|||
let hello = BigInt::parse_bytes("-224055342307539".as_bytes(), 10).unwrap();
|
||||
|
||||
assert_eq!(format!("{:b}", a), "1010");
|
||||
assert_eq!(format!("{:b}", hello),
|
||||
"-110010111100011011110011000101101001100011010011");
|
||||
assert_eq!(
|
||||
format!("{:b}", hello),
|
||||
"-110010111100011011110011000101101001100011010011"
|
||||
);
|
||||
assert_eq!(format!("{:♥>+#8b}", a), "♥+0b1010");
|
||||
}
|
||||
|
||||
|
@ -1145,50 +1081,113 @@ fn test_neg() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand() {
|
||||
let mut rng = thread_rng();
|
||||
let _n: BigInt = rng.gen_bigint(137);
|
||||
assert!(rng.gen_bigint(0).is_zero());
|
||||
fn test_negative_shr() {
|
||||
assert_eq!(BigInt::from(-1) >> 1, BigInt::from(-1));
|
||||
assert_eq!(BigInt::from(-2) >> 1, BigInt::from(-1));
|
||||
assert_eq!(BigInt::from(-3) >> 1, BigInt::from(-2));
|
||||
assert_eq!(BigInt::from(-3) >> 2, BigInt::from(-1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_range() {
|
||||
let mut rng = thread_rng();
|
||||
#[cfg(feature = "rand")]
|
||||
fn test_random_shr() {
|
||||
use rand::distributions::Standard;
|
||||
use rand::Rng;
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
for _ in 0..10 {
|
||||
assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(),
|
||||
&FromPrimitive::from_usize(237).unwrap()),
|
||||
FromPrimitive::from_usize(236).unwrap());
|
||||
}
|
||||
|
||||
fn check(l: BigInt, u: BigInt) {
|
||||
let mut rng = thread_rng();
|
||||
for _ in 0..1000 {
|
||||
let n: BigInt = rng.gen_bigint_range(&l, &u);
|
||||
assert!(n >= l);
|
||||
assert!(n < u);
|
||||
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);
|
||||
}
|
||||
}
|
||||
let l: BigInt = FromPrimitive::from_usize(403469000 + 2352).unwrap();
|
||||
let u: BigInt = FromPrimitive::from_usize(403469000 + 3513).unwrap();
|
||||
check(l.clone(), u.clone());
|
||||
check(-l.clone(), u.clone());
|
||||
check(-u.clone(), -l.clone());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_zero_rand_range() {
|
||||
thread_rng().gen_bigint_range(&FromPrimitive::from_isize(54).unwrap(),
|
||||
&FromPrimitive::from_isize(54).unwrap());
|
||||
fn test_iter_sum() {
|
||||
let result: BigInt = FromPrimitive::from_isize(-1234567).unwrap();
|
||||
let data: Vec<BigInt> = vec![
|
||||
FromPrimitive::from_i32(-1000000).unwrap(),
|
||||
FromPrimitive::from_i32(-200000).unwrap(),
|
||||
FromPrimitive::from_i32(-30000).unwrap(),
|
||||
FromPrimitive::from_i32(-4000).unwrap(),
|
||||
FromPrimitive::from_i32(-500).unwrap(),
|
||||
FromPrimitive::from_i32(-60).unwrap(),
|
||||
FromPrimitive::from_i32(-7).unwrap(),
|
||||
];
|
||||
|
||||
assert_eq!(result, data.iter().sum());
|
||||
assert_eq!(result, data.into_iter().sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_negative_rand_range() {
|
||||
let mut rng = thread_rng();
|
||||
let l = FromPrimitive::from_usize(2352).unwrap();
|
||||
let u = FromPrimitive::from_usize(3513).unwrap();
|
||||
// Switching u and l should fail:
|
||||
let _n: BigInt = rng.gen_bigint_range(&u, &l);
|
||||
fn test_iter_product() {
|
||||
let data: Vec<BigInt> = vec![
|
||||
FromPrimitive::from_i32(1001).unwrap(),
|
||||
FromPrimitive::from_i32(-1002).unwrap(),
|
||||
FromPrimitive::from_i32(1003).unwrap(),
|
||||
FromPrimitive::from_i32(-1004).unwrap(),
|
||||
FromPrimitive::from_i32(1005).unwrap(),
|
||||
];
|
||||
let result = data.get(0).unwrap()
|
||||
* data.get(1).unwrap()
|
||||
* data.get(2).unwrap()
|
||||
* data.get(3).unwrap()
|
||||
* data.get(4).unwrap();
|
||||
|
||||
assert_eq!(result, data.iter().product());
|
||||
assert_eq!(result, data.into_iter().product());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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());
|
||||
assert_eq!(result, data.into_iter().sum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iter_product_generic() {
|
||||
let data = vec![1001, -1002, 1003, -1004, 1005];
|
||||
let result = data[0].to_bigint().unwrap()
|
||||
* data[1].to_bigint().unwrap()
|
||||
* data[2].to_bigint().unwrap()
|
||||
* data[3].to_bigint().unwrap()
|
||||
* data[4].to_bigint().unwrap();
|
||||
|
||||
assert_eq!(result, data.iter().product());
|
||||
assert_eq!(result, data.into_iter().product());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pow() {
|
||||
let one = BigInt::from(1i32);
|
||||
let two = BigInt::from(2i32);
|
||||
let four = BigInt::from(4i32);
|
||||
let eight = BigInt::from(8i32);
|
||||
let minus_two = BigInt::from(-2i32);
|
||||
macro_rules! check {
|
||||
($t:ty) => {
|
||||
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);
|
||||
check!(u16);
|
||||
check!(u32);
|
||||
check!(u64);
|
||||
check!(usize);
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,109 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#![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]),
|
||||
];
|
|
@ -0,0 +1,70 @@
|
|||
#![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);
|
||||
};
|
||||
}
|
|
@ -3,58 +3,58 @@ 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";
|
||||
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";
|
||||
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";
|
||||
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";
|
||||
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;
|
||||
|
@ -102,7 +102,7 @@ mod biguint {
|
|||
mod bigint {
|
||||
use num_bigint::BigInt;
|
||||
use num_integer::Integer;
|
||||
use num_traits::{Num, Zero, 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) {
|
||||
|
|
|
@ -0,0 +1,317 @@
|
|||
#![cfg(feature = "quickcheck")]
|
||||
#![cfg(feature = "quickcheck_macros")]
|
||||
|
||||
extern crate num_bigint;
|
||||
extern crate num_integer;
|
||||
extern crate num_traits;
|
||||
|
||||
extern crate quickcheck;
|
||||
#[macro_use]
|
||||
extern crate quickcheck_macros;
|
||||
|
||||
use num_bigint::{BigInt, BigUint};
|
||||
use num_traits::{Num, One, Pow, Zero};
|
||||
use quickcheck::{QuickCheck, StdThreadGen, TestResult};
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_eq_reflexive(a: BigUint) -> bool {
|
||||
a == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_eq_reflexive(a: BigInt) -> bool {
|
||||
a == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_eq_symmetric(a: BigUint, b: BigUint) -> bool {
|
||||
if a == b {
|
||||
b == a
|
||||
} else {
|
||||
b != a
|
||||
}
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_eq_symmetric(a: BigInt, b: BigInt) -> bool {
|
||||
if a == b {
|
||||
b == a
|
||||
} else {
|
||||
b != a
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quickcheck_arith_primitive() {
|
||||
let gen = StdThreadGen::new(usize::max_value());
|
||||
let mut qc = QuickCheck::with_gen(gen);
|
||||
|
||||
fn test_unsigned_add_primitive(a: usize, b: usize) -> TestResult {
|
||||
let actual = BigUint::from(a) + BigUint::from(b);
|
||||
match a.checked_add(b) {
|
||||
None => TestResult::discard(),
|
||||
Some(expected) => TestResult::from_bool(BigUint::from(expected) == actual),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_signed_add_primitive(a: isize, b: isize) -> TestResult {
|
||||
let actual = BigInt::from(a) + BigInt::from(b);
|
||||
match a.checked_add(b) {
|
||||
None => TestResult::discard(),
|
||||
Some(expected) => TestResult::from_bool(BigInt::from(expected) == actual),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_unsigned_mul_primitive(a: u64, b: u64) -> bool {
|
||||
//maximum value of u64 means no overflow
|
||||
BigUint::from(a as u128 * b as u128) == BigUint::from(a) * BigUint::from(b)
|
||||
}
|
||||
|
||||
fn test_signed_mul_primitive(a: i64, b: i64) -> bool {
|
||||
//maximum value of i64 means no overflow
|
||||
BigInt::from(a as i128 * b as i128) == BigInt::from(a) * BigInt::from(b)
|
||||
}
|
||||
|
||||
fn test_unsigned_sub_primitive(a: u128, b: u128) -> bool {
|
||||
if b < a {
|
||||
BigUint::from(a - b) == BigUint::from(a) - BigUint::from(b)
|
||||
} else {
|
||||
BigUint::from(b - a) == BigUint::from(b) - BigUint::from(a)
|
||||
}
|
||||
}
|
||||
|
||||
fn test_signed_sub_primitive(a: i128, b: i128) -> bool {
|
||||
if b < a {
|
||||
BigInt::from(a - b) == BigInt::from(a) - BigInt::from(b)
|
||||
} else {
|
||||
BigInt::from(b - a) == BigInt::from(b) - BigInt::from(a)
|
||||
}
|
||||
}
|
||||
|
||||
fn test_unsigned_div_primitive(a: u128, b: u128) -> TestResult {
|
||||
if b == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
TestResult::from_bool(BigUint::from(a / b) == BigUint::from(a) / BigUint::from(b))
|
||||
}
|
||||
}
|
||||
|
||||
fn test_signed_div_primitive(a: i128, b: i128) -> TestResult {
|
||||
if b == 0 {
|
||||
TestResult::discard()
|
||||
} else {
|
||||
TestResult::from_bool(BigInt::from(a / b) == BigInt::from(a) / BigInt::from(b))
|
||||
}
|
||||
}
|
||||
|
||||
qc.quickcheck(test_unsigned_add_primitive as fn(usize, usize) -> TestResult);
|
||||
qc.quickcheck(test_signed_add_primitive as fn(isize, isize) -> TestResult);
|
||||
qc.quickcheck(test_unsigned_mul_primitive as fn(u64, u64) -> bool);
|
||||
qc.quickcheck(test_signed_mul_primitive as fn(i64, i64) -> bool);
|
||||
qc.quickcheck(test_unsigned_sub_primitive as fn(u128, u128) -> bool);
|
||||
qc.quickcheck(test_signed_sub_primitive as fn(i128, i128) -> bool);
|
||||
qc.quickcheck(test_unsigned_div_primitive as fn(u128, u128) -> TestResult);
|
||||
qc.quickcheck(test_signed_div_primitive as fn(i128, i128) -> TestResult);
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_add_commutative(a: BigUint, b: BigUint) -> bool {
|
||||
&a + &b == b + a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_add_commutative(a: BigInt, b: BigInt) -> bool {
|
||||
&a + &b == b + a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_add_zero(a: BigUint) -> bool {
|
||||
a == &a + BigUint::zero()
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_add_zero(a: BigInt) -> bool {
|
||||
a == &a + BigInt::zero()
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_add_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
|
||||
(&a + &b) + &c == a + (b + c)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_add_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
|
||||
(&a + &b) + &c == a + (b + c)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_mul_zero(a: BigUint) -> bool {
|
||||
a * BigUint::zero() == BigUint::zero()
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_mul_zero(a: BigInt) -> bool {
|
||||
a * BigInt::zero() == BigInt::zero()
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_mul_one(a: BigUint) -> bool {
|
||||
&a * BigUint::one() == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_mul_one(a: BigInt) -> bool {
|
||||
&a * BigInt::one() == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_mul_commutative(a: BigUint, b: BigUint) -> bool {
|
||||
&a * &b == b * a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_mul_commutative(a: BigInt, b: BigInt) -> bool {
|
||||
&a * &b == b * a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_mul_associative(a: BigUint, b: BigUint, c: BigUint) -> bool {
|
||||
(&a * &b) * &c == a * (b * c)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_mul_associative(a: BigInt, b: BigInt, c: BigInt) -> bool {
|
||||
(&a * &b) * &c == a * (b * c)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_distributive(a: BigUint, b: BigUint, c: BigUint) -> bool {
|
||||
&a * (&b + &c) == &a * b + a * c
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_distributive(a: BigInt, b: BigInt, c: BigInt) -> bool {
|
||||
&a * (&b + &c) == &a * b + a * c
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
///Tests that exactly one of a<b a>b a=b is true
|
||||
fn quickcheck_unsigned_ge_le_eq_mut_exclusive(a: BigUint, b: BigUint) -> bool {
|
||||
let gt_lt_eq = vec![a > b, a < b, a == b];
|
||||
gt_lt_eq
|
||||
.iter()
|
||||
.fold(0, |acc, e| if *e { acc + 1 } else { acc })
|
||||
== 1
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
///Tests that exactly one of a<b a>b a=b is true
|
||||
fn quickcheck_signed_ge_le_eq_mut_exclusive(a: BigInt, b: BigInt) -> bool {
|
||||
let gt_lt_eq = vec![a > b, a < b, a == b];
|
||||
gt_lt_eq
|
||||
.iter()
|
||||
.fold(0, |acc, e| if *e { acc + 1 } else { acc })
|
||||
== 1
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
/// Tests correctness of subtraction assuming addition is correct
|
||||
fn quickcheck_unsigned_sub(a: BigUint, b: BigUint) -> bool {
|
||||
if b < a {
|
||||
&a - &b + b == a
|
||||
} else {
|
||||
&b - &a + a == b
|
||||
}
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
/// Tests correctness of subtraction assuming addition is correct
|
||||
fn quickcheck_signed_sub(a: BigInt, b: BigInt) -> bool {
|
||||
if b < a {
|
||||
&a - &b + b == a
|
||||
} else {
|
||||
&b - &a + a == b
|
||||
}
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_pow_zero(a: BigUint) -> bool {
|
||||
a.pow(0_u32) == BigUint::one()
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_pow_one(a: BigUint) -> bool {
|
||||
a.pow(1_u32) == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_sqrt(a: BigUint) -> bool {
|
||||
(&a * &a).sqrt() == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_cbrt(a: BigUint) -> bool {
|
||||
(&a * &a * &a).cbrt() == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_cbrt(a: BigInt) -> bool {
|
||||
(&a * &a * &a).cbrt() == a
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_unsigned_conversion(a: BigUint, radix: u8) -> TestResult {
|
||||
let radix = radix as u32;
|
||||
if radix > 36 || radix < 2 {
|
||||
return TestResult::discard();
|
||||
}
|
||||
let string = a.to_str_radix(radix);
|
||||
TestResult::from_bool(a == BigUint::from_str_radix(&string, radix).unwrap())
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_signed_conversion(a: BigInt, radix: u8) -> TestResult {
|
||||
let radix = radix as u32;
|
||||
if radix > 36 || radix < 2 {
|
||||
return TestResult::discard();
|
||||
}
|
||||
let string = a.to_str_radix(radix);
|
||||
TestResult::from_bool(a == BigInt::from_str_radix(&string, radix).unwrap())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quicktest_shift() {
|
||||
let gen = StdThreadGen::new(usize::max_value());
|
||||
let mut qc = QuickCheck::with_gen(gen);
|
||||
|
||||
fn test_shr_unsigned(a: u64, shift: u8) -> TestResult {
|
||||
let shift = (shift % 64) as usize; //shift at most 64 bits
|
||||
let big_a = BigUint::from(a);
|
||||
TestResult::from_bool(BigUint::from(a >> shift) == big_a >> shift)
|
||||
}
|
||||
|
||||
fn test_shr_signed(a: i64, shift: u8) -> TestResult {
|
||||
let shift = (shift % 64) as usize; //shift at most 64 bits
|
||||
let big_a = BigInt::from(a);
|
||||
TestResult::from_bool(BigInt::from(a >> shift) == big_a >> shift)
|
||||
}
|
||||
|
||||
fn test_shl_unsigned(a: u32, shift: u8) -> TestResult {
|
||||
let shift = (shift % 32) as usize; //shift at most 32 bits
|
||||
let a = a as u64; //leave room for the shifted bits
|
||||
let big_a = BigUint::from(a);
|
||||
TestResult::from_bool(BigUint::from(a >> shift) == big_a >> shift)
|
||||
}
|
||||
|
||||
fn test_shl_signed(a: i32, shift: u8) -> TestResult {
|
||||
let shift = (shift % 32) as usize;
|
||||
let a = a as u64; //leave room for the shifted bits
|
||||
let big_a = BigInt::from(a);
|
||||
TestResult::from_bool(BigInt::from(a >> shift) == big_a >> shift)
|
||||
}
|
||||
|
||||
qc.quickcheck(test_shr_unsigned as fn(u64, u8) -> TestResult);
|
||||
qc.quickcheck(test_shr_signed as fn(i64, u8) -> TestResult);
|
||||
qc.quickcheck(test_shl_unsigned as fn(u32, u8) -> TestResult);
|
||||
qc.quickcheck(test_shl_signed as fn(i32, u8) -> TestResult);
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
#![cfg(feature = "rand")]
|
||||
|
||||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
extern crate rand;
|
||||
|
||||
mod biguint {
|
||||
use num_bigint::{BigUint, RandBigInt, RandomBits};
|
||||
use num_traits::Zero;
|
||||
use rand::distributions::Uniform;
|
||||
use rand::thread_rng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
#[test]
|
||||
fn test_rand() {
|
||||
let mut rng = thread_rng();
|
||||
let n: BigUint = rng.gen_biguint(137);
|
||||
assert!(n.bits() <= 137);
|
||||
assert!(rng.gen_biguint(0).is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_bits() {
|
||||
let mut rng = thread_rng();
|
||||
let n: BigUint = rng.sample(&RandomBits::new(137));
|
||||
assert!(n.bits() <= 137);
|
||||
let z: BigUint = rng.sample(&RandomBits::new(0));
|
||||
assert!(z.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_range() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for _ in 0..10 {
|
||||
assert_eq!(
|
||||
rng.gen_biguint_range(&BigUint::from(236u32), &BigUint::from(237u32)),
|
||||
BigUint::from(236u32)
|
||||
);
|
||||
}
|
||||
|
||||
let l = BigUint::from(403469000u32 + 2352);
|
||||
let u = BigUint::from(403469000u32 + 3513);
|
||||
for _ in 0..1000 {
|
||||
let n: BigUint = rng.gen_biguint_below(&u);
|
||||
assert!(n < u);
|
||||
|
||||
let n: BigUint = rng.gen_biguint_range(&l, &u);
|
||||
assert!(n >= l);
|
||||
assert!(n < u);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_zero_rand_range() {
|
||||
thread_rng().gen_biguint_range(&BigUint::from(54u32), &BigUint::from(54u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_negative_rand_range() {
|
||||
let mut rng = thread_rng();
|
||||
let l = BigUint::from(2352u32);
|
||||
let u = BigUint::from(3513u32);
|
||||
// Switching u and l should fail:
|
||||
let _n: BigUint = rng.gen_biguint_range(&u, &l);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_uniform() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let tiny = Uniform::new(BigUint::from(236u32), BigUint::from(237u32));
|
||||
for _ in 0..10 {
|
||||
assert_eq!(rng.sample(&tiny), BigUint::from(236u32));
|
||||
}
|
||||
|
||||
let l = BigUint::from(403469000u32 + 2352);
|
||||
let u = BigUint::from(403469000u32 + 3513);
|
||||
let below = Uniform::new(BigUint::zero(), u.clone());
|
||||
let range = Uniform::new(l.clone(), u.clone());
|
||||
for _ in 0..1000 {
|
||||
let n: BigUint = rng.sample(&below);
|
||||
assert!(n < u);
|
||||
|
||||
let n: BigUint = rng.sample(&range);
|
||||
assert!(n >= l);
|
||||
assert!(n < u);
|
||||
}
|
||||
}
|
||||
|
||||
fn seeded_value_stability<R: SeedableRng + RandBigInt>(expected: &[&str]) {
|
||||
let mut seed = <R::Seed>::default();
|
||||
for (i, x) in seed.as_mut().iter_mut().enumerate() {
|
||||
*x = (i as u8).wrapping_mul(191);
|
||||
}
|
||||
let mut rng = R::from_seed(seed);
|
||||
for (i, &s) in expected.iter().enumerate() {
|
||||
let n: BigUint = s.parse().unwrap();
|
||||
let r = rng.gen_biguint((1 << i) + i);
|
||||
assert_eq!(n, r);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chacha_value_stability() {
|
||||
const EXPECTED: &[&str] = &[
|
||||
"0",
|
||||
"0",
|
||||
"52",
|
||||
"84",
|
||||
"23780",
|
||||
"86502865016",
|
||||
"187057847319509867386",
|
||||
"34045731223080904464438757488196244981910",
|
||||
"23813754422987836414755953516143692594193066497413249270287126597896871975915808",
|
||||
"57401636903146945411652549098818446911814352529449356393690984105383482703074355\
|
||||
67088360974672291353736011718191813678720755501317478656550386324355699624671",
|
||||
];
|
||||
use rand::prng::ChaChaRng;
|
||||
seeded_value_stability::<ChaChaRng>(EXPECTED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_isaac_value_stability() {
|
||||
const EXPECTED: &[&str] = &[
|
||||
"1",
|
||||
"4",
|
||||
"3",
|
||||
"649",
|
||||
"89116",
|
||||
"7730042024",
|
||||
"20773149082453254949",
|
||||
"35999009049239918667571895439206839620281",
|
||||
"10191757312714088681302309313551624007714035309632506837271600807524767413673006",
|
||||
"37805949268912387809989378008822038725134260145886913321084097194957861133272558\
|
||||
43458183365174899239251448892645546322463253898288141861183340823194379722556",
|
||||
];
|
||||
use rand::prng::IsaacRng;
|
||||
seeded_value_stability::<IsaacRng>(EXPECTED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xorshift_value_stability() {
|
||||
const EXPECTED: &[&str] = &[
|
||||
"1",
|
||||
"0",
|
||||
"37",
|
||||
"395",
|
||||
"181116",
|
||||
"122718231117",
|
||||
"1068467172329355695001",
|
||||
"28246925743544411614293300167064395633287",
|
||||
"12750053187017853048648861493745244146555950255549630854523304068318587267293038",
|
||||
"53041498719137109355568081064978196049094604705283682101683207799515709404788873\
|
||||
53417136457745727045473194367732849819278740266658219147356315674940229288531",
|
||||
];
|
||||
use rand::prng::XorShiftRng;
|
||||
seeded_value_stability::<XorShiftRng>(EXPECTED);
|
||||
}
|
||||
}
|
||||
|
||||
mod bigint {
|
||||
use num_bigint::{BigInt, RandBigInt, RandomBits};
|
||||
use num_traits::Zero;
|
||||
use rand::distributions::Uniform;
|
||||
use rand::thread_rng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
#[test]
|
||||
fn test_rand() {
|
||||
let mut rng = thread_rng();
|
||||
let n: BigInt = rng.gen_bigint(137);
|
||||
assert!(n.bits() <= 137);
|
||||
assert!(rng.gen_bigint(0).is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_bits() {
|
||||
let mut rng = thread_rng();
|
||||
let n: BigInt = rng.sample(&RandomBits::new(137));
|
||||
assert!(n.bits() <= 137);
|
||||
let z: BigInt = rng.sample(&RandomBits::new(0));
|
||||
assert!(z.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_range() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
for _ in 0..10 {
|
||||
assert_eq!(
|
||||
rng.gen_bigint_range(&BigInt::from(236), &BigInt::from(237)),
|
||||
BigInt::from(236)
|
||||
);
|
||||
}
|
||||
|
||||
fn check(l: BigInt, u: BigInt) {
|
||||
let mut rng = thread_rng();
|
||||
for _ in 0..1000 {
|
||||
let n: BigInt = rng.gen_bigint_range(&l, &u);
|
||||
assert!(n >= l);
|
||||
assert!(n < u);
|
||||
}
|
||||
}
|
||||
let l: BigInt = BigInt::from(403469000 + 2352);
|
||||
let u: BigInt = BigInt::from(403469000 + 3513);
|
||||
check(l.clone(), u.clone());
|
||||
check(-l.clone(), u.clone());
|
||||
check(-u.clone(), -l.clone());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_zero_rand_range() {
|
||||
thread_rng().gen_bigint_range(&BigInt::from(54), &BigInt::from(54));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_negative_rand_range() {
|
||||
let mut rng = thread_rng();
|
||||
let l = BigInt::from(2352);
|
||||
let u = BigInt::from(3513);
|
||||
// Switching u and l should fail:
|
||||
let _n: BigInt = rng.gen_bigint_range(&u, &l);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_uniform() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let tiny = Uniform::new(BigInt::from(236u32), BigInt::from(237u32));
|
||||
for _ in 0..10 {
|
||||
assert_eq!(rng.sample(&tiny), BigInt::from(236u32));
|
||||
}
|
||||
|
||||
fn check(l: BigInt, u: BigInt) {
|
||||
let mut rng = thread_rng();
|
||||
let range = Uniform::new(l.clone(), u.clone());
|
||||
for _ in 0..1000 {
|
||||
let n: BigInt = rng.sample(&range);
|
||||
assert!(n >= l);
|
||||
assert!(n < u);
|
||||
}
|
||||
}
|
||||
let l: BigInt = BigInt::from(403469000 + 2352);
|
||||
let u: BigInt = BigInt::from(403469000 + 3513);
|
||||
check(l.clone(), u.clone());
|
||||
check(-l.clone(), u.clone());
|
||||
check(-u.clone(), -l.clone());
|
||||
}
|
||||
|
||||
fn seeded_value_stability<R: SeedableRng + RandBigInt>(expected: &[&str]) {
|
||||
let mut seed = <R::Seed>::default();
|
||||
for (i, x) in seed.as_mut().iter_mut().enumerate() {
|
||||
*x = (i as u8).wrapping_mul(191);
|
||||
}
|
||||
let mut rng = R::from_seed(seed);
|
||||
for (i, &s) in expected.iter().enumerate() {
|
||||
let n: BigInt = s.parse().unwrap();
|
||||
let r = rng.gen_bigint((1 << i) + i);
|
||||
assert_eq!(n, r);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chacha_value_stability() {
|
||||
const EXPECTED: &[&str] = &[
|
||||
"0",
|
||||
"-6",
|
||||
"-1",
|
||||
"1321",
|
||||
"-147247",
|
||||
"8486373526",
|
||||
"-272736656290199720696",
|
||||
"2731152629387534140535423510744221288522",
|
||||
"-28820024790651190394679732038637785320661450462089347915910979466834461433196572",
|
||||
"501454570554170484799723603981439288209930393334472085317977614690773821680884844\
|
||||
8530978478667288338327570972869032358120588620346111979053742269317702532328",
|
||||
];
|
||||
use rand::prng::ChaChaRng;
|
||||
seeded_value_stability::<ChaChaRng>(EXPECTED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_isaac_value_stability() {
|
||||
const EXPECTED: &[&str] = &[
|
||||
"1",
|
||||
"0",
|
||||
"5",
|
||||
"113",
|
||||
"-132240",
|
||||
"-36348760761",
|
||||
"-365690596708430705434",
|
||||
"-14090753008246284277803606722552430292432",
|
||||
"-26313941628626248579319341019368550803676255307056857978955881718727601479436059",
|
||||
"-14563174552421101848999036239003801073335703811160945137332228646111920972691151\
|
||||
88341090358094331641182310792892459091016794928947242043358702692294695845817",
|
||||
];
|
||||
use rand::prng::IsaacRng;
|
||||
seeded_value_stability::<IsaacRng>(EXPECTED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xorshift_value_stability() {
|
||||
const EXPECTED: &[&str] = &[
|
||||
"-1",
|
||||
"-4",
|
||||
"11",
|
||||
"-1802",
|
||||
"966495",
|
||||
"-62592045703",
|
||||
"-602281783447192077116",
|
||||
"-34335811410223060575607987996861632509125",
|
||||
"29156580925282215857325937227200350542000244609280383263289720243118706105351199",
|
||||
"49920038676141573457451407325930326489996232208489690499754573826911037849083623\
|
||||
24546142615325187412887314466195222441945661833644117700809693098722026764846",
|
||||
];
|
||||
use rand::prng::XorShiftRng;
|
||||
seeded_value_stability::<XorShiftRng>(EXPECTED);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
//! Test serialization and deserialization of `BigUint` and `BigInt`
|
||||
//!
|
||||
//! The serialized formats should not change, even if we change our
|
||||
//! internal representation, because we want to preserve forward and
|
||||
//! backward compatibility of serialized data!
|
||||
|
||||
#![cfg(feature = "serde")]
|
||||
|
||||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
extern crate serde_test;
|
||||
|
||||
use num_bigint::{BigInt, BigUint};
|
||||
use num_traits::{One, Zero};
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
#[test]
|
||||
fn biguint_zero() {
|
||||
let tokens = [Token::Seq { len: Some(0) }, Token::SeqEnd];
|
||||
assert_tokens(&BigUint::zero(), &tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bigint_zero() {
|
||||
let tokens = [
|
||||
Token::Tuple { len: 2 },
|
||||
Token::I8(0),
|
||||
Token::Seq { len: Some(0) },
|
||||
Token::SeqEnd,
|
||||
Token::TupleEnd,
|
||||
];
|
||||
assert_tokens(&BigInt::zero(), &tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn biguint_one() {
|
||||
let tokens = [Token::Seq { len: Some(1) }, Token::U32(1), Token::SeqEnd];
|
||||
assert_tokens(&BigUint::one(), &tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bigint_one() {
|
||||
let tokens = [
|
||||
Token::Tuple { len: 2 },
|
||||
Token::I8(1),
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::U32(1),
|
||||
Token::SeqEnd,
|
||||
Token::TupleEnd,
|
||||
];
|
||||
assert_tokens(&BigInt::one(), &tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bigint_negone() {
|
||||
let tokens = [
|
||||
Token::Tuple { len: 2 },
|
||||
Token::I8(-1),
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::U32(1),
|
||||
Token::SeqEnd,
|
||||
Token::TupleEnd,
|
||||
];
|
||||
assert_tokens(&-BigInt::one(), &tokens);
|
||||
}
|
||||
|
||||
// Generated independently from python `hex(factorial(100))`
|
||||
const FACTORIAL_100: &'static [u32] = &[
|
||||
0x00000000, 0x00000000, 0x00000000, 0x2735c61a, 0xee8b02ea, 0xb3b72ed2, 0x9420c6ec, 0x45570cca,
|
||||
0xdf103917, 0x943a321c, 0xeb21b5b2, 0x66ef9a70, 0xa40d16e9, 0x28d54bbd, 0xdc240695, 0x964ec395,
|
||||
0x1b30,
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn biguint_factorial_100() {
|
||||
let n: BigUint = (1u8..101).product();
|
||||
|
||||
let mut tokens = vec![];
|
||||
tokens.push(Token::Seq {
|
||||
len: Some(FACTORIAL_100.len()),
|
||||
});
|
||||
tokens.extend(FACTORIAL_100.iter().map(|&u| Token::U32(u)));
|
||||
tokens.push(Token::SeqEnd);
|
||||
|
||||
assert_tokens(&n, &tokens);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bigint_factorial_100() {
|
||||
let n: BigInt = (1i8..101).product();
|
||||
|
||||
let mut tokens = vec![];
|
||||
tokens.push(Token::Tuple { len: 2 });
|
||||
tokens.push(Token::I8(1));
|
||||
tokens.push(Token::Seq {
|
||||
len: Some(FACTORIAL_100.len()),
|
||||
});
|
||||
tokens.extend(FACTORIAL_100.iter().map(|&u| Token::U32(u)));
|
||||
tokens.push(Token::SeqEnd);
|
||||
tokens.push(Token::TupleEnd);
|
||||
|
||||
assert_tokens(&n, &tokens);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#![cfg(feature = "rand")]
|
||||
|
||||
extern crate num_bigint;
|
||||
extern crate num_traits;
|
||||
extern crate rand;
|
||||
|
||||
use num_bigint::RandBigInt;
|
||||
use num_traits::Zero;
|
||||
use rand::prelude::*;
|
||||
|
||||
fn test_mul_divide_torture_count(count: usize) {
|
||||
let bits_max = 1 << 12;
|
||||
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let mut rng = SmallRng::from_seed(seed);
|
||||
|
||||
for _ in 0..count {
|
||||
// Test with numbers of random sizes:
|
||||
let xbits = rng.gen_range(0, bits_max);
|
||||
let ybits = rng.gen_range(0, bits_max);
|
||||
|
||||
let x = rng.gen_biguint(xbits);
|
||||
let y = rng.gen_biguint(ybits);
|
||||
|
||||
if x.is_zero() || y.is_zero() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let prod = &x * &y;
|
||||
assert_eq!(&prod / &x, y);
|
||||
assert_eq!(&prod / &y, x);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mul_divide_torture() {
|
||||
test_mul_divide_torture_count(1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_mul_divide_torture_long() {
|
||||
test_mul_divide_torture_count(1000000);
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"9786af550e08e1eac4a902cc4c148729bf3cbbdf6caa803786b2f7c829ff023f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"ec49ad594875e0fc5b060af011fa82baa7e58cda2b9c50fa8f1ef9780ba3fe96","RELEASES.md":"1f79030c9864dac0e7b14dda47fa7cc8313c82621ee26739eeeb1abf0b5d1fc4","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","build.rs":"16de2aa57e754fc1526d0400b5d87a3f771296705fca54601aa598b6f74ded8f","ci/rustup.sh":"1698b0030a5b0807b10c5d0ed9e9f5fe58e1b259016007723ffd1426284473e0","ci/test_full.sh":"3538ba4ff317568a6001fa5cb0fc433b1a36df3aab58a0fc9c0487ef39ca5810","src/bounds.rs":"dfbcd607c3bc648356f38d2cc63ceb20cd5820b7da06c5758efe91d0b0642ec2","src/cast.rs":"b5bc61c83267d80d6b71f7f0effa9cd193d30e026965f749434105b66c94c78a","src/float.rs":"a33b6a812cfbfc46e6884434c036c5a8fdeb91cb353d75c352512f1294e318b1","src/identities.rs":"d9037a084657bde78a73735e9a45bac4ed41f1954d567eb28d5bc2e1338c3ea8","src/int.rs":"287f6a6193908f4bd465d930db91b190845c466e64911df1280ddb12737d78ee","src/lib.rs":"a248f6e5e80eb786a71e748c783fc99e6b01f5f3fb9c9fe2f8ba42dfeadf3414","src/macros.rs":"b589a98c2468ca98131c641a058601964c4e82d75129b1c16fdc17aca8779eca","src/ops/checked.rs":"f30376b3f23e924220bf11d8c6addd844d7c3649c8d15f5417dcdbbf43560195","src/ops/inv.rs":"dd80b9bd48d815f17855a25842287942317fa49d1fdcdd655b61bd20ef927cda","src/ops/mod.rs":"036b2a1900dc8e7295a91060e660184b2bd98f33b5db81a62b08cf8d3df726cf","src/ops/mul_add.rs":"b36e058a5c1882958417c7a4a54baa0ba181d6290821fc0859459d8b8ba3571a","src/ops/saturating.rs":"81c34038ec88fe49f4286e6e1213a1da831c5e66caac651f0a61506a4534c9ce","src/ops/wrapping.rs":"8d334dd2b8128e640bff6c3e93ea301182241987b3ed1fc158268292827bbd0c","src/pow.rs":"caad87386fb717eada6dae32a00e536e8a355bf5b4c31037f6afb163775bd218","src/real.rs":"a93ac4a48084cb49e5c97eafa54aaf0ea2f627b4e372a8b77d784c5e158d2c3c","src/sign.rs":"d82757198fe3144676316035e5574801f724821f604ad0fee892e86e83f9d802","tests/cast.rs":"2c4b4f2185ec0d687e1bde292731dbc5efec527ab393478b5adf26f6e1352231"},"package":"0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"}
|
||||
{"files":{"Cargo.toml":"35c48122af67e382695600a6af69d73c0dd907afb31914aee049eebc88c871a5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"b442afb73953744a9d2134442845d3e960984ac5be2a058e5064ae851624d67f","RELEASES.md":"683c12fd04a3185fcbfa1915d1fbce8051077c5bdf07c3bfade4606bdd92d0e4","build.rs":"b4b2d0df90ca7570a339ca4d84a72e4ef00d9dced8927350424e666790c752d7","src/bounds.rs":"4fbc6bf3550e4da7ef55c9eb96466c6e0aee7f7542d7c85cfd742f16e3b4729f","src/cast.rs":"2eae0873cbe11fa0d1a012e304f48dea6a0802c0ee738dc25683779cf15b18fb","src/float.rs":"5c1a11e4218d376cd531aff0d6546c2b590d687bda5825f8c27dc6d6f974fb9b","src/identities.rs":"5b6238ebd52e1fadd5b405bc40ad81e45346bcb1c4b46cf1f0496a30be7c9bc4","src/int.rs":"bbc014a02998848170430abf60ab80fa46d7835be3a5e8bf7d28e1c5318068ae","src/lib.rs":"beb207aa3f791811b043d7aa0daa34a2f8f3a52e0555bda8eb32e3359203a129","src/macros.rs":"b589a98c2468ca98131c641a058601964c4e82d75129b1c16fdc17aca8779eca","src/ops/checked.rs":"b6dfae21fe1a5ce41e92074c57d204284975ec56d45e63cac5f0136b8c3643b4","src/ops/inv.rs":"dd80b9bd48d815f17855a25842287942317fa49d1fdcdd655b61bd20ef927cda","src/ops/mod.rs":"036b2a1900dc8e7295a91060e660184b2bd98f33b5db81a62b08cf8d3df726cf","src/ops/mul_add.rs":"368bdebb40b16f3b4b85cf50235954268ff601ec7a458a3a83fe433f47f86f6d","src/ops/saturating.rs":"81c34038ec88fe49f4286e6e1213a1da831c5e66caac651f0a61506a4534c9ce","src/ops/wrapping.rs":"8d334dd2b8128e640bff6c3e93ea301182241987b3ed1fc158268292827bbd0c","src/pow.rs":"9f78cb9c4d5987b59e16f4141723a33ff689781cc352f357b0cc0111d22cde3a","src/real.rs":"b5115bb2cfb752a59426bb3fcbabf9cff15521a00a3f8b5ef4dfc0b0b31bb1f4","src/sign.rs":"81b1116300b5787546852d9d04f0375fa24342f85c34f5bc1ce5360b53fa411a","tests/cast.rs":"2c4b4f2185ec0d687e1bde292731dbc5efec527ab393478b5adf26f6e1352231"},"package":"d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"}
|
|
@ -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,9 +12,10 @@
|
|||
|
||||
[package]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
version = "0.2.10"
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
|
||||
description = "Numeric traits for generic mathematics"
|
||||
homepage = "https://github.com/rust-num/num-traits"
|
||||
documentation = "https://docs.rs/num-traits"
|
||||
|
@ -25,8 +26,11 @@ license = "MIT/Apache-2.0"
|
|||
repository = "https://github.com/rust-num/num-traits"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["std"]
|
||||
|
||||
[dependencies]
|
||||
[dependencies.libm]
|
||||
version = "0.2.0"
|
||||
optional = true
|
||||
[build-dependencies.autocfg]
|
||||
version = "0.1.3"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
|
|
@ -31,11 +31,14 @@ the default `std` feature. Use this in `Cargo.toml`:
|
|||
[dependencies.num-traits]
|
||||
version = "0.2"
|
||||
default-features = false
|
||||
# features = ["libm"] # <--- Uncomment if you wish to use `Float` and `Real` without `std`
|
||||
```
|
||||
|
||||
The `Float` and `Real` traits are only available when `std` is enabled. The
|
||||
`FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
|
||||
and `f64` also require `std`, as do implementations of signed and floating-
|
||||
The `Float` and `Real` traits are only available when either `std` or `libm` is enabled.
|
||||
The `libm` feature is only available with Rust 1.31 and later ([see PR #99](https://github.com/rust-num/num-traits/pull/99)).
|
||||
|
||||
The `FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32`
|
||||
and `f64` also require `std` or `libm`, as do implementations of signed and floating-
|
||||
point exponents in `Pow`.
|
||||
|
||||
Implementations for `i128` and `u128` are only available with Rust 1.26 and
|
||||
|
|
|
@ -1,3 +1,48 @@
|
|||
# Release 0.2.10 (2019-11-22)
|
||||
|
||||
- [Updated the `libm` dependency to 0.2][144].
|
||||
|
||||
**Contributors**: @CryZe
|
||||
|
||||
[144]: https://github.com/rust-num/num-traits/pull/144
|
||||
|
||||
# Release 0.2.9 (2019-11-12)
|
||||
|
||||
- [A new optional `libm` dependency][99] enables the `Float` and `Real` traits
|
||||
in `no_std` builds.
|
||||
- [The new `clamp_min` and `clamp_max`][122] limit minimum and maximum values
|
||||
while preserving input `NAN`s.
|
||||
- [Fixed a panic in floating point `from_str_radix` on invalid signs][126].
|
||||
- Miscellaneous documentation updates.
|
||||
|
||||
**Contributors**: @cuviper, @dingelish, @HeroicKatora, @jturner314, @ocstl,
|
||||
@Shnatsel, @termoshtt, @waywardmonkeys, @yoanlcq
|
||||
|
||||
[99]: https://github.com/rust-num/num-traits/pull/99
|
||||
[122]: https://github.com/rust-num/num-traits/pull/122
|
||||
[126]: https://github.com/rust-num/num-traits/pull/126
|
||||
|
||||
# Release 0.2.8 (2019-05-21)
|
||||
|
||||
- [Fixed feature detection on `no_std` targets][116].
|
||||
|
||||
**Contributors**: @cuviper
|
||||
|
||||
[116]: https://github.com/rust-num/num-traits/pull/116
|
||||
|
||||
# Release 0.2.7 (2019-05-20)
|
||||
|
||||
- [Documented when `CheckedShl` and `CheckedShr` return `None`][90].
|
||||
- [The new `Zero::set_zero` and `One::set_one`][104] will set values to their
|
||||
identities in place, possibly optimized better than direct assignment.
|
||||
- [Documented general features and intentions of `PrimInt`][108].
|
||||
|
||||
**Contributors**: @cuviper, @dvdhrm, @ignatenkobrain, @lcnr, @samueltardieu
|
||||
|
||||
[90]: https://github.com/rust-num/num-traits/pull/90
|
||||
[104]: https://github.com/rust-num/num-traits/pull/104
|
||||
[108]: https://github.com/rust-num/num-traits/pull/108
|
||||
|
||||
# Release 0.2.6 (2018-09-13)
|
||||
|
||||
- [Documented that `pow(0, 0)` returns `1`][79]. Mathematically, this is not
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
status = [
|
||||
"continuous-integration/travis-ci/push",
|
||||
]
|
|
@ -1,35 +1,14 @@
|
|||
extern crate autocfg;
|
||||
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
if probe("fn main() { 0i128; }") {
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
/// 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()
|
||||
|
||||
autocfg::rerun_path("build.rs");
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#!/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 $PWD/ci/test_full.sh
|
||||
done
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
echo Testing num-traits on rustc ${TRAVIS_RUST_VERSION}
|
||||
|
||||
# num-traits 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
|
|
@ -95,8 +95,8 @@ fn wrapping_bounded() {
|
|||
macro_rules! test_wrapping_bounded {
|
||||
($($t:ty)+) => {
|
||||
$(
|
||||
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ fn wrapping_bounded_i128() {
|
|||
macro_rules! test_wrapping_bounded {
|
||||
($($t:ty)+) => {
|
||||
$(
|
||||
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::min_value().0, <$t>::min_value());
|
||||
assert_eq!(<Wrapping<$t> as Bounded>::max_value().0, <$t>::max_value());
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,38 +10,45 @@ use float::FloatCore;
|
|||
|
||||
/// A generic trait for converting a value to a number.
|
||||
pub trait ToPrimitive {
|
||||
/// Converts the value of `self` to an `isize`.
|
||||
/// Converts the value of `self` to an `isize`. If the value cannot be
|
||||
/// represented by an `isize`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> {
|
||||
self.to_i64().as_ref().and_then(ToPrimitive::to_isize)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i8`.
|
||||
/// Converts the value of `self` to an `i8`. If the value cannot be
|
||||
/// represented by an `i8`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> {
|
||||
self.to_i64().as_ref().and_then(ToPrimitive::to_i8)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i16`.
|
||||
/// Converts the value of `self` to an `i16`. If the value cannot be
|
||||
/// represented by an `i16`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> {
|
||||
self.to_i64().as_ref().and_then(ToPrimitive::to_i16)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i32`.
|
||||
/// Converts the value of `self` to an `i32`. If the value cannot be
|
||||
/// represented by an `i32`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> {
|
||||
self.to_i64().as_ref().and_then(ToPrimitive::to_i32)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i64`.
|
||||
/// Converts the value of `self` to an `i64`. If the value cannot be
|
||||
/// represented by an `i64`, then `None` is returned.
|
||||
fn to_i64(&self) -> Option<i64>;
|
||||
|
||||
/// Converts the value of `self` to an `i128`.
|
||||
/// Converts the value of `self` to an `i128`. If the value cannot be
|
||||
/// represented by an `i128` (`i64` under the default implementation), then
|
||||
/// `None` is returned.
|
||||
///
|
||||
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
|
||||
///
|
||||
/// The default implementation converts through `to_i64()`. Types implementing
|
||||
/// The default implementation converts through `to_i64()`. Types implementing
|
||||
/// this trait should override this method if they can represent a greater range.
|
||||
#[inline]
|
||||
#[cfg(has_i128)]
|
||||
|
@ -49,35 +56,41 @@ pub trait ToPrimitive {
|
|||
self.to_i64().map(From::from)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to a `usize`.
|
||||
/// Converts the value of `self` to a `usize`. If the value cannot be
|
||||
/// represented by a `usize`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
self.to_u64().as_ref().and_then(ToPrimitive::to_usize)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u8`.
|
||||
/// Converts the value of `self` to a `u8`. If the value cannot be
|
||||
/// represented by a `u8`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> {
|
||||
self.to_u64().as_ref().and_then(ToPrimitive::to_u8)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u16`.
|
||||
/// Converts the value of `self` to a `u16`. If the value cannot be
|
||||
/// represented by a `u16`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> {
|
||||
self.to_u64().as_ref().and_then(ToPrimitive::to_u16)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u32`.
|
||||
/// Converts the value of `self` to a `u32`. If the value cannot be
|
||||
/// represented by a `u32`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> {
|
||||
self.to_u64().as_ref().and_then(ToPrimitive::to_u32)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u64`.
|
||||
#[inline]
|
||||
/// Converts the value of `self` to a `u64`. If the value cannot be
|
||||
/// represented by a `u64`, then `None` is returned.
|
||||
fn to_u64(&self) -> Option<u64>;
|
||||
|
||||
/// Converts the value of `self` to an `u128`.
|
||||
/// Converts the value of `self` to a `u128`. If the value cannot be
|
||||
/// represented by a `u128` (`u64` under the default implementation), then
|
||||
/// `None` is returned.
|
||||
///
|
||||
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
|
||||
///
|
||||
|
@ -89,13 +102,15 @@ pub trait ToPrimitive {
|
|||
self.to_u64().map(From::from)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `f32`.
|
||||
/// Converts the value of `self` to an `f32`. If the value cannot be
|
||||
/// represented by an `f32`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> {
|
||||
self.to_f64().as_ref().and_then(ToPrimitive::to_f32)
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `f64`.
|
||||
/// Converts the value of `self` to an `f64`. If the value cannot be
|
||||
/// represented by an `f64`, then `None` is returned.
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> {
|
||||
match self.to_i64() {
|
||||
|
@ -362,44 +377,44 @@ impl_to_primitive_float!(f64);
|
|||
|
||||
/// A generic trait for converting a number to a value.
|
||||
pub trait FromPrimitive: Sized {
|
||||
/// Convert an `isize` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `isize` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
n.to_i64().and_then(FromPrimitive::from_i64)
|
||||
}
|
||||
|
||||
/// Convert an `i8` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `i8` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
FromPrimitive::from_i64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert an `i16` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `i16` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
FromPrimitive::from_i64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert an `i32` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `i32` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
FromPrimitive::from_i64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert an `i64` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `i64` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
fn from_i64(n: i64) -> Option<Self>;
|
||||
|
||||
/// Convert an `i128` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `i128` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
///
|
||||
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
|
||||
///
|
||||
/// The default implementation converts through `from_i64()`. Types implementing
|
||||
/// The default implementation converts through `from_i64()`. Types implementing
|
||||
/// this trait should override this method if they can represent a greater range.
|
||||
#[inline]
|
||||
#[cfg(has_i128)]
|
||||
|
@ -407,44 +422,44 @@ pub trait FromPrimitive: Sized {
|
|||
n.to_i64().and_then(FromPrimitive::from_i64)
|
||||
}
|
||||
|
||||
/// Convert a `usize` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts a `usize` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
n.to_u64().and_then(FromPrimitive::from_u64)
|
||||
}
|
||||
|
||||
/// Convert an `u8` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `u8` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
FromPrimitive::from_u64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert an `u16` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `u16` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
FromPrimitive::from_u64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert an `u32` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `u32` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
FromPrimitive::from_u64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert an `u64` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `u64` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
fn from_u64(n: u64) -> Option<Self>;
|
||||
|
||||
/// Convert an `u128` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts an `u128` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
///
|
||||
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
|
||||
///
|
||||
/// The default implementation converts through `from_u64()`. Types implementing
|
||||
/// The default implementation converts through `from_u64()`. Types implementing
|
||||
/// this trait should override this method if they can represent a greater range.
|
||||
#[inline]
|
||||
#[cfg(has_i128)]
|
||||
|
@ -452,15 +467,15 @@ pub trait FromPrimitive: Sized {
|
|||
n.to_u64().and_then(FromPrimitive::from_u64)
|
||||
}
|
||||
|
||||
/// Convert a `f32` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts a `f32` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_f32(n: f32) -> Option<Self> {
|
||||
FromPrimitive::from_f64(From::from(n))
|
||||
}
|
||||
|
||||
/// Convert a `f64` to return an optional value of this type. If the
|
||||
/// type cannot be represented by this value, then `None` is returned.
|
||||
/// Converts a `f64` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this type, then `None` is returned.
|
||||
#[inline]
|
||||
fn from_f64(n: f64) -> Option<Self> {
|
||||
match n.to_i64() {
|
||||
|
@ -639,7 +654,8 @@ pub fn cast<T: NumCast, U: NumCast>(n: T) -> Option<U> {
|
|||
/// An interface for casting between machine scalars.
|
||||
pub trait NumCast: Sized + ToPrimitive {
|
||||
/// Creates a number from another value that can be converted into
|
||||
/// a primitive via the `ToPrimitive` trait.
|
||||
/// a primitive via the `ToPrimitive` trait. If the source value cannot be
|
||||
/// represented by the target type, then `None` is returned.
|
||||
fn from<T: ToPrimitive>(n: T) -> Option<Self>;
|
||||
}
|
||||
|
||||
|
@ -682,7 +698,7 @@ impl<T: NumCast> NumCast for Wrapping<T> {
|
|||
|
||||
/// A generic interface for casting between machine scalars with the
|
||||
/// `as` operator, which admits narrowing and precision loss.
|
||||
/// Implementers of this trait AsPrimitive should behave like a primitive
|
||||
/// Implementers of this trait `AsPrimitive` should behave like a primitive
|
||||
/// numeric type (e.g. a newtype around another primitive), and the
|
||||
/// intended conversion must never fail.
|
||||
///
|
||||
|
|
|
@ -7,6 +7,9 @@ use core::f64;
|
|||
|
||||
use {Num, NumCast, ToPrimitive};
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
use libm;
|
||||
|
||||
/// Generic trait for floating point numbers that works with `no_std`.
|
||||
///
|
||||
/// This trait implements a subset of the `Float` trait.
|
||||
|
@ -766,6 +769,8 @@ impl FloatCore for f32 {
|
|||
const EXP_MASK: u32 = 0x7f800000;
|
||||
const MAN_MASK: u32 = 0x007fffff;
|
||||
|
||||
// Safety: this identical to the implementation of f32::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u32 = unsafe { mem::transmute(self) };
|
||||
match (bits & MAN_MASK, bits & EXP_MASK) {
|
||||
(0, 0) => FpCategory::Zero,
|
||||
|
@ -838,6 +843,8 @@ impl FloatCore for f64 {
|
|||
const EXP_MASK: u64 = 0x7ff0000000000000;
|
||||
const MAN_MASK: u64 = 0x000fffffffffffff;
|
||||
|
||||
// Safety: this identical to the implementation of f64::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u64 = unsafe { mem::transmute(self) };
|
||||
match (bits & MAN_MASK, bits & EXP_MASK) {
|
||||
(0, 0) => FpCategory::Zero,
|
||||
|
@ -893,8 +900,8 @@ impl FloatCore for f64 {
|
|||
|
||||
/// Generic trait for floating point numbers
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
#[cfg(feature = "std")]
|
||||
/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
||||
/// Returns the `NaN` value.
|
||||
///
|
||||
|
@ -1802,7 +1809,7 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! float_impl {
|
||||
macro_rules! float_impl_std {
|
||||
($T:ident $decode:ident) => {
|
||||
impl Float for $T {
|
||||
constant! {
|
||||
|
@ -1880,7 +1887,57 @@ macro_rules! float_impl {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
macro_rules! float_impl_libm {
|
||||
($T:ident $decode:ident) => {
|
||||
constant! {
|
||||
nan() -> $T::NAN;
|
||||
infinity() -> $T::INFINITY;
|
||||
neg_infinity() -> $T::NEG_INFINITY;
|
||||
neg_zero() -> -0.0;
|
||||
min_value() -> $T::MIN;
|
||||
min_positive_value() -> $T::MIN_POSITIVE;
|
||||
epsilon() -> $T::EPSILON;
|
||||
max_value() -> $T::MAX;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn integer_decode(self) -> (u64, i16, i8) {
|
||||
$decode(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fract(self) -> Self {
|
||||
self - FloatCore::trunc(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn log(self, base: Self) -> Self {
|
||||
self.ln() / base.ln()
|
||||
}
|
||||
|
||||
forward! {
|
||||
FloatCore::is_nan(self) -> bool;
|
||||
FloatCore::is_infinite(self) -> bool;
|
||||
FloatCore::is_finite(self) -> bool;
|
||||
FloatCore::is_normal(self) -> bool;
|
||||
FloatCore::classify(self) -> FpCategory;
|
||||
FloatCore::signum(self) -> Self;
|
||||
FloatCore::is_sign_positive(self) -> bool;
|
||||
FloatCore::is_sign_negative(self) -> bool;
|
||||
FloatCore::recip(self) -> Self;
|
||||
FloatCore::powi(self, n: i32) -> Self;
|
||||
FloatCore::to_degrees(self) -> Self;
|
||||
FloatCore::to_radians(self) -> Self;
|
||||
FloatCore::max(self, other: Self) -> Self;
|
||||
FloatCore::min(self, other: Self) -> Self;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
||||
// Safety: this identical to the implementation of f32::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u32 = unsafe { mem::transmute(f) };
|
||||
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
|
||||
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
||||
|
@ -1895,6 +1952,8 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
|||
}
|
||||
|
||||
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
||||
// Safety: this identical to the implementation of f64::to_bits(),
|
||||
// which is only available starting at Rust 1.20
|
||||
let bits: u64 = unsafe { mem::transmute(f) };
|
||||
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
|
||||
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
||||
|
@ -1909,9 +1968,279 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
|||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
float_impl!(f32 integer_decode_f32);
|
||||
float_impl_std!(f32 integer_decode_f32);
|
||||
#[cfg(feature = "std")]
|
||||
float_impl!(f64 integer_decode_f64);
|
||||
float_impl_std!(f64 integer_decode_f64);
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
impl Float for f32 {
|
||||
float_impl_libm!(f32 integer_decode_f32);
|
||||
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
fn abs_sub(self, other: Self) -> Self {
|
||||
libm::fdimf(self, other)
|
||||
}
|
||||
#[inline]
|
||||
fn floor(self) -> Self {
|
||||
libm::floorf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn ceil(self) -> Self {
|
||||
libm::ceilf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn round(self) -> Self {
|
||||
libm::roundf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn trunc(self) -> Self {
|
||||
libm::truncf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn abs(self) -> Self {
|
||||
libm::fabsf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self {
|
||||
libm::fmaf(self, a, b)
|
||||
}
|
||||
#[inline]
|
||||
fn powf(self, n: Self) -> Self {
|
||||
libm::powf(self, n)
|
||||
}
|
||||
#[inline]
|
||||
fn sqrt(self) -> Self {
|
||||
libm::sqrtf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn exp(self) -> Self {
|
||||
libm::expf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn exp2(self) -> Self {
|
||||
libm::exp2f(self)
|
||||
}
|
||||
#[inline]
|
||||
fn ln(self) -> Self {
|
||||
libm::logf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn log2(self) -> Self {
|
||||
libm::log2f(self)
|
||||
}
|
||||
#[inline]
|
||||
fn log10(self) -> Self {
|
||||
libm::log10f(self)
|
||||
}
|
||||
#[inline]
|
||||
fn cbrt(self) -> Self {
|
||||
libm::cbrtf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn hypot(self, other: Self) -> Self {
|
||||
libm::hypotf(self, other)
|
||||
}
|
||||
#[inline]
|
||||
fn sin(self) -> Self {
|
||||
libm::sinf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn cos(self) -> Self {
|
||||
libm::cosf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn tan(self) -> Self {
|
||||
libm::tanf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn asin(self) -> Self {
|
||||
libm::asinf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn acos(self) -> Self {
|
||||
libm::acosf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn atan(self) -> Self {
|
||||
libm::atanf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn atan2(self, other: Self) -> Self {
|
||||
libm::atan2f(self, other)
|
||||
}
|
||||
#[inline]
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
libm::sincosf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn exp_m1(self) -> Self {
|
||||
libm::expm1f(self)
|
||||
}
|
||||
#[inline]
|
||||
fn ln_1p(self) -> Self {
|
||||
libm::log1pf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn sinh(self) -> Self {
|
||||
libm::sinhf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn cosh(self) -> Self {
|
||||
libm::coshf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn tanh(self) -> Self {
|
||||
libm::tanhf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn asinh(self) -> Self {
|
||||
libm::asinhf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn acosh(self) -> Self {
|
||||
libm::acoshf(self)
|
||||
}
|
||||
#[inline]
|
||||
fn atanh(self) -> Self {
|
||||
libm::atanhf(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
impl Float for f64 {
|
||||
float_impl_libm!(f64 integer_decode_f64);
|
||||
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
fn abs_sub(self, other: Self) -> Self {
|
||||
libm::fdim(self, other)
|
||||
}
|
||||
#[inline]
|
||||
fn floor(self) -> Self {
|
||||
libm::floor(self)
|
||||
}
|
||||
#[inline]
|
||||
fn ceil(self) -> Self {
|
||||
libm::ceil(self)
|
||||
}
|
||||
#[inline]
|
||||
fn round(self) -> Self {
|
||||
libm::round(self)
|
||||
}
|
||||
#[inline]
|
||||
fn trunc(self) -> Self {
|
||||
libm::trunc(self)
|
||||
}
|
||||
#[inline]
|
||||
fn abs(self) -> Self {
|
||||
libm::fabs(self)
|
||||
}
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self {
|
||||
libm::fma(self, a, b)
|
||||
}
|
||||
#[inline]
|
||||
fn powf(self, n: Self) -> Self {
|
||||
libm::pow(self, n)
|
||||
}
|
||||
#[inline]
|
||||
fn sqrt(self) -> Self {
|
||||
libm::sqrt(self)
|
||||
}
|
||||
#[inline]
|
||||
fn exp(self) -> Self {
|
||||
libm::exp(self)
|
||||
}
|
||||
#[inline]
|
||||
fn exp2(self) -> Self {
|
||||
libm::exp2(self)
|
||||
}
|
||||
#[inline]
|
||||
fn ln(self) -> Self {
|
||||
libm::log(self)
|
||||
}
|
||||
#[inline]
|
||||
fn log2(self) -> Self {
|
||||
libm::log2(self)
|
||||
}
|
||||
#[inline]
|
||||
fn log10(self) -> Self {
|
||||
libm::log10(self)
|
||||
}
|
||||
#[inline]
|
||||
fn cbrt(self) -> Self {
|
||||
libm::cbrt(self)
|
||||
}
|
||||
#[inline]
|
||||
fn hypot(self, other: Self) -> Self {
|
||||
libm::hypot(self, other)
|
||||
}
|
||||
#[inline]
|
||||
fn sin(self) -> Self {
|
||||
libm::sin(self)
|
||||
}
|
||||
#[inline]
|
||||
fn cos(self) -> Self {
|
||||
libm::cos(self)
|
||||
}
|
||||
#[inline]
|
||||
fn tan(self) -> Self {
|
||||
libm::tan(self)
|
||||
}
|
||||
#[inline]
|
||||
fn asin(self) -> Self {
|
||||
libm::asin(self)
|
||||
}
|
||||
#[inline]
|
||||
fn acos(self) -> Self {
|
||||
libm::acos(self)
|
||||
}
|
||||
#[inline]
|
||||
fn atan(self) -> Self {
|
||||
libm::atan(self)
|
||||
}
|
||||
#[inline]
|
||||
fn atan2(self, other: Self) -> Self {
|
||||
libm::atan2(self, other)
|
||||
}
|
||||
#[inline]
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
libm::sincos(self)
|
||||
}
|
||||
#[inline]
|
||||
fn exp_m1(self) -> Self {
|
||||
libm::expm1(self)
|
||||
}
|
||||
#[inline]
|
||||
fn ln_1p(self) -> Self {
|
||||
libm::log1p(self)
|
||||
}
|
||||
#[inline]
|
||||
fn sinh(self) -> Self {
|
||||
libm::sinh(self)
|
||||
}
|
||||
#[inline]
|
||||
fn cosh(self) -> Self {
|
||||
libm::cosh(self)
|
||||
}
|
||||
#[inline]
|
||||
fn tanh(self) -> Self {
|
||||
libm::tanh(self)
|
||||
}
|
||||
#[inline]
|
||||
fn asinh(self) -> Self {
|
||||
libm::asinh(self)
|
||||
}
|
||||
#[inline]
|
||||
fn acosh(self) -> Self {
|
||||
libm::acosh(self)
|
||||
}
|
||||
#[inline]
|
||||
fn atanh(self) -> Self {
|
||||
libm::atanh(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! float_const_impl {
|
||||
($(#[$doc:meta] $constant:ident,)+) => (
|
||||
|
@ -1994,7 +2323,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
#[test]
|
||||
fn convert_deg_rad_std() {
|
||||
for &(deg, rad) in &DEG_RAD_PAIRS {
|
||||
|
|
|
@ -2,16 +2,15 @@ use core::num::Wrapping;
|
|||
use core::ops::{Add, Mul};
|
||||
|
||||
/// Defines an additive identity element for `Self`.
|
||||
///
|
||||
/// # Laws
|
||||
///
|
||||
/// ```{.text}
|
||||
/// a + 0 = a ∀ a ∈ Self
|
||||
/// 0 + a = a ∀ a ∈ Self
|
||||
/// ```
|
||||
pub trait Zero: Sized + Add<Self, Output = Self> {
|
||||
/// Returns the additive identity element of `Self`, `0`.
|
||||
///
|
||||
/// # Laws
|
||||
///
|
||||
/// ```{.text}
|
||||
/// a + 0 = a ∀ a ∈ Self
|
||||
/// 0 + a = a ∀ a ∈ Self
|
||||
/// ```
|
||||
///
|
||||
/// # Purity
|
||||
///
|
||||
/// This function should return the same result at all times regardless of
|
||||
|
@ -20,8 +19,12 @@ pub trait Zero: Sized + Add<Self, Output = Self> {
|
|||
// This cannot be an associated constant, because of bignums.
|
||||
fn zero() -> Self;
|
||||
|
||||
/// Sets `self` to the additive identity element of `Self`, `0`.
|
||||
fn set_zero(&mut self) {
|
||||
*self = Zero::zero();
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is equal to the additive identity.
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool;
|
||||
}
|
||||
|
||||
|
@ -66,22 +69,27 @@ where
|
|||
fn is_zero(&self) -> bool {
|
||||
self.0.is_zero()
|
||||
}
|
||||
|
||||
fn set_zero(&mut self) {
|
||||
self.0.set_zero();
|
||||
}
|
||||
|
||||
fn zero() -> Self {
|
||||
Wrapping(T::zero())
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a multiplicative identity element for `Self`.
|
||||
///
|
||||
/// # Laws
|
||||
///
|
||||
/// ```{.text}
|
||||
/// a * 1 = a ∀ a ∈ Self
|
||||
/// 1 * a = a ∀ a ∈ Self
|
||||
/// ```
|
||||
pub trait One: Sized + Mul<Self, Output = Self> {
|
||||
/// Returns the multiplicative identity element of `Self`, `1`.
|
||||
///
|
||||
/// # Laws
|
||||
///
|
||||
/// ```{.text}
|
||||
/// a * 1 = a ∀ a ∈ Self
|
||||
/// 1 * a = a ∀ a ∈ Self
|
||||
/// ```
|
||||
///
|
||||
/// # Purity
|
||||
///
|
||||
/// This function should return the same result at all times regardless of
|
||||
|
@ -90,6 +98,11 @@ pub trait One: Sized + Mul<Self, Output = Self> {
|
|||
// This cannot be an associated constant, because of bignums.
|
||||
fn one() -> Self;
|
||||
|
||||
/// Sets `self` to the multiplicative identity element of `Self`, `1`.
|
||||
fn set_one(&mut self) {
|
||||
*self = One::one();
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is equal to the multiplicative identity.
|
||||
///
|
||||
/// For performance reasons, it's best to implement this manually.
|
||||
|
@ -111,6 +124,10 @@ macro_rules! one_impl {
|
|||
fn one() -> $t {
|
||||
$v
|
||||
}
|
||||
#[inline]
|
||||
fn is_one(&self) -> bool {
|
||||
*self == $v
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -138,6 +155,10 @@ impl<T: One> One for Wrapping<T>
|
|||
where
|
||||
Wrapping<T>: Mul<Output = Wrapping<T>>,
|
||||
{
|
||||
fn set_one(&mut self) {
|
||||
self.0.set_one();
|
||||
}
|
||||
|
||||
fn one() -> Self {
|
||||
Wrapping(T::one())
|
||||
}
|
||||
|
|
|
@ -5,6 +5,32 @@ use ops::checked::*;
|
|||
use ops::saturating::Saturating;
|
||||
use {Num, NumCast};
|
||||
|
||||
/// Generic trait for primitive integers.
|
||||
///
|
||||
/// The `PrimInt` trait is an abstraction over the builtin primitive integer types (e.g., `u8`,
|
||||
/// `u32`, `isize`, `i128`, ...). It inherits the basic numeric traits and extends them with
|
||||
/// bitwise operators and non-wrapping arithmetic.
|
||||
///
|
||||
/// The trait explicitly inherits `Copy`, `Eq`, `Ord`, and `Sized`. The intention is that all
|
||||
/// types implementing this trait behave like primitive types that are passed by value by default
|
||||
/// and behave like builtin integers. Furthermore, the types are expected to expose the integer
|
||||
/// value in binary representation and support bitwise operators. The standard bitwise operations
|
||||
/// (e.g., bitwise-and, bitwise-or, right-shift, left-shift) are inherited and the trait extends
|
||||
/// these with introspective queries (e.g., `PrimInt::count_ones()`, `PrimInt::leading_zeros()`),
|
||||
/// bitwise combinators (e.g., `PrimInt::rotate_left()`), and endianness converters (e.g.,
|
||||
/// `PrimInt::to_be()`).
|
||||
///
|
||||
/// All `PrimInt` types are expected to be fixed-width binary integers. The width can be queried
|
||||
/// via `T::zero().count_zeros()`. The trait currently lacks a way to query the width at
|
||||
/// compile-time.
|
||||
///
|
||||
/// While a default implementation for all builtin primitive integers is provided, the trait is in
|
||||
/// no way restricted to these. Other integer types that fulfil the requirements are free to
|
||||
/// implement the trait was well.
|
||||
///
|
||||
/// This trait and many of the method names originate in the unstable `core::num::Int` trait from
|
||||
/// the rust standard library. The original trait was never stabilized and thus removed from the
|
||||
/// standard library.
|
||||
pub trait PrimInt:
|
||||
Sized
|
||||
+ Copy
|
||||
|
@ -171,10 +197,10 @@ pub trait PrimInt:
|
|||
/// ```
|
||||
/// use num_traits::PrimInt;
|
||||
///
|
||||
/// let n = 0xFEDCBA9876543210i64;
|
||||
/// let m = 0x000FEDCBA9876543i64;
|
||||
/// let n = -8i8; // 0b11111000
|
||||
/// let m = 62i8; // 0b00111110
|
||||
///
|
||||
/// assert_eq!(n.unsigned_shr(12), m);
|
||||
/// assert_eq!(n.unsigned_shr(2), m);
|
||||
/// ```
|
||||
fn unsigned_shr(self, n: u32) -> Self;
|
||||
|
||||
|
|
|
@ -20,13 +20,17 @@
|
|||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
// Only `no_std` builds actually use `libm`.
|
||||
#[cfg(all(not(feature = "std"), feature = "libm"))]
|
||||
extern crate libm;
|
||||
|
||||
use core::fmt;
|
||||
use core::num::Wrapping;
|
||||
use core::ops::{Add, Div, Mul, Rem, Sub};
|
||||
use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
|
||||
|
||||
pub use bounds::Bounded;
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
pub use float::Float;
|
||||
pub use float::FloatConst;
|
||||
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
|
||||
|
@ -53,7 +57,6 @@ pub mod identities;
|
|||
pub mod int;
|
||||
pub mod ops;
|
||||
pub mod pow;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod real;
|
||||
pub mod sign;
|
||||
|
||||
|
@ -90,13 +93,12 @@ pub trait NumOps<Rhs = Self, Output = Self>:
|
|||
{
|
||||
}
|
||||
|
||||
impl<T, Rhs, Output> NumOps<Rhs, Output> for T
|
||||
where
|
||||
impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
|
||||
T: Add<Rhs, Output = Output>
|
||||
+ Sub<Rhs, Output = Output>
|
||||
+ Mul<Rhs, Output = Output>
|
||||
+ Div<Rhs, Output = Output>
|
||||
+ Rem<Rhs, Output = Output>,
|
||||
+ Rem<Rhs, Output = Output>
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -105,22 +107,14 @@ where
|
|||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
|
||||
impl<T> NumRef for T
|
||||
where
|
||||
T: Num + for<'r> NumOps<&'r T>,
|
||||
{
|
||||
}
|
||||
impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
|
||||
|
||||
/// The trait for references which implement numeric operations, taking the
|
||||
/// second operand either by value or by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
|
||||
impl<T, Base> RefNum<Base> for T
|
||||
where
|
||||
T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base>,
|
||||
{
|
||||
}
|
||||
impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
|
||||
|
||||
/// The trait for types implementing numeric assignment operators (like `+=`).
|
||||
///
|
||||
|
@ -130,9 +124,8 @@ pub trait NumAssignOps<Rhs = Self>:
|
|||
{
|
||||
}
|
||||
|
||||
impl<T, Rhs> NumAssignOps<Rhs> for T
|
||||
where
|
||||
T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>,
|
||||
impl<T, Rhs> NumAssignOps<Rhs> for T where
|
||||
T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -140,22 +133,14 @@ where
|
|||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssign: Num + NumAssignOps {}
|
||||
impl<T> NumAssign for T
|
||||
where
|
||||
T: Num + NumAssignOps,
|
||||
{
|
||||
}
|
||||
impl<T> NumAssign for T where T: Num + NumAssignOps {}
|
||||
|
||||
/// The trait for `NumAssign` types which also implement assignment operations
|
||||
/// taking the second operand by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
|
||||
impl<T> NumAssignRef for T
|
||||
where
|
||||
T: NumAssign + for<'r> NumAssignOps<&'r T>,
|
||||
{
|
||||
}
|
||||
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
|
||||
|
||||
macro_rules! int_trait_impl {
|
||||
($name:ident for $($t:ty)*) => ($(
|
||||
|
@ -234,7 +219,12 @@ macro_rules! float_trait_impl {
|
|||
}
|
||||
|
||||
fn slice_shift_char(src: &str) -> Option<(char, &str)> {
|
||||
src.chars().nth(0).map(|ch| (ch, &src[1..]))
|
||||
let mut chars = src.chars();
|
||||
if let Some(ch) = chars.next() {
|
||||
Some((ch, chars.as_str()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let (is_positive, src) = match slice_shift_char(src) {
|
||||
|
@ -377,6 +367,8 @@ float_trait_impl!(Num for f32 f64);
|
|||
/// If input is less than min then this returns min.
|
||||
/// If input is greater than max then this returns max.
|
||||
/// Otherwise this returns input.
|
||||
///
|
||||
/// **Panics** in debug mode if `!(min <= max)`.
|
||||
#[inline]
|
||||
pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
|
||||
debug_assert!(min <= max, "min must be less than or equal to max");
|
||||
|
@ -389,17 +381,97 @@ pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
|
|||
}
|
||||
}
|
||||
|
||||
/// A value bounded by a minimum value
|
||||
///
|
||||
/// If input is less than min then this returns min.
|
||||
/// Otherwise this returns input.
|
||||
/// `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
|
||||
///
|
||||
/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
|
||||
#[inline]
|
||||
pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
|
||||
debug_assert!(min == min, "min must not be NAN");
|
||||
if input < min {
|
||||
min
|
||||
} else {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
/// A value bounded by a maximum value
|
||||
///
|
||||
/// If input is greater than max then this returns max.
|
||||
/// Otherwise this returns input.
|
||||
/// `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
|
||||
///
|
||||
/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
|
||||
#[inline]
|
||||
pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
|
||||
debug_assert!(max == max, "max must not be NAN");
|
||||
if input > max {
|
||||
max
|
||||
} else {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clamp_test() {
|
||||
// Int test
|
||||
assert_eq!(1, clamp(1, -1, 2));
|
||||
assert_eq!(-1, clamp(-2, -1, 2));
|
||||
assert_eq!(2, clamp(3, -1, 2));
|
||||
assert_eq!(1, clamp_min(1, -1));
|
||||
assert_eq!(-1, clamp_min(-2, -1));
|
||||
assert_eq!(-1, clamp_max(1, -1));
|
||||
assert_eq!(-2, clamp_max(-2, -1));
|
||||
|
||||
// Float test
|
||||
assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
|
||||
assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
|
||||
assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
|
||||
assert_eq!(1.0, clamp_min(1.0, -1.0));
|
||||
assert_eq!(-1.0, clamp_min(-2.0, -1.0));
|
||||
assert_eq!(-1.0, clamp_max(1.0, -1.0));
|
||||
assert_eq!(-2.0, clamp_max(-2.0, -1.0));
|
||||
assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());
|
||||
assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());
|
||||
assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_nan_min() {
|
||||
clamp(0., ::core::f32::NAN, 1.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_nan_max() {
|
||||
clamp(0., -1., ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_nan_min_max() {
|
||||
clamp(0., ::core::f32::NAN, ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_min_nan_min() {
|
||||
clamp_min(0., ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(debug_assertions)]
|
||||
fn clamp_max_nan_max() {
|
||||
clamp_max(0., ::core::f32::NAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -413,6 +485,15 @@ fn from_str_radix_unwrap() {
|
|||
assert_eq!(f, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str_radix_multi_byte_fail() {
|
||||
// Ensure parsing doesn't panic, even on invalid sign characters
|
||||
assert!(f32::from_str_radix("™0.2", 10).is_err());
|
||||
|
||||
// Even when parsing the exponent sign
|
||||
assert!(f32::from_str_radix("0.2E™1", 10).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping_is_num() {
|
||||
fn require_num<T: Num>(_: &T) {}
|
||||
|
|
|
@ -195,10 +195,11 @@ checked_impl_unary!(CheckedNeg, checked_neg, isize);
|
|||
#[cfg(has_i128)]
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i128);
|
||||
|
||||
/// Performs a left shift that returns `None` on overflow.
|
||||
/// Performs a left shift that returns `None` on shifts larger than
|
||||
/// the type width.
|
||||
pub trait CheckedShl: Sized + Shl<u32, Output = Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
/// `None` is returned.
|
||||
/// Checked shift left. Computes `self << rhs`, returning `None`
|
||||
/// if `rhs` is larger than or equal to the number of bits in `self`.
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::CheckedShl;
|
||||
|
@ -240,10 +241,11 @@ checked_shift_impl!(CheckedShl, checked_shl, isize);
|
|||
#[cfg(has_i128)]
|
||||
checked_shift_impl!(CheckedShl, checked_shl, i128);
|
||||
|
||||
/// Performs a right shift that returns `None` on overflow.
|
||||
/// Performs a right shift that returns `None` on shifts larger than
|
||||
/// the type width.
|
||||
pub trait CheckedShr: Sized + Shr<u32, Output = Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
/// `None` is returned.
|
||||
/// Checked shift right. Computes `self >> rhs`, returning `None`
|
||||
/// if `rhs` is larger than or equal to the number of bits in `self`.
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::CheckedShr;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
/// // 100.0
|
||||
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f32::EPSILON);
|
||||
/// assert!(abs_difference <= 100.0 * f32::EPSILON);
|
||||
/// ```
|
||||
pub trait MulAdd<A = Self, B = Self> {
|
||||
/// The resulting type after applying the fused multiply-add.
|
||||
|
@ -34,23 +34,23 @@ pub trait MulAddAssign<A = Self, B = Self> {
|
|||
fn mul_add_assign(&mut self, a: A, b: B);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAdd<f32, f32> for f32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f32::mul_add(self, a, b)
|
||||
<Self as ::Float>::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAdd<f64, f64> for f64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f64::mul_add(self, a, b)
|
||||
<Self as ::Float>::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,19 +71,19 @@ mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
|||
#[cfg(has_i128)]
|
||||
mul_add_impl!(MulAdd for i128 u128);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAddAssign<f32, f32> for f32 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f32::mul_add(*self, a, b)
|
||||
*self = <Self as ::Float>::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
impl MulAddAssign<f64, f64> for f64 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f64::mul_add(*self, a, b)
|
||||
*self = <Self as ::Float>::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ mod tests {
|
|||
|
||||
let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs();
|
||||
|
||||
assert!(abs_difference <= $t::EPSILON);
|
||||
assert!(abs_difference <= 46.4 * $t::EPSILON);
|
||||
}
|
||||
)+
|
||||
};
|
||||
|
|
|
@ -152,28 +152,29 @@ pow_impl!(Wrapping<isize>);
|
|||
// pow_impl!(usize, u64);
|
||||
// pow_impl!(isize, u64);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", feature = "libm"))]
|
||||
mod float_impls {
|
||||
use super::Pow;
|
||||
use Float;
|
||||
|
||||
pow_impl!(f32, i8, i32, f32::powi);
|
||||
pow_impl!(f32, u8, i32, f32::powi);
|
||||
pow_impl!(f32, i16, i32, f32::powi);
|
||||
pow_impl!(f32, u16, i32, f32::powi);
|
||||
pow_impl!(f32, i32, i32, f32::powi);
|
||||
pow_impl!(f64, i8, i32, f64::powi);
|
||||
pow_impl!(f64, u8, i32, f64::powi);
|
||||
pow_impl!(f64, i16, i32, f64::powi);
|
||||
pow_impl!(f64, u16, i32, f64::powi);
|
||||
pow_impl!(f64, i32, i32, f64::powi);
|
||||
pow_impl!(f32, f32, f32, f32::powf);
|
||||
pow_impl!(f64, f32, f64, f64::powf);
|
||||
pow_impl!(f64, f64, f64, f64::powf);
|
||||
pow_impl!(f32, i8, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, u8, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, i16, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, u16, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f32, i32, i32, <f32 as Float>::powi);
|
||||
pow_impl!(f64, i8, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, u8, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, i16, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, u16, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f64, i32, i32, <f64 as Float>::powi);
|
||||
pow_impl!(f32, f32, f32, <f32 as Float>::powf);
|
||||
pow_impl!(f64, f32, f64, <f64 as Float>::powf);
|
||||
pow_impl!(f64, f64, f64, <f64 as Float>::powf);
|
||||
}
|
||||
|
||||
/// Raises a value to the power of exp, using exponentiation by squaring.
|
||||
///
|
||||
/// Note that `0⁰` (`pow(0, 0)`) returnes `1`. Mathematically this is undefined.
|
||||
/// Note that `0⁰` (`pow(0, 0)`) returns `1`. Mathematically this is undefined.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -211,7 +212,7 @@ pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) ->
|
|||
|
||||
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// Note that `0⁰` (`checked_pow(0, 0)`) returnes `Some(1)`. Mathematically this is undefined.
|
||||
/// Note that `0⁰` (`checked_pow(0, 0)`) returns `Some(1)`. Mathematically this is undefined.
|
||||
///
|
||||
/// Otherwise same as the `pow` function.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::ops::Neg;
|
||||
#![cfg(any(feature = "std", feature = "libm"))]
|
||||
|
||||
use core::ops::Neg;
|
||||
|
||||
use {Float, Num, NumCast};
|
||||
|
||||
|
@ -11,7 +13,7 @@ use {Float, Num, NumCast};
|
|||
/// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type)
|
||||
/// for a list of data types that could meaningfully implement this trait.
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
|
||||
pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
|
||||
/// Returns the smallest finite value that this type can represent.
|
||||
///
|
||||
|
|
|
@ -206,11 +206,7 @@ empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
|
|||
#[cfg(has_i128)]
|
||||
empty_trait_impl!(Unsigned for u128);
|
||||
|
||||
impl<T: Unsigned> Unsigned for Wrapping<T>
|
||||
where
|
||||
Wrapping<T>: Num,
|
||||
{
|
||||
}
|
||||
impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
|
||||
|
||||
#[test]
|
||||
fn unsigned_wrapping_is_unsigned() {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"fd8fb63d62ad4e89438c8ab623684bae455ceb47baf5746c60e7c962c219752a","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","NOTICE":"6e0c856925602c18a04e173be3a6e2d812a7ca4501176642a07fec1af97e0eab","README.md":"4f227c9d8a3c07e4b82b2812d3fcc512cdf477a4daf2c9c955f49fb2e94cbab8","rustfmt.toml":"925e9c7b3d6df043a11531da116439cc0d0b0368b682875a8fb0e8229fc7df01","src/errors.rs":"efcc4e8472ee06de82b122017cca4e87898034c98bc9b593110b2a4f8a557e26","src/functions.rs":"1bec1b1ac5c38d3db527880ab5b06005f567a52bba7b98b1ec0fdf64f7d0a68b","src/lib.rs":"ec21c8a26eaf41912967871f324371a673821ee61bd557b19f30d729bb3695c0","src/tests.rs":"e1a03e88b1d03bbd1fd9817cd347224d523a96ad85440a0ffbf82b1a494aac6f","src/types.rs":"797b99955b4fa30ad373ee435076c6d251978bb6ae724cc9a082020fb8f984fc"},"package":"ff403ab0d15638fc795f4e2122e77e007fdcf17db7fee38f225f173c6e4cc1c3"}
|
||||
{"files":{"Cargo.toml":"62c225dc3a9c63990f9542efc86b23aa444a24d91dab57d8d1a8a3414f0befe0","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","NOTICE":"6e0c856925602c18a04e173be3a6e2d812a7ca4501176642a07fec1af97e0eab","README.md":"4f227c9d8a3c07e4b82b2812d3fcc512cdf477a4daf2c9c955f49fb2e94cbab8","rustfmt.toml":"925e9c7b3d6df043a11531da116439cc0d0b0368b682875a8fb0e8229fc7df01","src/errors.rs":"efcc4e8472ee06de82b122017cca4e87898034c98bc9b593110b2a4f8a557e26","src/functions.rs":"1bec1b1ac5c38d3db527880ab5b06005f567a52bba7b98b1ec0fdf64f7d0a68b","src/lib.rs":"3d22aaedf17669d9ca5f50c7ff892e7d874d257369fa40b49ed582409ee94455","src/tests.rs":"b7257ef2bff4321ac03095af9b4015fc9a88d2cddddb94ca8ae8f7516b19e7f1","src/types.rs":"797b99955b4fa30ad373ee435076c6d251978bb6ae724cc9a082020fb8f984fc"},"package":null}
|
|
@ -1,33 +1,39 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
# Copyright 2017 Marcus Heese
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
#
|
||||
# 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)
|
||||
|
||||
# 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.
|
||||
[package]
|
||||
name = "pkcs11"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
authors = ["Marcus Heese <marcus.heese@gmail.com>"]
|
||||
exclude = ["pkcs11-docs/**"]
|
||||
description = "Rust PKCS#11 Library"
|
||||
#documentation = "https://github.com/mheese/rust-pkcs11"
|
||||
homepage = "https://github.com/mheese/rust-pkcs11"
|
||||
repository = "https://github.com/mheese/rust-pkcs11"
|
||||
#readme = "..."
|
||||
keywords = ["pkcs11", "cryptoki"]
|
||||
categories = ["external-ffi-bindings", "cryptography", "hardware-support"]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/mheese/rust-pkcs11"
|
||||
[dependencies.libloading]
|
||||
version = "^0.4"
|
||||
exclude = [
|
||||
"pkcs11-docs/**",
|
||||
]
|
||||
|
||||
[dependencies.num-bigint]
|
||||
version = "^0.1"
|
||||
[dev-dependencies.hex]
|
||||
version = "^0.3"
|
||||
[dependencies]
|
||||
libloading = "^0.4"
|
||||
num-bigint = "^0.2"
|
||||
#libc = "0.2.33"
|
||||
|
||||
[dev-dependencies.num-traits]
|
||||
version = "^0.1"
|
||||
[dev-dependencies]
|
||||
num-traits = "^0.1"
|
||||
hex = "^0.3"
|
||||
serial_test = "~0.1"
|
||||
serial_test_derive = "~0.1"
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
extern crate libloading;
|
||||
extern crate num_bigint;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use] extern crate serial_test_derive;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ fn pkcs11_module_name() -> PathBuf {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_label_from_str() {
|
||||
let s30 = "Löwe 老虎 Léopar虎d虎aaa";
|
||||
let s32 = "Löwe 老虎 Léopar虎d虎aaaö";
|
||||
|
@ -75,6 +76,7 @@ fn test_label_from_str() {
|
|||
assert_eq!(l34[31], 32);
|
||||
}
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_new() {
|
||||
let res = Ctx::new(pkcs11_module_name());
|
||||
assert!(
|
||||
|
@ -85,6 +87,7 @@ fn ctx_new() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_initialize() {
|
||||
let mut ctx = Ctx::new(pkcs11_module_name()).unwrap();
|
||||
let res = ctx.initialize(None);
|
||||
|
@ -97,6 +100,7 @@ fn ctx_initialize() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_new_and_initialize() {
|
||||
let res = Ctx::new_and_initialize(pkcs11_module_name());
|
||||
assert!(
|
||||
|
@ -107,6 +111,7 @@ fn ctx_new_and_initialize() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_finalize() {
|
||||
let mut ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let res = ctx.finalize();
|
||||
|
@ -118,6 +123,7 @@ fn ctx_finalize() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_info() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let res = ctx.get_info();
|
||||
|
@ -131,6 +137,7 @@ fn ctx_get_info() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_function_list() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let res = ctx.get_function_list();
|
||||
|
@ -144,6 +151,7 @@ fn ctx_get_function_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_slot_list() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let res = ctx.get_slot_list(false);
|
||||
|
@ -157,6 +165,7 @@ fn ctx_get_slot_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_slot_infos() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -175,6 +184,7 @@ fn ctx_get_slot_infos() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_token_infos() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -193,6 +203,7 @@ fn ctx_get_token_infos() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_mechanism_lists() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -211,6 +222,7 @@ fn ctx_get_mechanism_lists() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_mechanism_infos() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -233,6 +245,7 @@ fn ctx_get_mechanism_infos() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_init_token() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -258,6 +271,7 @@ fn ctx_init_token() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_init_pin() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -283,6 +297,7 @@ fn ctx_init_pin() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_set_pin() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -310,6 +325,7 @@ fn ctx_set_pin() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_open_session() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -331,6 +347,7 @@ fn ctx_open_session() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_close_session() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -354,6 +371,7 @@ fn ctx_close_session() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_close_all_sessions() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -377,6 +395,7 @@ fn ctx_close_all_sessions() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_session_info() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -401,6 +420,7 @@ fn ctx_get_session_info() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_login() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -425,6 +445,7 @@ fn ctx_login() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_logout() {
|
||||
let ctx = Ctx::new_and_initialize(pkcs11_module_name()).unwrap();
|
||||
let slots = ctx.get_slot_list(false).unwrap();
|
||||
|
@ -575,6 +596,7 @@ fn fixture_token() -> Result<(Ctx, CK_SESSION_HANDLE), Error> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_create_object() {
|
||||
/*
|
||||
CKA_CLASS ck_type object_class:CKO_DATA
|
||||
|
@ -642,6 +664,7 @@ fn fixture_token_and_object() -> Result<(Ctx, CK_SESSION_HANDLE, CK_OBJECT_HANDL
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_copy_object() {
|
||||
let (ctx, sh, oh) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -663,6 +686,7 @@ fn ctx_copy_object() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_destroy_object() {
|
||||
let (ctx, sh, oh) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -677,6 +701,7 @@ fn ctx_destroy_object() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_object_size() {
|
||||
let (ctx, sh, oh) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -693,6 +718,7 @@ fn ctx_get_object_size() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_attribute_value() {
|
||||
{
|
||||
let (ctx, sh, oh) = fixture_token_and_object().unwrap();
|
||||
|
@ -748,6 +774,7 @@ fn ctx_get_attribute_value() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_set_attribute_value() {
|
||||
let (ctx, sh, oh) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -771,6 +798,7 @@ fn ctx_set_attribute_value() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_find_objects_init() {
|
||||
let (ctx, sh, _) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -788,6 +816,7 @@ fn ctx_find_objects_init() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_find_objects() {
|
||||
let (ctx, sh, _) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -809,6 +838,7 @@ fn ctx_find_objects() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_find_objects_final() {
|
||||
let (ctx, sh, _) = fixture_token_and_object().unwrap();
|
||||
|
||||
|
@ -828,6 +858,7 @@ fn ctx_find_objects_final() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_generate_key() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
|
||||
|
@ -894,6 +925,7 @@ fn ctx_generate_key() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_generate_key_pair() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
|
||||
|
@ -1227,6 +1259,7 @@ fn fixture_dh_key_pair(
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_wrap_key() {
|
||||
let (ctx, sh, wrapOh, secOh) = fixture_token_and_secret_keys().unwrap();
|
||||
|
||||
|
@ -1256,6 +1289,7 @@ fn ctx_wrap_key() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_unwrap_key() {
|
||||
let (ctx, sh, wrapOh, secOh) = fixture_token_and_secret_keys().unwrap();
|
||||
|
||||
|
@ -1310,6 +1344,7 @@ fn ctx_unwrap_key() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_derive_key() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
|
||||
|
@ -1431,6 +1466,7 @@ fn ctx_derive_key() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_seed_random() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
|
||||
|
@ -1446,6 +1482,7 @@ fn ctx_seed_random() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_generate_random() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
let res = ctx.generate_random(sh, 32);
|
||||
|
@ -1461,6 +1498,7 @@ fn ctx_generate_random() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_get_function_status() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
let res = ctx.get_function_status(sh);
|
||||
|
@ -1475,6 +1513,7 @@ fn ctx_get_function_status() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_cancel_function() {
|
||||
let (ctx, sh) = fixture_token().unwrap();
|
||||
let res = ctx.cancel_function(sh);
|
||||
|
@ -1489,6 +1528,7 @@ fn ctx_cancel_function() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ctx_wait_for_slot_event() {
|
||||
let (ctx, _) = fixture_token().unwrap();
|
||||
let res = ctx.wait_for_slot_event(CKF_DONT_BLOCK);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"files":{"CHANGELOG.md":"f5e9c71d4123971f9f6c54eed8837245e6cac4b610c9d23b680fa95538946142","Cargo.toml":"4c770ee471e19f4a453a36d76479f9a530987058b793c735cd7a2bcf937d7edb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"fb8071c3bc1013107b16ebcb303f31ef614e81440f2d58a46bfb9ff1e311b792","appveyor.yml":"8796156caf7041ef2a43f7a313df21ea639de3f2563b6181bba1096b1c489f1b","benches/bench.rs":"35c4ab609f2a5f5aab6c52c257415258dc0780621b492b5a82bb12d048cab6db","benches/distributions/exponential.rs":"99cb59c013a0b6bb390d34c5649b341fc3b88ea7df0caf2470bdda8798f9fe3d","benches/distributions/gamma.rs":"3533f311e4b55d743c5b01a7eb6529c94fd97726ef6702a6372f914f5f33666b","benches/distributions/mod.rs":"0028f1cb96f61152ed5b49a4fe91227d809ef6d19035592c36032a538af7f95e","benches/distributions/normal.rs":"4e10c18cb583ccb96301ea953c8e0aa9ee3b6662060271d1b8d19ca23364dc6b","benches/generators.rs":"aaa2f1dbfb399df8323d8a5796b92add6210cd5f0f1d916895ffdd81d60f812b","benches/misc.rs":"bd2f7c5a16f0fcb59022d5aeef66ed3c94e89ebf6c06667851dd23d0b1595504","src/distributions/exponential.rs":"103c8412c8a581b71835f1c00e40f6370e7702adf9d499243933a793d132d4e7","src/distributions/gamma.rs":"7a3f85c8daad4e56e334586ddb9fc9d83df3b0699738ed681a6c41e4ed455be9","src/distributions/mod.rs":"7943c4f83721bac816f831cca3b1574b6136932f7b4927aa6101130080ba62c5","src/distributions/normal.rs":"1562b43f80e4d5f83a8deb5af18de5a18dfeeeeda11fefc577da26672b14c949","src/distributions/range.rs":"a72a538d3ec4ed23f8d632aa55fd4793c464f24a5872d04ce8095ddd5db92115","src/distributions/ziggurat_tables.rs":"4eacf94fc352c91c455a6623de6a721e53842e1690f13a5662b6a79c7fbb73de","src/jitter.rs":"befd4b84bf753c107370b5b9498ad49611c220bdae2e4be9ee4398e9fa497042","src/lib.rs":"f9f4d15c2ce67f9ba21261a4bc76599523b930698cee2ae1e37d01f0d2ba834e","src/os.rs":"bbba4481432ae0f19bafb2168af5e7e1a858547ff8a7f8996286ea1b2a951158","src/prng/chacha.rs":"558007276f9c22933d39e5b8e853f4dd9533e823ed66df8dc1f23ad6925b1d51","src/prng/isaac.rs":"a8a2ee8b38d312663308e3bdf03376e342fd91330655f39144e5bba7392b2a8e","src/prng/isaac64.rs":"f28f7596ccab910db265b42671116abb9d2039fa8a421cbc75312bd0e7715d3a","src/prng/mod.rs":"c1a73450f49e819a20942a5b591f84a08ebb5ac33aa0f65b18ac1dc9a19a3084","src/prng/xorshift.rs":"606c308747293652c868b46dc3cad847d0c3717629c04ba75681c887c7634114","src/rand_impls.rs":"e1f27077fc13d5855bb66235f8ccfb216e116337eb38424d9c30c090e112215c","src/read.rs":"bd0eb508a6b659dc578d546fc2f231484aed80c73cfe8c475e0d65c8d699a769","src/reseeding.rs":"a97b86387b87ea1adc5262ddea480fe735c9c2a86762abaace29119022ac9f6e","src/seq.rs":"76dd58af0f580aed2721c393a5c036322186dc7cb3b4abed33436620c7c49288","utils/ziggurat_tables.py":"a9fc0a2fdae9b5c798c238788f94b720c156e13fd96f2356c409aa533191eb94"},"package":"552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"}
|
|
@ -1,277 +0,0 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.5] - 2019-01-25
|
||||
### Platforms
|
||||
- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng
|
||||
|
||||
## [0.4.4] - 2019-01-06
|
||||
### Added
|
||||
- SGX support
|
||||
|
||||
## [0.4.3] - 2018-08-16
|
||||
### Fixed
|
||||
- Use correct syscall number for PowerPC (#589)
|
||||
|
||||
## [0.4.2] - 2018-01-05
|
||||
### Changed
|
||||
- Use winapi on Windows
|
||||
- Update for Fuchsia OS
|
||||
- Remove dev-dependency on `log`
|
||||
|
||||
## [0.4.1] - 2017-12-17
|
||||
### Added
|
||||
- `no_std` support
|
||||
|
||||
## [0.4.0-pre.0] - 2017-12-11
|
||||
### Added
|
||||
- `JitterRng` added as a high-quality alternative entropy source using the
|
||||
system timer
|
||||
- new `seq` module with `sample_iter`, `sample_slice`, etc.
|
||||
- WASM support via dummy implementations (fail at run-time)
|
||||
- Additional benchmarks, covering generators and new seq code
|
||||
|
||||
### Changed
|
||||
- `thread_rng` uses `JitterRng` if seeding from system time fails
|
||||
(slower but more secure than previous method)
|
||||
|
||||
### Deprecated
|
||||
- `sample` function deprecated (replaced by `sample_iter`)
|
||||
|
||||
## [0.3.18] - 2017-11-06
|
||||
### Changed
|
||||
- `thread_rng` is seeded from the system time if `OsRng` fails
|
||||
- `weak_rng` now uses `thread_rng` internally
|
||||
|
||||
|
||||
## [0.3.17] - 2017-10-07
|
||||
### Changed
|
||||
- Fuchsia: Magenta was renamed Zircon
|
||||
|
||||
## [0.3.16] - 2017-07-27
|
||||
### Added
|
||||
- Implement Debug for mote non-public types
|
||||
- implement `Rand` for (i|u)i128
|
||||
- Support for Fuchsia
|
||||
|
||||
### Changed
|
||||
- Add inline attribute to SampleRange::construct_range.
|
||||
This improves the benchmark for sample in 11% and for shuffle in 16%.
|
||||
- Use `RtlGenRandom` instead of `CryptGenRandom`
|
||||
|
||||
|
||||
## [0.3.15] - 2016-11-26
|
||||
### Added
|
||||
- Add `Rng` trait method `choose_mut`
|
||||
- Redox support
|
||||
|
||||
### Changed
|
||||
- Use `arc4rand` for `OsRng` on FreeBSD.
|
||||
- Use `arc4random(3)` for `OsRng` on OpenBSD.
|
||||
|
||||
### Fixed
|
||||
- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows
|
||||
|
||||
|
||||
## [0.3.14] - 2016-02-13
|
||||
### Fixed
|
||||
- Inline definitions from winapi/advapi32, wich decreases build times
|
||||
|
||||
|
||||
## [0.3.13] - 2016-01-09
|
||||
### Fixed
|
||||
- Compatible with Rust 1.7.0-nightly (needed some extra type annotations)
|
||||
|
||||
|
||||
## [0.3.12] - 2015-11-09
|
||||
### Changed
|
||||
- Replaced the methods in `next_f32` and `next_f64` with the technique described
|
||||
Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more
|
||||
uniform distribution.
|
||||
- Depend on libc 0.2
|
||||
|
||||
### Fixed
|
||||
- Fix iterator protocol issue in `rand::sample`
|
||||
|
||||
|
||||
## [0.3.11] - 2015-08-31
|
||||
### Added
|
||||
- Implement `Rand` for arrays with n <= 32
|
||||
|
||||
|
||||
## [0.3.10] - 2015-08-17
|
||||
### Added
|
||||
- Support for NaCl platforms
|
||||
|
||||
### Changed
|
||||
- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box<R>` where `R: ?Sized + Rng`
|
||||
|
||||
|
||||
## [0.3.9] - 2015-06-18
|
||||
### Changed
|
||||
- Use `winapi` for Windows API things
|
||||
|
||||
### Fixed
|
||||
- Fixed test on stable/nightly
|
||||
- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu
|
||||
|
||||
|
||||
## [0.3.8] - 2015-04-23
|
||||
### Changed
|
||||
- `log` is a dev dependency
|
||||
|
||||
### Fixed
|
||||
- Fix race condition of atomics in `is_getrandom_available`
|
||||
|
||||
|
||||
## [0.3.7] - 2015-04-03
|
||||
### Fixed
|
||||
- Derive Copy/Clone changes
|
||||
|
||||
|
||||
## [0.3.6] - 2015-04-02
|
||||
### Changed
|
||||
- Move to stable Rust!
|
||||
|
||||
|
||||
## [0.3.5] - 2015-04-01
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
|
||||
|
||||
## [0.3.4] - 2015-03-31
|
||||
### Added
|
||||
- Implement Clone for `Weighted`
|
||||
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
|
||||
|
||||
## [0.3.3] - 2015-03-26
|
||||
### Fixed
|
||||
- Fix compile on Windows
|
||||
|
||||
|
||||
## [0.3.2] - 2015-03-26
|
||||
|
||||
|
||||
## [0.3.1] - 2015-03-26
|
||||
### Fixed
|
||||
- Fix compile on Windows
|
||||
|
||||
|
||||
## [0.3.0] - 2015-03-25
|
||||
### Changed
|
||||
- Update to use log version 0.3.x
|
||||
|
||||
|
||||
## [0.2.1] - 2015-03-22
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
- Fixed iOS compilation
|
||||
|
||||
|
||||
## [0.2.0] - 2015-03-06
|
||||
### Fixed
|
||||
- Compatible with Rust master (move from `old_io` to `std::io`)
|
||||
|
||||
|
||||
## [0.1.4] - 2015-03-04
|
||||
### Fixed
|
||||
- Compatible with Rust master (use wrapping ops)
|
||||
|
||||
|
||||
## [0.1.3] - 2015-02-20
|
||||
### Fixed
|
||||
- Compatible with Rust master
|
||||
|
||||
### Removed
|
||||
- Removed Copy inplementaions from RNGs
|
||||
|
||||
|
||||
## [0.1.2] - 2015-02-03
|
||||
### Added
|
||||
- Imported functionality from `std::rand`, including:
|
||||
- `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()`
|
||||
- `ReaderRng`: A wrapper around any Reader to treat it as an RNG.
|
||||
- Imported documentation from `std::rand`
|
||||
- Imported tests from `std::rand`
|
||||
|
||||
|
||||
## [0.1.1] - 2015-02-03
|
||||
### Added
|
||||
- Migrate to a cargo-compatible directory structure.
|
||||
|
||||
### Fixed
|
||||
- Do not use entropy during `gen_weighted_bool(1)`
|
||||
|
||||
|
||||
## [Rust 0.12.0] - 2014-10-09
|
||||
### Added
|
||||
- Impl Rand for tuples of arity 11 and 12
|
||||
- Include ChaCha pseudorandom generator
|
||||
- Add `next_f64` and `next_f32` to Rng
|
||||
- Implement Clone for PRNGs
|
||||
|
||||
### Changed
|
||||
- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a
|
||||
runtime is removed from Rust).
|
||||
|
||||
### Fixed
|
||||
- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by
|
||||
informing the optimiser that indexing is never out-of-bounds.
|
||||
|
||||
### Removed
|
||||
- Removed the Deprecated `choose_option`
|
||||
|
||||
|
||||
## [Rust 0.11.0] - 2014-07-02
|
||||
### Added
|
||||
- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random`
|
||||
- `Rng::gen_iter()` which will return an infinite stream of random values
|
||||
- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters
|
||||
|
||||
### Changed
|
||||
- Now only depends on libcore! 2adf5363f88ffe06f6d2ea5c338d1b186d47f4a1
|
||||
- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()`
|
||||
- Rename OSRng to OsRng
|
||||
- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
|
||||
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
|
||||
structure now has a lifetime associated with it.
|
||||
- The `sample` method on `Rng` has been moved to a top-level function in the
|
||||
`rand` module due to its dependence on `Vec`.
|
||||
|
||||
### Removed
|
||||
- `Rng::gen_vec()` was removed. Previous behavior can be regained with
|
||||
`rng.gen_iter().take(n).collect()`
|
||||
- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with
|
||||
`rng.gen_ascii_chars().take(n).collect()`
|
||||
- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
|
||||
relied on being able to use an OSRng for seeding, but this is no longer
|
||||
available in librand (where these types are defined). To retain the same
|
||||
functionality, these types now implement the `Rand` trait so they can be
|
||||
generated with a random seed from another random number generator. This allows
|
||||
the stdlib to use an OSRng to create seeded instances of these RNGs.
|
||||
- Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
|
||||
pretty rare in the codebase, and it allows for librand to not depend on
|
||||
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
|
||||
supported.
|
||||
- Remove a slew of old deprecated functions
|
||||
|
||||
|
||||
## [Rust 0.10] - 2014-04-03
|
||||
### Changed
|
||||
- replace `Rng.shuffle's` functionality with `.shuffle_mut`
|
||||
- bubble up IO errors when creating an OSRng
|
||||
|
||||
### Fixed
|
||||
- Use `fill()` instead of `read()`
|
||||
- Rewrite OsRng in Rust for windows
|
||||
|
||||
## [0.10-pre] - 2014-03-02
|
||||
### Added
|
||||
- Seperate `rand` out of the standard library
|
||||
|
|
@ -1,45 +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 = "rand"
|
||||
version = "0.4.6"
|
||||
authors = ["The Rust Project Developers"]
|
||||
description = "Random number generators and other randomness functionality.\n"
|
||||
homepage = "https://github.com/rust-lang-nursery/rand"
|
||||
documentation = "https://docs.rs/rand"
|
||||
readme = "README.md"
|
||||
keywords = ["random", "rng"]
|
||||
categories = ["algorithms"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rust-lang-nursery/rand"
|
||||
|
||||
[features]
|
||||
alloc = []
|
||||
default = ["std"]
|
||||
i128_support = []
|
||||
nightly = ["i128_support"]
|
||||
std = ["libc"]
|
||||
[target."cfg(target_env = \"sgx\")".dependencies.rand_core]
|
||||
version = "0.3"
|
||||
default-features = false
|
||||
|
||||
[target."cfg(target_env = \"sgx\")".dependencies.rdrand]
|
||||
version = "0.4.0"
|
||||
[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-cprng]
|
||||
version = "0.1.0"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = ["minwindef", "ntsecapi", "profileapi", "winnt"]
|
|
@ -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,139 +0,0 @@
|
|||
rand
|
||||
====
|
||||
|
||||
A Rust library for random number generators and other randomness functionality.
|
||||
|
||||
[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/rm5c9o33k3jhchbw?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand)
|
||||
|
||||
[Documentation](https://docs.rs/rand)
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rand = "0.4"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate rand;
|
||||
```
|
||||
|
||||
### Versions
|
||||
|
||||
Version `0.4`was released in December 2017. It contains almost no breaking
|
||||
changes since the `0.3` series, but nevertheless contains some significant
|
||||
new code, including a new "external" entropy source (`JitterRng`) and `no_std`
|
||||
support.
|
||||
|
||||
Version `0.5` is in development and contains significant performance
|
||||
improvements for the ISAAC random number generators.
|
||||
|
||||
## Examples
|
||||
|
||||
There is built-in support for a random number generator (RNG) associated with each thread stored in thread-local storage. This RNG can be accessed via thread_rng, or used implicitly via random. This RNG is normally randomly seeded from an operating-system source of randomness, e.g. /dev/urandom on Unix systems, and will automatically reseed itself from this source after generating 32 KiB of random data.
|
||||
|
||||
```rust
|
||||
let tuple = rand::random::<(f64, char)>();
|
||||
println!("{:?}", tuple)
|
||||
```
|
||||
|
||||
```rust
|
||||
use rand::Rng;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
if rng.gen() { // random bool
|
||||
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
|
||||
}
|
||||
```
|
||||
|
||||
It is also possible to use other RNG types, which have a similar interface. The following uses the "ChaCha" algorithm instead of the default.
|
||||
|
||||
```rust
|
||||
use rand::{Rng, ChaChaRng};
|
||||
|
||||
let mut rng = rand::ChaChaRng::new_unseeded();
|
||||
println!("i32: {}, u32: {}", rng.gen::<i32>(), rng.gen::<u32>())
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
By default, `rand` is built with all stable features available. The following
|
||||
optional features are available:
|
||||
|
||||
- `i128_support` enables support for generating `u128` and `i128` values
|
||||
- `nightly` enables all unstable features (`i128_support`)
|
||||
- `std` enabled by default; by setting "default-features = false" `no_std`
|
||||
mode is activated; this removes features depending on `std` functionality:
|
||||
|
||||
- `OsRng` is entirely unavailable
|
||||
- `JitterRng` code is still present, but a nanosecond timer must be
|
||||
provided via `JitterRng::new_with_timer`
|
||||
- Since no external entropy is available, it is not possible to create
|
||||
generators with fresh seeds (user must provide entropy)
|
||||
- `thread_rng`, `weak_rng` and `random` are all disabled
|
||||
- exponential, normal and gamma type distributions are unavailable
|
||||
since `exp` and `log` functions are not provided in `core`
|
||||
- any code requiring `Vec` or `Box`
|
||||
- `alloc` can be used instead of `std` to provide `Vec` and `Box`
|
||||
|
||||
## Testing
|
||||
|
||||
Unfortunately, `cargo test` does not test everything. The following tests are
|
||||
recommended:
|
||||
|
||||
```
|
||||
# Basic tests for rand and sub-crates
|
||||
cargo test --all
|
||||
|
||||
# Test no_std support (build only since nearly all tests require std)
|
||||
cargo build --all --no-default-features
|
||||
|
||||
# Test 128-bit support (requires nightly)
|
||||
cargo test --all --features nightly
|
||||
|
||||
# Benchmarks (requires nightly)
|
||||
cargo bench
|
||||
# or just to test the benchmark code:
|
||||
cargo test --benches
|
||||
```
|
||||
|
||||
# `derive(Rand)`
|
||||
|
||||
You can derive the `Rand` trait for your custom type via the `#[derive(Rand)]`
|
||||
directive. To use this first add this to your Cargo.toml:
|
||||
|
||||
```toml
|
||||
rand = "0.4"
|
||||
rand_derive = "0.3"
|
||||
```
|
||||
|
||||
Next in your crate:
|
||||
|
||||
```rust
|
||||
extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate rand_derive;
|
||||
|
||||
#[derive(Rand, Debug)]
|
||||
struct MyStruct {
|
||||
a: i32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", rand::random::<MyStruct>());
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# License
|
||||
|
||||
`rand` is primarily distributed under the terms of both the MIT
|
||||
license and the Apache License (Version 2.0).
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
|
@ -1,38 +0,0 @@
|
|||
environment:
|
||||
|
||||
# At the time this was added AppVeyor was having troubles with checking
|
||||
# revocation of SSL certificates of sites like static.rust-lang.org and what
|
||||
# we think is crates.io. The libcurl HTTP client by default checks for
|
||||
# revocation on Windows and according to a mailing list [1] this can be
|
||||
# disabled.
|
||||
#
|
||||
# The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL
|
||||
# revocation checking on Windows in libcurl. Note, though, that rustup, which
|
||||
# we're using to download Rust here, also uses libcurl as the default backend.
|
||||
# Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation
|
||||
# checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to
|
||||
# use the Hyper instead of libcurl backend. Both Hyper and libcurl use
|
||||
# schannel on Windows but it appears that Hyper configures it slightly
|
||||
# differently such that revocation checking isn't turned on by default.
|
||||
#
|
||||
# [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html
|
||||
RUSTUP_USE_HYPER: 1
|
||||
CARGO_HTTP_CHECK_REVOKE: false
|
||||
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
install:
|
||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test --benches
|
||||
- cargo test
|
||||
- cargo test --features nightly
|
||||
- cargo test --manifest-path rand-derive/Cargo.toml
|
|
@ -1,34 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
const RAND_BENCH_N: u64 = 1000;
|
||||
|
||||
mod distributions;
|
||||
|
||||
use std::mem::size_of;
|
||||
use test::{black_box, Bencher};
|
||||
use rand::{StdRng, Rng};
|
||||
|
||||
#[bench]
|
||||
fn rand_f32(b: &mut Bencher) {
|
||||
let mut rng = StdRng::new().unwrap();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.next_f32());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<f32>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_f64(b: &mut Bencher) {
|
||||
let mut rng = StdRng::new().unwrap();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.next_f64());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
use std::mem::size_of;
|
||||
use test::Bencher;
|
||||
use rand;
|
||||
use rand::distributions::exponential::Exp;
|
||||
use rand::distributions::Sample;
|
||||
|
||||
#[bench]
|
||||
fn rand_exp(b: &mut Bencher) {
|
||||
let mut rng = rand::weak_rng();
|
||||
let mut exp = Exp::new(2.71828 * 3.14159);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
exp.sample(&mut rng);
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
use std::mem::size_of;
|
||||
use test::Bencher;
|
||||
use rand;
|
||||
use rand::distributions::IndependentSample;
|
||||
use rand::distributions::gamma::Gamma;
|
||||
|
||||
#[bench]
|
||||
fn bench_gamma_large_shape(b: &mut Bencher) {
|
||||
let gamma = Gamma::new(10., 1.0);
|
||||
let mut rng = rand::weak_rng();
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
gamma.ind_sample(&mut rng);
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_gamma_small_shape(b: &mut Bencher) {
|
||||
let gamma = Gamma::new(0.1, 1.0);
|
||||
let mut rng = rand::weak_rng();
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
gamma.ind_sample(&mut rng);
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
mod exponential;
|
||||
mod normal;
|
||||
mod gamma;
|
|
@ -1,18 +0,0 @@
|
|||
use std::mem::size_of;
|
||||
use test::Bencher;
|
||||
use rand;
|
||||
use rand::distributions::Sample;
|
||||
use rand::distributions::normal::Normal;
|
||||
|
||||
#[bench]
|
||||
fn rand_normal(b: &mut Bencher) {
|
||||
let mut rng = rand::weak_rng();
|
||||
let mut normal = Normal::new(-2.71828, 3.14159);
|
||||
|
||||
b.iter(|| {
|
||||
for _ in 0..::RAND_BENCH_N {
|
||||
normal.sample(&mut rng);
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N;
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
const RAND_BENCH_N: u64 = 1000;
|
||||
const BYTES_LEN: usize = 1024;
|
||||
|
||||
use std::mem::size_of;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
use rand::{Rng, StdRng, OsRng, JitterRng};
|
||||
use rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng};
|
||||
|
||||
macro_rules! gen_bytes {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: $gen = OsRng::new().unwrap().gen();
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
rng.fill_bytes(&mut buf);
|
||||
black_box(buf);
|
||||
}
|
||||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gen_bytes_new {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen::new().unwrap();
|
||||
let mut buf = [0u8; BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
rng.fill_bytes(&mut buf);
|
||||
black_box(buf);
|
||||
}
|
||||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_bytes!(gen_bytes_xorshift, XorShiftRng);
|
||||
gen_bytes!(gen_bytes_isaac, IsaacRng);
|
||||
gen_bytes!(gen_bytes_isaac64, Isaac64Rng);
|
||||
gen_bytes!(gen_bytes_chacha, ChaChaRng);
|
||||
gen_bytes_new!(gen_bytes_std, StdRng);
|
||||
gen_bytes_new!(gen_bytes_os, OsRng);
|
||||
|
||||
|
||||
macro_rules! gen_uint {
|
||||
($fnn:ident, $ty:ty, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: $gen = OsRng::new().unwrap().gen();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.gen::<$ty>());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! gen_uint_new {
|
||||
($fnn:ident, $ty:ty, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = $gen::new().unwrap();
|
||||
b.iter(|| {
|
||||
for _ in 0..RAND_BENCH_N {
|
||||
black_box(rng.gen::<$ty>());
|
||||
}
|
||||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_uint!(gen_u32_xorshift, u32, XorShiftRng);
|
||||
gen_uint!(gen_u32_isaac, u32, IsaacRng);
|
||||
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng);
|
||||
gen_uint!(gen_u32_chacha, u32, ChaChaRng);
|
||||
gen_uint_new!(gen_u32_std, u32, StdRng);
|
||||
gen_uint_new!(gen_u32_os, u32, OsRng);
|
||||
|
||||
gen_uint!(gen_u64_xorshift, u64, XorShiftRng);
|
||||
gen_uint!(gen_u64_isaac, u64, IsaacRng);
|
||||
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng);
|
||||
gen_uint!(gen_u64_chacha, u64, ChaChaRng);
|
||||
gen_uint_new!(gen_u64_std, u64, StdRng);
|
||||
gen_uint_new!(gen_u64_os, u64, OsRng);
|
||||
|
||||
#[bench]
|
||||
fn gen_u64_jitter(b: &mut Bencher) {
|
||||
let mut rng = JitterRng::new().unwrap();
|
||||
b.iter(|| {
|
||||
black_box(rng.gen::<u64>());
|
||||
});
|
||||
b.bytes = size_of::<u64>() as u64;
|
||||
}
|
||||
|
||||
macro_rules! init_gen {
|
||||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng: XorShiftRng = OsRng::new().unwrap().gen();
|
||||
b.iter(|| {
|
||||
let r2: $gen = rng.gen();
|
||||
black_box(r2);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init_gen!(init_xorshift, XorShiftRng);
|
||||
init_gen!(init_isaac, IsaacRng);
|
||||
init_gen!(init_isaac64, Isaac64Rng);
|
||||
init_gen!(init_chacha, ChaChaRng);
|
||||
|
||||
#[bench]
|
||||
fn init_jitter(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
black_box(JitterRng::new().unwrap());
|
||||
});
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rand;
|
||||
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
use rand::{Rng, weak_rng};
|
||||
use rand::seq::*;
|
||||
|
||||
#[bench]
|
||||
fn misc_shuffle_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &mut [usize] = &mut [1; 100];
|
||||
b.iter(|| {
|
||||
rng.shuffle(x);
|
||||
black_box(&x);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &[usize] = &[1; 100];
|
||||
b.iter(|| {
|
||||
black_box(sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &[usize] = &[1; 100];
|
||||
b.iter(|| {
|
||||
black_box(sample_slice(&mut rng, x, 10));
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
let x : &[usize] = &[1; 100];
|
||||
b.iter(|| {
|
||||
black_box(sample_slice_ref(&mut rng, x, 10));
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! sample_indices {
|
||||
($name:ident, $amount:expr, $length:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut rng = weak_rng();
|
||||
b.iter(|| {
|
||||
black_box(sample_indices(&mut rng, $length, $amount));
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
|
||||
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
|
||||
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);
|
|
@ -1,124 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
//! The exponential distribution.
|
||||
|
||||
use {Rng, Rand};
|
||||
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
|
||||
|
||||
/// A wrapper around an `f64` to generate Exp(1) random numbers.
|
||||
///
|
||||
/// See `Exp` for the general exponential distribution.
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
|
||||
/// exact description in the paper was adjusted to use tables for the
|
||||
/// exponential distribution rather than normal.
|
||||
///
|
||||
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random
|
||||
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
|
||||
/// College, Oxford
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::exponential::Exp1;
|
||||
///
|
||||
/// let Exp1(x) = rand::random();
|
||||
/// println!("{}", x);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp1(pub f64);
|
||||
|
||||
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
|
||||
impl Rand for Exp1 {
|
||||
#[inline]
|
||||
fn rand<R:Rng>(rng: &mut R) -> Exp1 {
|
||||
#[inline]
|
||||
fn pdf(x: f64) -> f64 {
|
||||
(-x).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
|
||||
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
|
||||
}
|
||||
|
||||
Exp1(ziggurat(rng, false,
|
||||
&ziggurat_tables::ZIG_EXP_X,
|
||||
&ziggurat_tables::ZIG_EXP_F,
|
||||
pdf, zero_case))
|
||||
}
|
||||
}
|
||||
|
||||
/// The exponential distribution `Exp(lambda)`.
|
||||
///
|
||||
/// This distribution has density function: `f(x) = lambda *
|
||||
/// exp(-lambda * x)` for `x > 0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{Exp, IndependentSample};
|
||||
///
|
||||
/// let exp = Exp::new(2.0);
|
||||
/// let v = exp.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Exp(2) distribution", v);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp {
|
||||
/// `lambda` stored as `1/lambda`, since this is what we scale by.
|
||||
lambda_inverse: f64
|
||||
}
|
||||
|
||||
impl Exp {
|
||||
/// Construct a new `Exp` with the given shape parameter
|
||||
/// `lambda`. Panics if `lambda <= 0`.
|
||||
#[inline]
|
||||
pub fn new(lambda: f64) -> Exp {
|
||||
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
|
||||
Exp { lambda_inverse: 1.0 / lambda }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample<f64> for Exp {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for Exp {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let Exp1(n) = rng.gen::<Exp1>();
|
||||
n * self.lambda_inverse
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::Exp;
|
||||
|
||||
#[test]
|
||||
fn test_exp() {
|
||||
let mut exp = Exp::new(10.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
assert!(exp.sample(&mut rng) >= 0.0);
|
||||
assert!(exp.ind_sample(&mut rng) >= 0.0);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exp_invalid_lambda_zero() {
|
||||
Exp::new(0.0);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exp_invalid_lambda_neg() {
|
||||
Exp::new(-10.0);
|
||||
}
|
||||
}
|
|
@ -1,386 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
//
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
//! The Gamma and derived distributions.
|
||||
|
||||
use self::GammaRepr::*;
|
||||
use self::ChiSquaredRepr::*;
|
||||
|
||||
use {Rng, Open01};
|
||||
use super::normal::StandardNormal;
|
||||
use super::{IndependentSample, Sample, Exp};
|
||||
|
||||
/// The Gamma distribution `Gamma(shape, scale)` distribution.
|
||||
///
|
||||
/// The density function of this distribution is
|
||||
///
|
||||
/// ```text
|
||||
/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
|
||||
/// ```
|
||||
///
|
||||
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
|
||||
/// scale and both `k` and `θ` are strictly positive.
|
||||
///
|
||||
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
|
||||
/// falling back to directly sampling from an Exponential for `shape
|
||||
/// == 1`, and using the boosting technique described in [1] for
|
||||
/// `shape < 1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{IndependentSample, Gamma};
|
||||
///
|
||||
/// let gamma = Gamma::new(2.0, 5.0);
|
||||
/// let v = gamma.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a Gamma(2, 5) distribution", v);
|
||||
/// ```
|
||||
///
|
||||
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
|
||||
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
|
||||
/// (September 2000),
|
||||
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Gamma {
|
||||
repr: GammaRepr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum GammaRepr {
|
||||
Large(GammaLargeShape),
|
||||
One(Exp),
|
||||
Small(GammaSmallShape)
|
||||
}
|
||||
|
||||
// These two helpers could be made public, but saving the
|
||||
// match-on-Gamma-enum branch from using them directly (e.g. if one
|
||||
// knows that the shape is always > 1) doesn't appear to be much
|
||||
// faster.
|
||||
|
||||
/// Gamma distribution where the shape parameter is less than 1.
|
||||
///
|
||||
/// Note, samples from this require a compulsory floating-point `pow`
|
||||
/// call, which makes it significantly slower than sampling from a
|
||||
/// gamma distribution where the shape parameter is greater than or
|
||||
/// equal to 1.
|
||||
///
|
||||
/// See `Gamma` for sampling from a Gamma distribution with general
|
||||
/// shape parameters.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaSmallShape {
|
||||
inv_shape: f64,
|
||||
large_shape: GammaLargeShape
|
||||
}
|
||||
|
||||
/// Gamma distribution where the shape parameter is larger than 1.
|
||||
///
|
||||
/// See `Gamma` for sampling from a Gamma distribution with general
|
||||
/// shape parameters.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaLargeShape {
|
||||
scale: f64,
|
||||
c: f64,
|
||||
d: f64
|
||||
}
|
||||
|
||||
impl Gamma {
|
||||
/// Construct an object representing the `Gamma(shape, scale)`
|
||||
/// distribution.
|
||||
///
|
||||
/// Panics if `shape <= 0` or `scale <= 0`.
|
||||
#[inline]
|
||||
pub fn new(shape: f64, scale: f64) -> Gamma {
|
||||
assert!(shape > 0.0, "Gamma::new called with shape <= 0");
|
||||
assert!(scale > 0.0, "Gamma::new called with scale <= 0");
|
||||
|
||||
let repr = if shape == 1.0 {
|
||||
One(Exp::new(1.0 / scale))
|
||||
} else if shape < 1.0 {
|
||||
Small(GammaSmallShape::new_raw(shape, scale))
|
||||
} else {
|
||||
Large(GammaLargeShape::new_raw(shape, scale))
|
||||
};
|
||||
Gamma { repr: repr }
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaSmallShape {
|
||||
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
|
||||
GammaSmallShape {
|
||||
inv_shape: 1. / shape,
|
||||
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GammaLargeShape {
|
||||
fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
|
||||
let d = shape - 1. / 3.;
|
||||
GammaLargeShape {
|
||||
scale: scale,
|
||||
c: 1. / (9. * d).sqrt(),
|
||||
d: d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample<f64> for Gamma {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl Sample<f64> for GammaSmallShape {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl Sample<f64> for GammaLargeShape {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl IndependentSample<f64> for Gamma {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
match self.repr {
|
||||
Small(ref g) => g.ind_sample(rng),
|
||||
One(ref g) => g.ind_sample(rng),
|
||||
Large(ref g) => g.ind_sample(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IndependentSample<f64> for GammaSmallShape {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let Open01(u) = rng.gen::<Open01<f64>>();
|
||||
|
||||
self.large_shape.ind_sample(rng) * u.powf(self.inv_shape)
|
||||
}
|
||||
}
|
||||
impl IndependentSample<f64> for GammaLargeShape {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
loop {
|
||||
let StandardNormal(x) = rng.gen::<StandardNormal>();
|
||||
let v_cbrt = 1.0 + self.c * x;
|
||||
if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
|
||||
continue
|
||||
}
|
||||
|
||||
let v = v_cbrt * v_cbrt * v_cbrt;
|
||||
let Open01(u) = rng.gen::<Open01<f64>>();
|
||||
|
||||
let x_sqr = x * x;
|
||||
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
|
||||
u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
|
||||
return self.d * v * self.scale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
|
||||
/// freedom.
|
||||
///
|
||||
/// For `k > 0` integral, this distribution is the sum of the squares
|
||||
/// of `k` independent standard normal random variables. For other
|
||||
/// `k`, this uses the equivalent characterisation
|
||||
/// `χ²(k) = Gamma(k/2, 2)`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{ChiSquared, IndependentSample};
|
||||
///
|
||||
/// let chi = ChiSquared::new(11.0);
|
||||
/// let v = chi.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a χ²(11) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ChiSquared {
|
||||
repr: ChiSquaredRepr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum ChiSquaredRepr {
|
||||
// k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
|
||||
// e.g. when alpha = 1/2 as it would be for this case, so special-
|
||||
// casing and using the definition of N(0,1)^2 is faster.
|
||||
DoFExactlyOne,
|
||||
DoFAnythingElse(Gamma),
|
||||
}
|
||||
|
||||
impl ChiSquared {
|
||||
/// Create a new chi-squared distribution with degrees-of-freedom
|
||||
/// `k`. Panics if `k < 0`.
|
||||
pub fn new(k: f64) -> ChiSquared {
|
||||
let repr = if k == 1.0 {
|
||||
DoFExactlyOne
|
||||
} else {
|
||||
assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
|
||||
DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
|
||||
};
|
||||
ChiSquared { repr: repr }
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for ChiSquared {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for ChiSquared {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
match self.repr {
|
||||
DoFExactlyOne => {
|
||||
// k == 1 => N(0,1)^2
|
||||
let StandardNormal(norm) = rng.gen::<StandardNormal>();
|
||||
norm * norm
|
||||
}
|
||||
DoFAnythingElse(ref g) => g.ind_sample(rng)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Fisher F distribution `F(m, n)`.
|
||||
///
|
||||
/// This distribution is equivalent to the ratio of two normalised
|
||||
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
|
||||
/// (χ²(n)/n)`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{FisherF, IndependentSample};
|
||||
///
|
||||
/// let f = FisherF::new(2.0, 32.0);
|
||||
/// let v = f.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an F(2, 32) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FisherF {
|
||||
numer: ChiSquared,
|
||||
denom: ChiSquared,
|
||||
// denom_dof / numer_dof so that this can just be a straight
|
||||
// multiplication, rather than a division.
|
||||
dof_ratio: f64,
|
||||
}
|
||||
|
||||
impl FisherF {
|
||||
/// Create a new `FisherF` distribution, with the given
|
||||
/// parameter. Panics if either `m` or `n` are not positive.
|
||||
pub fn new(m: f64, n: f64) -> FisherF {
|
||||
assert!(m > 0.0, "FisherF::new called with `m < 0`");
|
||||
assert!(n > 0.0, "FisherF::new called with `n < 0`");
|
||||
|
||||
FisherF {
|
||||
numer: ChiSquared::new(m),
|
||||
denom: ChiSquared::new(n),
|
||||
dof_ratio: n / m
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for FisherF {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for FisherF {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
|
||||
}
|
||||
}
|
||||
|
||||
/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
|
||||
/// freedom.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{StudentT, IndependentSample};
|
||||
///
|
||||
/// let t = StudentT::new(11.0);
|
||||
/// let v = t.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a t(11) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StudentT {
|
||||
chi: ChiSquared,
|
||||
dof: f64
|
||||
}
|
||||
|
||||
impl StudentT {
|
||||
/// Create a new Student t distribution with `n` degrees of
|
||||
/// freedom. Panics if `n <= 0`.
|
||||
pub fn new(n: f64) -> StudentT {
|
||||
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
|
||||
StudentT {
|
||||
chi: ChiSquared::new(n),
|
||||
dof: n
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for StudentT {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for StudentT {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let StandardNormal(norm) = rng.gen::<StandardNormal>();
|
||||
norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::{ChiSquared, StudentT, FisherF};
|
||||
|
||||
#[test]
|
||||
fn test_chi_squared_one() {
|
||||
let mut chi = ChiSquared::new(1.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
chi.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_chi_squared_small() {
|
||||
let mut chi = ChiSquared::new(0.5);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
chi.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_chi_squared_large() {
|
||||
let mut chi = ChiSquared::new(30.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
chi.sample(&mut rng);
|
||||
chi.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_chi_squared_invalid_dof() {
|
||||
ChiSquared::new(-1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f() {
|
||||
let mut f = FisherF::new(2.0, 32.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
f.sample(&mut rng);
|
||||
f.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_t() {
|
||||
let mut t = StudentT::new(11.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
t.sample(&mut rng);
|
||||
t.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,409 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
//! Sampling from random distributions.
|
||||
//!
|
||||
//! This is a generalization of `Rand` to allow parameters to control the
|
||||
//! exact properties of the generated values, e.g. the mean and standard
|
||||
//! deviation of a normal distribution. The `Sample` trait is the most
|
||||
//! general, and allows for generating values that change some state
|
||||
//! internally. The `IndependentSample` trait is for generating values
|
||||
//! that do not need to record state.
|
||||
|
||||
use core::marker;
|
||||
|
||||
use {Rng, Rand};
|
||||
|
||||
pub use self::range::Range;
|
||||
#[cfg(feature="std")]
|
||||
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
|
||||
#[cfg(feature="std")]
|
||||
pub use self::normal::{Normal, LogNormal};
|
||||
#[cfg(feature="std")]
|
||||
pub use self::exponential::Exp;
|
||||
|
||||
pub mod range;
|
||||
#[cfg(feature="std")]
|
||||
pub mod gamma;
|
||||
#[cfg(feature="std")]
|
||||
pub mod normal;
|
||||
#[cfg(feature="std")]
|
||||
pub mod exponential;
|
||||
|
||||
#[cfg(feature="std")]
|
||||
mod ziggurat_tables;
|
||||
|
||||
/// Types that can be used to create a random instance of `Support`.
|
||||
pub trait Sample<Support> {
|
||||
/// Generate a random value of `Support`, using `rng` as the
|
||||
/// source of randomness.
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
|
||||
}
|
||||
|
||||
/// `Sample`s that do not require keeping track of state.
|
||||
///
|
||||
/// Since no state is recorded, each sample is (statistically)
|
||||
/// independent of all others, assuming the `Rng` used has this
|
||||
/// property.
|
||||
// FIXME maybe having this separate is overkill (the only reason is to
|
||||
// take &self rather than &mut self)? or maybe this should be the
|
||||
// trait called `Sample` and the other should be `DependentSample`.
|
||||
pub trait IndependentSample<Support>: Sample<Support> {
|
||||
/// Generate a random value.
|
||||
fn ind_sample<R: Rng>(&self, &mut R) -> Support;
|
||||
}
|
||||
|
||||
/// A wrapper for generating types that implement `Rand` via the
|
||||
/// `Sample` & `IndependentSample` traits.
|
||||
#[derive(Debug)]
|
||||
pub struct RandSample<Sup> {
|
||||
_marker: marker::PhantomData<fn() -> Sup>,
|
||||
}
|
||||
|
||||
impl<Sup> Copy for RandSample<Sup> {}
|
||||
impl<Sup> Clone for RandSample<Sup> {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
|
||||
rng.gen()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Sup> RandSample<Sup> {
|
||||
pub fn new() -> RandSample<Sup> {
|
||||
RandSample { _marker: marker::PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
/// A value with a particular weight for use with `WeightedChoice`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Weighted<T> {
|
||||
/// The numerical weight of this item
|
||||
pub weight: u32,
|
||||
/// The actual item which is being weighted
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
/// A distribution that selects from a finite collection of weighted items.
|
||||
///
|
||||
/// Each item has an associated weight that influences how likely it
|
||||
/// is to be chosen: higher weight is more likely.
|
||||
///
|
||||
/// The `Clone` restriction is a limitation of the `Sample` and
|
||||
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
|
||||
/// all `T`, as is `u32`, so one can store references or indices into
|
||||
/// another vector.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{Weighted, WeightedChoice, IndependentSample};
|
||||
///
|
||||
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
|
||||
/// Weighted { weight: 4, item: 'b' },
|
||||
/// Weighted { weight: 1, item: 'c' });
|
||||
/// let wc = WeightedChoice::new(&mut items);
|
||||
/// let mut rng = rand::thread_rng();
|
||||
/// for _ in 0..16 {
|
||||
/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
|
||||
/// println!("{}", wc.ind_sample(&mut rng));
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct WeightedChoice<'a, T:'a> {
|
||||
items: &'a mut [Weighted<T>],
|
||||
weight_range: Range<u32>
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> WeightedChoice<'a, T> {
|
||||
/// Create a new `WeightedChoice`.
|
||||
///
|
||||
/// Panics if:
|
||||
///
|
||||
/// - `items` is empty
|
||||
/// - the total weight is 0
|
||||
/// - the total weight is larger than a `u32` can contain.
|
||||
pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
|
||||
// strictly speaking, this is subsumed by the total weight == 0 case
|
||||
assert!(!items.is_empty(), "WeightedChoice::new called with no items");
|
||||
|
||||
let mut running_total: u32 = 0;
|
||||
|
||||
// we convert the list from individual weights to cumulative
|
||||
// weights so we can binary search. This *could* drop elements
|
||||
// with weight == 0 as an optimisation.
|
||||
for item in items.iter_mut() {
|
||||
running_total = match running_total.checked_add(item.weight) {
|
||||
Some(n) => n,
|
||||
None => panic!("WeightedChoice::new called with a total weight \
|
||||
larger than a u32 can contain")
|
||||
};
|
||||
|
||||
item.weight = running_total;
|
||||
}
|
||||
assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
|
||||
|
||||
WeightedChoice {
|
||||
items: items,
|
||||
// we're likely to be generating numbers in this range
|
||||
// relatively often, so might as well cache it
|
||||
weight_range: Range::new(0, running_total)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
|
||||
// we want to find the first element that has cumulative
|
||||
// weight > sample_weight, which we do by binary since the
|
||||
// cumulative weights of self.items are sorted.
|
||||
|
||||
// choose a weight in [0, total_weight)
|
||||
let sample_weight = self.weight_range.ind_sample(rng);
|
||||
|
||||
// short circuit when it's the first item
|
||||
if sample_weight < self.items[0].weight {
|
||||
return self.items[0].item.clone();
|
||||
}
|
||||
|
||||
let mut idx = 0;
|
||||
let mut modifier = self.items.len();
|
||||
|
||||
// now we know that every possibility has an element to the
|
||||
// left, so we can just search for the last element that has
|
||||
// cumulative weight <= sample_weight, then the next one will
|
||||
// be "it". (Note that this greatest element will never be the
|
||||
// last element of the vector, since sample_weight is chosen
|
||||
// in [0, total_weight) and the cumulative weight of the last
|
||||
// one is exactly the total weight.)
|
||||
while modifier > 1 {
|
||||
let i = idx + modifier / 2;
|
||||
if self.items[i].weight <= sample_weight {
|
||||
// we're small, so look to the right, but allow this
|
||||
// exact element still.
|
||||
idx = i;
|
||||
// we need the `/ 2` to round up otherwise we'll drop
|
||||
// the trailing elements when `modifier` is odd.
|
||||
modifier += 1;
|
||||
} else {
|
||||
// otherwise we're too big, so go left. (i.e. do
|
||||
// nothing)
|
||||
}
|
||||
modifier /= 2;
|
||||
}
|
||||
return self.items[idx + 1].item.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample a random number using the Ziggurat method (specifically the
|
||||
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
|
||||
/// directly from the paper:
|
||||
///
|
||||
/// * `rng`: source of randomness
|
||||
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
|
||||
/// * `X`: the $x_i$ abscissae.
|
||||
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
|
||||
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
|
||||
/// * `pdf`: the probability density function
|
||||
/// * `zero_case`: manual sampling from the tail when we chose the
|
||||
/// bottom box (i.e. i == 0)
|
||||
|
||||
// the perf improvement (25-50%) is definitely worth the extra code
|
||||
// size from force-inlining.
|
||||
#[cfg(feature="std")]
|
||||
#[inline(always)]
|
||||
fn ziggurat<R: Rng, P, Z>(
|
||||
rng: &mut R,
|
||||
symmetric: bool,
|
||||
x_tab: ziggurat_tables::ZigTable,
|
||||
f_tab: ziggurat_tables::ZigTable,
|
||||
mut pdf: P,
|
||||
mut zero_case: Z)
|
||||
-> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
|
||||
const SCALE: f64 = (1u64 << 53) as f64;
|
||||
loop {
|
||||
// reimplement the f64 generation as an optimisation suggested
|
||||
// by the Doornik paper: we have a lot of precision-space
|
||||
// (i.e. there are 11 bits of the 64 of a u64 to use after
|
||||
// creating a f64), so we might as well reuse some to save
|
||||
// generating a whole extra random number. (Seems to be 15%
|
||||
// faster.)
|
||||
//
|
||||
// This unfortunately misses out on the benefits of direct
|
||||
// floating point generation if an RNG like dSMFT is
|
||||
// used. (That is, such RNGs create floats directly, highly
|
||||
// efficiently and overload next_f32/f64, so by not calling it
|
||||
// this may be slower than it would be otherwise.)
|
||||
// FIXME: investigate/optimise for the above.
|
||||
let bits: u64 = rng.gen();
|
||||
let i = (bits & 0xff) as usize;
|
||||
let f = (bits >> 11) as f64 / SCALE;
|
||||
|
||||
// u is either U(-1, 1) or U(0, 1) depending on if this is a
|
||||
// symmetric distribution or not.
|
||||
let u = if symmetric {2.0 * f - 1.0} else {f};
|
||||
let x = u * x_tab[i];
|
||||
|
||||
let test_x = if symmetric { x.abs() } else {x};
|
||||
|
||||
// algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
|
||||
if test_x < x_tab[i + 1] {
|
||||
return x;
|
||||
}
|
||||
if i == 0 {
|
||||
return zero_case(rng, u);
|
||||
}
|
||||
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
|
||||
if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use {Rng, Rand};
|
||||
use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct ConstRand(usize);
|
||||
impl Rand for ConstRand {
|
||||
fn rand<R: Rng>(_: &mut R) -> ConstRand {
|
||||
ConstRand(0)
|
||||
}
|
||||
}
|
||||
|
||||
// 0, 1, 2, 3, ...
|
||||
struct CountingRng { i: u32 }
|
||||
impl Rng for CountingRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.i += 1;
|
||||
self.i - 1
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.next_u32() as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_sample() {
|
||||
let mut rand_sample = RandSample::<ConstRand>::new();
|
||||
|
||||
assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
|
||||
assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
|
||||
}
|
||||
#[test]
|
||||
fn test_weighted_choice() {
|
||||
// this makes assumptions about the internal implementation of
|
||||
// WeightedChoice, specifically: it doesn't reorder the items,
|
||||
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
|
||||
// 1, internally; modulo a modulo operation).
|
||||
|
||||
macro_rules! t {
|
||||
($items:expr, $expected:expr) => {{
|
||||
let mut items = $items;
|
||||
let wc = WeightedChoice::new(&mut items);
|
||||
let expected = $expected;
|
||||
|
||||
let mut rng = CountingRng { i: 0 };
|
||||
|
||||
for &val in expected.iter() {
|
||||
assert_eq!(wc.ind_sample(&mut rng), val)
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
t!(vec!(Weighted { weight: 1, item: 10}), [10]);
|
||||
|
||||
// skip some
|
||||
t!(vec!(Weighted { weight: 0, item: 20},
|
||||
Weighted { weight: 2, item: 21},
|
||||
Weighted { weight: 0, item: 22},
|
||||
Weighted { weight: 1, item: 23}),
|
||||
[21,21, 23]);
|
||||
|
||||
// different weights
|
||||
t!(vec!(Weighted { weight: 4, item: 30},
|
||||
Weighted { weight: 3, item: 31}),
|
||||
[30,30,30,30, 31,31,31]);
|
||||
|
||||
// check that we're binary searching
|
||||
// correctly with some vectors of odd
|
||||
// length.
|
||||
t!(vec!(Weighted { weight: 1, item: 40},
|
||||
Weighted { weight: 1, item: 41},
|
||||
Weighted { weight: 1, item: 42},
|
||||
Weighted { weight: 1, item: 43},
|
||||
Weighted { weight: 1, item: 44}),
|
||||
[40, 41, 42, 43, 44]);
|
||||
t!(vec!(Weighted { weight: 1, item: 50},
|
||||
Weighted { weight: 1, item: 51},
|
||||
Weighted { weight: 1, item: 52},
|
||||
Weighted { weight: 1, item: 53},
|
||||
Weighted { weight: 1, item: 54},
|
||||
Weighted { weight: 1, item: 55},
|
||||
Weighted { weight: 1, item: 56}),
|
||||
[50, 51, 52, 53, 54, 55, 56]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weighted_clone_initialization() {
|
||||
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
|
||||
let clone = initial.clone();
|
||||
assert_eq!(initial.weight, clone.weight);
|
||||
assert_eq!(initial.item, clone.item);
|
||||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_clone_change_weight() {
|
||||
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
|
||||
let mut clone = initial.clone();
|
||||
clone.weight = 5;
|
||||
assert_eq!(initial.weight, clone.weight);
|
||||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_clone_change_item() {
|
||||
let initial : Weighted<u32> = Weighted {weight: 1, item: 1};
|
||||
let mut clone = initial.clone();
|
||||
clone.item = 5;
|
||||
assert_eq!(initial.item, clone.item);
|
||||
|
||||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_choice_no_items() {
|
||||
WeightedChoice::<isize>::new(&mut []);
|
||||
}
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_choice_zero_weight() {
|
||||
WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
|
||||
Weighted { weight: 0, item: 1}]);
|
||||
}
|
||||
#[test] #[should_panic]
|
||||
fn test_weighted_choice_weight_overflows() {
|
||||
let x = ::std::u32::MAX / 2; // x + x + 2 is the overflow
|
||||
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
|
||||
Weighted { weight: 1, item: 1 },
|
||||
Weighted { weight: x, item: 2 },
|
||||
Weighted { weight: 1, item: 3 }]);
|
||||
}
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
//! The normal and derived distributions.
|
||||
|
||||
use {Rng, Rand, Open01};
|
||||
use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
|
||||
|
||||
/// A wrapper around an `f64` to generate N(0, 1) random numbers
|
||||
/// (a.k.a. a standard normal, or Gaussian).
|
||||
///
|
||||
/// See `Normal` for the general normal distribution.
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
|
||||
///
|
||||
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random
|
||||
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
|
||||
/// College, Oxford
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::normal::StandardNormal;
|
||||
///
|
||||
/// let StandardNormal(x) = rand::random();
|
||||
/// println!("{}", x);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StandardNormal(pub f64);
|
||||
|
||||
impl Rand for StandardNormal {
|
||||
fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
|
||||
#[inline]
|
||||
fn pdf(x: f64) -> f64 {
|
||||
(-x*x/2.0).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
|
||||
// compute a random number in the tail by hand
|
||||
|
||||
// strange initial conditions, because the loop is not
|
||||
// do-while, so the condition should be true on the first
|
||||
// run, they get overwritten anyway (0 < 1, so these are
|
||||
// good).
|
||||
let mut x = 1.0f64;
|
||||
let mut y = 0.0f64;
|
||||
|
||||
while -2.0 * y < x * x {
|
||||
let Open01(x_) = rng.gen::<Open01<f64>>();
|
||||
let Open01(y_) = rng.gen::<Open01<f64>>();
|
||||
|
||||
x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
|
||||
y = y_.ln();
|
||||
}
|
||||
|
||||
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
|
||||
}
|
||||
|
||||
StandardNormal(ziggurat(
|
||||
rng,
|
||||
true, // this is symmetric
|
||||
&ziggurat_tables::ZIG_NORM_X,
|
||||
&ziggurat_tables::ZIG_NORM_F,
|
||||
pdf, zero_case))
|
||||
}
|
||||
}
|
||||
|
||||
/// The normal distribution `N(mean, std_dev**2)`.
|
||||
///
|
||||
/// This uses the ZIGNOR variant of the Ziggurat method, see
|
||||
/// `StandardNormal` for more details.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{Normal, IndependentSample};
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let normal = Normal::new(2.0, 3.0);
|
||||
/// let v = normal.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from a N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Normal {
|
||||
mean: f64,
|
||||
std_dev: f64,
|
||||
}
|
||||
|
||||
impl Normal {
|
||||
/// Construct a new `Normal` distribution with the given mean and
|
||||
/// standard deviation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `std_dev < 0`.
|
||||
#[inline]
|
||||
pub fn new(mean: f64, std_dev: f64) -> Normal {
|
||||
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
|
||||
Normal {
|
||||
mean: mean,
|
||||
std_dev: std_dev
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for Normal {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for Normal {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
let StandardNormal(n) = rng.gen::<StandardNormal>();
|
||||
self.mean + self.std_dev * n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// The log-normal distribution `ln N(mean, std_dev**2)`.
|
||||
///
|
||||
/// If `X` is log-normal distributed, then `ln(X)` is `N(mean,
|
||||
/// std_dev**2)` distributed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{LogNormal, IndependentSample};
|
||||
///
|
||||
/// // mean 2, standard deviation 3
|
||||
/// let log_normal = LogNormal::new(2.0, 3.0);
|
||||
/// let v = log_normal.ind_sample(&mut rand::thread_rng());
|
||||
/// println!("{} is from an ln N(2, 9) distribution", v)
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LogNormal {
|
||||
norm: Normal
|
||||
}
|
||||
|
||||
impl LogNormal {
|
||||
/// Construct a new `LogNormal` distribution with the given mean
|
||||
/// and standard deviation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `std_dev < 0`.
|
||||
#[inline]
|
||||
pub fn new(mean: f64, std_dev: f64) -> LogNormal {
|
||||
assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0");
|
||||
LogNormal { norm: Normal::new(mean, std_dev) }
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for LogNormal {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for LogNormal {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
self.norm.ind_sample(rng).exp()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::{Normal, LogNormal};
|
||||
|
||||
#[test]
|
||||
fn test_normal() {
|
||||
let mut norm = Normal::new(10.0, 10.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
norm.sample(&mut rng);
|
||||
norm.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_normal_invalid_sd() {
|
||||
Normal::new(10.0, -1.0);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_log_normal() {
|
||||
let mut lnorm = LogNormal::new(10.0, 10.0);
|
||||
let mut rng = ::test::rng();
|
||||
for _ in 0..1000 {
|
||||
lnorm.sample(&mut rng);
|
||||
lnorm.ind_sample(&mut rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_log_normal_invalid_sd() {
|
||||
LogNormal::new(10.0, -1.0);
|
||||
}
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
//! Generating numbers between two others.
|
||||
|
||||
// this is surprisingly complicated to be both generic & correct
|
||||
|
||||
use core::num::Wrapping as w;
|
||||
|
||||
use Rng;
|
||||
use distributions::{Sample, IndependentSample};
|
||||
|
||||
/// Sample values uniformly between two bounds.
|
||||
///
|
||||
/// This gives a uniform distribution (assuming the RNG used to sample
|
||||
/// it is itself uniform & the `SampleRange` implementation for the
|
||||
/// given type is correct), even for edge cases like `low = 0u8`,
|
||||
/// `high = 170u8`, for which a naive modulo operation would return
|
||||
/// numbers less than 85 with double the probability to those greater
|
||||
/// than 85.
|
||||
///
|
||||
/// Types should attempt to sample in `[low, high)`, i.e., not
|
||||
/// including `high`, but this may be very difficult. All the
|
||||
/// primitive integer types satisfy this property, and the float types
|
||||
/// normally satisfy it, but rounding may mean `high` can occur.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::distributions::{IndependentSample, Range};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let between = Range::new(10, 10000);
|
||||
/// let mut rng = rand::thread_rng();
|
||||
/// let mut sum = 0;
|
||||
/// for _ in 0..1000 {
|
||||
/// sum += between.ind_sample(&mut rng);
|
||||
/// }
|
||||
/// println!("{}", sum);
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Range<X> {
|
||||
low: X,
|
||||
range: X,
|
||||
accept_zone: X
|
||||
}
|
||||
|
||||
impl<X: SampleRange + PartialOrd> Range<X> {
|
||||
/// Create a new `Range` instance that samples uniformly from
|
||||
/// `[low, high)`. Panics if `low >= high`.
|
||||
pub fn new(low: X, high: X) -> Range<X> {
|
||||
assert!(low < high, "Range::new called with `low >= high`");
|
||||
SampleRange::construct_range(low, high)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
|
||||
#[inline]
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
|
||||
}
|
||||
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
|
||||
SampleRange::sample_range(self, rng)
|
||||
}
|
||||
}
|
||||
|
||||
/// The helper trait for types that have a sensible way to sample
|
||||
/// uniformly between two values. This should not be used directly,
|
||||
/// and is only to facilitate `Range`.
|
||||
pub trait SampleRange : Sized {
|
||||
/// Construct the `Range` object that `sample_range`
|
||||
/// requires. This should not ever be called directly, only via
|
||||
/// `Range::new`, which will check that `low < high`, so this
|
||||
/// function doesn't have to repeat the check.
|
||||
fn construct_range(low: Self, high: Self) -> Range<Self>;
|
||||
|
||||
/// Sample a value from the given `Range` with the given `Rng` as
|
||||
/// a source of randomness.
|
||||
fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! integer_impl {
|
||||
($ty:ty, $unsigned:ident) => {
|
||||
impl SampleRange for $ty {
|
||||
// we play free and fast with unsigned vs signed here
|
||||
// (when $ty is signed), but that's fine, since the
|
||||
// contract of this macro is for $ty and $unsigned to be
|
||||
// "bit-equal", so casting between them is a no-op & a
|
||||
// bijection.
|
||||
|
||||
#[inline]
|
||||
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
|
||||
let range = (w(high as $unsigned) - w(low as $unsigned)).0;
|
||||
let unsigned_max: $unsigned = ::core::$unsigned::MAX;
|
||||
|
||||
// this is the largest number that fits into $unsigned
|
||||
// that `range` divides evenly, so, if we've sampled
|
||||
// `n` uniformly from this region, then `n % range` is
|
||||
// uniform in [0, range)
|
||||
let zone = unsigned_max - unsigned_max % range;
|
||||
|
||||
Range {
|
||||
low: low,
|
||||
range: range as $ty,
|
||||
accept_zone: zone as $ty
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
|
||||
loop {
|
||||
// rejection sample
|
||||
let v = rng.gen::<$unsigned>();
|
||||
// until we find something that fits into the
|
||||
// region which r.range evenly divides (this will
|
||||
// be uniformly distributed)
|
||||
if v < r.accept_zone as $unsigned {
|
||||
// and return it, with some adjustments
|
||||
return (w(r.low) + w((v % r.range as $unsigned) as $ty)).0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
integer_impl! { i8, u8 }
|
||||
integer_impl! { i16, u16 }
|
||||
integer_impl! { i32, u32 }
|
||||
integer_impl! { i64, u64 }
|
||||
#[cfg(feature = "i128_support")]
|
||||
integer_impl! { i128, u128 }
|
||||
integer_impl! { isize, usize }
|
||||
integer_impl! { u8, u8 }
|
||||
integer_impl! { u16, u16 }
|
||||
integer_impl! { u32, u32 }
|
||||
integer_impl! { u64, u64 }
|
||||
#[cfg(feature = "i128_support")]
|
||||
integer_impl! { u128, u128 }
|
||||
integer_impl! { usize, usize }
|
||||
|
||||
macro_rules! float_impl {
|
||||
($ty:ty) => {
|
||||
impl SampleRange for $ty {
|
||||
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
|
||||
Range {
|
||||
low: low,
|
||||
range: high - low,
|
||||
accept_zone: 0.0 // unused
|
||||
}
|
||||
}
|
||||
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
|
||||
r.low + r.range * rng.gen::<$ty>()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_impl! { f32 }
|
||||
float_impl! { f64 }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use distributions::{Sample, IndependentSample};
|
||||
use super::Range as Range;
|
||||
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_range_bad_limits_equal() {
|
||||
Range::new(10, 10);
|
||||
}
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_range_bad_limits_flipped() {
|
||||
Range::new(10, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integers() {
|
||||
let mut rng = ::test::rng();
|
||||
macro_rules! t {
|
||||
($($ty:ident),*) => {{
|
||||
$(
|
||||
let v: &[($ty, $ty)] = &[(0, 10),
|
||||
(10, 127),
|
||||
(::core::$ty::MIN, ::core::$ty::MAX)];
|
||||
for &(low, high) in v.iter() {
|
||||
let mut sampler: Range<$ty> = Range::new(low, high);
|
||||
for _ in 0..1000 {
|
||||
let v = sampler.sample(&mut rng);
|
||||
assert!(low <= v && v < high);
|
||||
let v = sampler.ind_sample(&mut rng);
|
||||
assert!(low <= v && v < high);
|
||||
}
|
||||
}
|
||||
)*
|
||||
}}
|
||||
}
|
||||
#[cfg(not(feature = "i128_support"))]
|
||||
t!(i8, i16, i32, i64, isize,
|
||||
u8, u16, u32, u64, usize);
|
||||
#[cfg(feature = "i128_support")]
|
||||
t!(i8, i16, i32, i64, i128, isize,
|
||||
u8, u16, u32, u64, u128, usize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_floats() {
|
||||
let mut rng = ::test::rng();
|
||||
macro_rules! t {
|
||||
($($ty:ty),*) => {{
|
||||
$(
|
||||
let v: &[($ty, $ty)] = &[(0.0, 100.0),
|
||||
(-1e35, -1e25),
|
||||
(1e-35, 1e-25),
|
||||
(-1e35, 1e35)];
|
||||
for &(low, high) in v.iter() {
|
||||
let mut sampler: Range<$ty> = Range::new(low, high);
|
||||
for _ in 0..1000 {
|
||||
let v = sampler.sample(&mut rng);
|
||||
assert!(low <= v && v < high);
|
||||
let v = sampler.ind_sample(&mut rng);
|
||||
assert!(low <= v && v < high);
|
||||
}
|
||||
}
|
||||
)*
|
||||
}}
|
||||
}
|
||||
|
||||
t!(f32, f64)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
// Tables for distributions which are sampled using the ziggurat
|
||||
// algorithm. Autogenerated by `ziggurat_tables.py`.
|
||||
|
||||
pub type ZigTable = &'static [f64; 257];
|
||||
pub const ZIG_NORM_R: f64 = 3.654152885361008796;
|
||||
pub static ZIG_NORM_X: [f64; 257] =
|
||||
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
|
||||
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
|
||||
2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
|
||||
2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
|
||||
2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
|
||||
2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
|
||||
2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
|
||||
2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
|
||||
2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
|
||||
2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
|
||||
2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
|
||||
2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
|
||||
2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
|
||||
2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
|
||||
2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
|
||||
2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
|
||||
2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
|
||||
1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
|
||||
1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
|
||||
1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
|
||||
1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
|
||||
1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
|
||||
1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
|
||||
1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
|
||||
1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
|
||||
1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
|
||||
1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
|
||||
1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
|
||||
1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
|
||||
1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
|
||||
1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
|
||||
1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
|
||||
1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
|
||||
1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
|
||||
1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
|
||||
1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
|
||||
1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
|
||||
1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
|
||||
1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
|
||||
1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
|
||||
1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
|
||||
1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
|
||||
1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
|
||||
1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
|
||||
1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
|
||||
1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
|
||||
1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
|
||||
1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
|
||||
1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
|
||||
1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
|
||||
1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
|
||||
1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
|
||||
0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
|
||||
0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
|
||||
0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
|
||||
0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
|
||||
0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
|
||||
0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
|
||||
0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
|
||||
0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
|
||||
0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
|
||||
0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
|
||||
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
|
||||
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
|
||||
0.000000000000000000];
|
||||
pub static ZIG_NORM_F: [f64; 257] =
|
||||
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
|
||||
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
|
||||
0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
|
||||
0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
|
||||
0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
|
||||
0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
|
||||
0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
|
||||
0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
|
||||
0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
|
||||
0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
|
||||
0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
|
||||
0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
|
||||
0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
|
||||
0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
|
||||
0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
|
||||
0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
|
||||
0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
|
||||
0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
|
||||
0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
|
||||
0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
|
||||
0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
|
||||
0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
|
||||
0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
|
||||
0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
|
||||
0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
|
||||
0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
|
||||
0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
|
||||
0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
|
||||
0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
|
||||
0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
|
||||
0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
|
||||
0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
|
||||
0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
|
||||
0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
|
||||
0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
|
||||
0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
|
||||
0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
|
||||
0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
|
||||
0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
|
||||
0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
|
||||
0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
|
||||
0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
|
||||
0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
|
||||
0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
|
||||
0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
|
||||
0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
|
||||
0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
|
||||
0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
|
||||
0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
|
||||
0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
|
||||
0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
|
||||
0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
|
||||
0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
|
||||
0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
|
||||
0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
|
||||
0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
|
||||
0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
|
||||
0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
|
||||
0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
|
||||
0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
|
||||
0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
|
||||
0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
|
||||
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
|
||||
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
|
||||
1.000000000000000000];
|
||||
pub const ZIG_EXP_R: f64 = 7.697117470131050077;
|
||||
pub static ZIG_EXP_X: [f64; 257] =
|
||||
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
|
||||
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
|
||||
5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
|
||||
4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
|
||||
4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
|
||||
4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
|
||||
3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
|
||||
3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
|
||||
3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
|
||||
3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
|
||||
3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
|
||||
3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
|
||||
3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
|
||||
2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
|
||||
2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
|
||||
2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
|
||||
2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
|
||||
2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
|
||||
2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
|
||||
2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
|
||||
2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
|
||||
2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
|
||||
2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
|
||||
2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
|
||||
2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
|
||||
2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
|
||||
1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
|
||||
1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
|
||||
1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
|
||||
1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
|
||||
1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
|
||||
1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
|
||||
1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
|
||||
1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
|
||||
1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
|
||||
1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
|
||||
1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
|
||||
1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
|
||||
1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
|
||||
1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
|
||||
1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
|
||||
1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
|
||||
1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
|
||||
1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
|
||||
1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
|
||||
1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
|
||||
1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
|
||||
0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
|
||||
0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
|
||||
0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
|
||||
0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
|
||||
0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
|
||||
0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
|
||||
0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
|
||||
0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
|
||||
0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
|
||||
0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
|
||||
0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
|
||||
0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
|
||||
0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
|
||||
0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
|
||||
0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
|
||||
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
|
||||
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
|
||||
0.000000000000000000];
|
||||
pub static ZIG_EXP_F: [f64; 257] =
|
||||
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
|
||||
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
|
||||
0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
|
||||
0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
|
||||
0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
|
||||
0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
|
||||
0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
|
||||
0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
|
||||
0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
|
||||
0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
|
||||
0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
|
||||
0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
|
||||
0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
|
||||
0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
|
||||
0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
|
||||
0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
|
||||
0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
|
||||
0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
|
||||
0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
|
||||
0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
|
||||
0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
|
||||
0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
|
||||
0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
|
||||
0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
|
||||
0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
|
||||
0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
|
||||
0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
|
||||
0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
|
||||
0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
|
||||
0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
|
||||
0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
|
||||
0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
|
||||
0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
|
||||
0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
|
||||
0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
|
||||
0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
|
||||
0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
|
||||
0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
|
||||
0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
|
||||
0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
|
||||
0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
|
||||
0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
|
||||
0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
|
||||
0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
|
||||
0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
|
||||
0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
|
||||
0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
|
||||
0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
|
||||
0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
|
||||
0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
|
||||
0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
|
||||
0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
|
||||
0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
|
||||
0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
|
||||
0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
|
||||
0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
|
||||
0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
|
||||
0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
|
||||
0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
|
||||
0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
|
||||
0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
|
||||
0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
|
||||
0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
|
||||
0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
|
||||
1.000000000000000000];
|
|
@ -1,754 +0,0 @@
|
|||
// Copyright 2017 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.
|
||||
//
|
||||
// Based on jitterentropy-library, http://www.chronox.de/jent.html.
|
||||
// Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017.
|
||||
//
|
||||
// With permission from Stephan Mueller to relicense the Rust translation under
|
||||
// the MIT license.
|
||||
|
||||
//! Non-physical true random number generator based on timing jitter.
|
||||
|
||||
use Rng;
|
||||
|
||||
use core::{fmt, mem, ptr};
|
||||
#[cfg(feature="std")]
|
||||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
|
||||
const MEMORY_BLOCKS: usize = 64;
|
||||
const MEMORY_BLOCKSIZE: usize = 32;
|
||||
const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;
|
||||
|
||||
/// A true random number generator based on jitter in the CPU execution time,
|
||||
/// and jitter in memory access time.
|
||||
///
|
||||
/// This is a true random number generator, as opposed to pseudo-random
|
||||
/// generators. Random numbers generated by `JitterRng` can be seen as fresh
|
||||
/// entropy. A consequence is that is orders of magnitude slower than `OsRng`
|
||||
/// and PRNGs (about 10^3 .. 10^6 slower).
|
||||
///
|
||||
/// There are very few situations where using this RNG is appropriate. Only very
|
||||
/// few applications require true entropy. A normal PRNG can be statistically
|
||||
/// indistinguishable, and a cryptographic PRNG should also be as impossible to
|
||||
/// predict.
|
||||
///
|
||||
/// Use of `JitterRng` is recommended for initializing cryptographic PRNGs when
|
||||
/// `OsRng` is not available.
|
||||
///
|
||||
/// This implementation is based on
|
||||
/// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0.
|
||||
//
|
||||
// Note: the C implementation relies on being compiled without optimizations.
|
||||
// This implementation goes through lengths to make the compiler not optimise
|
||||
// out what is technically dead code, but that does influence timing jitter.
|
||||
pub struct JitterRng {
|
||||
data: u64, // Actual random number
|
||||
// Number of rounds to run the entropy collector per 64 bits
|
||||
rounds: u32,
|
||||
// Timer and previous time stamp, used by `measure_jitter`
|
||||
timer: fn() -> u64,
|
||||
prev_time: u64,
|
||||
// Deltas used for the stuck test
|
||||
last_delta: i64,
|
||||
last_delta2: i64,
|
||||
// Memory for the Memory Access noise source
|
||||
mem_prev_index: usize,
|
||||
mem: [u8; MEMORY_SIZE],
|
||||
// Make `next_u32` not waste 32 bits
|
||||
data_remaining: Option<u32>,
|
||||
}
|
||||
|
||||
// Custom Debug implementation that does not expose the internal state
|
||||
impl fmt::Debug for JitterRng {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "JitterRng {{}}")
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can occur when `test_timer` fails.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TimerError {
|
||||
/// No timer available.
|
||||
NoTimer,
|
||||
/// Timer too coarse to use as an entropy source.
|
||||
CoarseTimer,
|
||||
/// Timer is not monotonically increasing.
|
||||
NotMonotonic,
|
||||
/// Variations of deltas of time too small.
|
||||
TinyVariantions,
|
||||
/// Too many stuck results (indicating no added entropy).
|
||||
TooManyStuck,
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive,
|
||||
}
|
||||
|
||||
impl TimerError {
|
||||
fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
TimerError::NoTimer => "no timer available",
|
||||
TimerError::CoarseTimer => "coarse timer",
|
||||
TimerError::NotMonotonic => "timer not monotonic",
|
||||
TimerError::TinyVariantions => "time delta variations too small",
|
||||
TimerError::TooManyStuck => "too many stuck results",
|
||||
TimerError::__Nonexhaustive => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TimerError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="std")]
|
||||
impl ::std::error::Error for TimerError {
|
||||
fn description(&self) -> &str {
|
||||
self.description()
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise to zero; must be positive
|
||||
#[cfg(feature="std")]
|
||||
static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
impl JitterRng {
|
||||
/// Create a new `JitterRng`.
|
||||
/// Makes use of `std::time` for a timer.
|
||||
///
|
||||
/// During initialization CPU execution timing jitter is measured a few
|
||||
/// hundred times. If this does not pass basic quality tests, an error is
|
||||
/// returned. The test result is cached to make subsequent calls faster.
|
||||
#[cfg(feature="std")]
|
||||
pub fn new() -> Result<JitterRng, TimerError> {
|
||||
let mut ec = JitterRng::new_with_timer(platform::get_nstime);
|
||||
let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u32;
|
||||
if rounds == 0 {
|
||||
// No result yet: run test.
|
||||
// This allows the timer test to run multiple times; we don't care.
|
||||
rounds = ec.test_timer()?;
|
||||
JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed);
|
||||
}
|
||||
ec.set_rounds(rounds);
|
||||
Ok(ec)
|
||||
}
|
||||
|
||||
/// Create a new `JitterRng`.
|
||||
/// A custom timer can be supplied, making it possible to use `JitterRng` in
|
||||
/// `no_std` environments.
|
||||
///
|
||||
/// The timer must have nanosecond precision.
|
||||
///
|
||||
/// This method is more low-level than `new()`. It is the responsibility of
|
||||
/// the caller to run `test_timer` before using any numbers generated with
|
||||
/// `JitterRng`, and optionally call `set_rounds()`.
|
||||
pub fn new_with_timer(timer: fn() -> u64) -> JitterRng {
|
||||
let mut ec = JitterRng {
|
||||
data: 0,
|
||||
rounds: 64,
|
||||
timer: timer,
|
||||
prev_time: 0,
|
||||
last_delta: 0,
|
||||
last_delta2: 0,
|
||||
mem_prev_index: 0,
|
||||
mem: [0; MEMORY_SIZE],
|
||||
data_remaining: None,
|
||||
};
|
||||
|
||||
// Fill `data`, `prev_time`, `last_delta` and `last_delta2` with
|
||||
// non-zero values.
|
||||
ec.prev_time = timer();
|
||||
ec.gen_entropy();
|
||||
|
||||
// Do a single read from `self.mem` to make sure the Memory Access noise
|
||||
// source is not optimised out.
|
||||
// Note: this read is important, it effects optimisations for the entire
|
||||
// module!
|
||||
black_box(ec.mem[0]);
|
||||
|
||||
ec
|
||||
}
|
||||
|
||||
/// Configures how many rounds are used to generate each 64-bit value.
|
||||
/// This must be greater than zero, and has a big impact on performance
|
||||
/// and output quality.
|
||||
///
|
||||
/// `new_with_timer` conservatively uses 64 rounds, but often less rounds
|
||||
/// can be used. The `test_timer()` function returns the minimum number of
|
||||
/// rounds required for full strength (platform dependent), so one may use
|
||||
/// `rng.set_rounds(rng.test_timer()?);` or cache the value.
|
||||
pub fn set_rounds(&mut self, rounds: u32) {
|
||||
assert!(rounds > 0);
|
||||
self.rounds = rounds;
|
||||
}
|
||||
|
||||
// Calculate a random loop count used for the next round of an entropy
|
||||
// collection, based on bits from a fresh value from the timer.
|
||||
//
|
||||
// The timer is folded to produce a number that contains at most `n_bits`
|
||||
// bits.
|
||||
//
|
||||
// Note: A constant should be added to the resulting random loop count to
|
||||
// prevent loops that run 0 times.
|
||||
#[inline(never)]
|
||||
fn random_loop_cnt(&mut self, n_bits: u32) -> u32 {
|
||||
let mut rounds = 0;
|
||||
|
||||
let mut time = (self.timer)();
|
||||
// Mix with the current state of the random number balance the random
|
||||
// loop counter a bit more.
|
||||
time ^= self.data;
|
||||
|
||||
// We fold the time value as much as possible to ensure that as many
|
||||
// bits of the time stamp are included as possible.
|
||||
let folds = (64 + n_bits - 1) / n_bits;
|
||||
let mask = (1 << n_bits) - 1;
|
||||
for _ in 0..folds {
|
||||
rounds ^= time & mask;
|
||||
time = time >> n_bits;
|
||||
}
|
||||
|
||||
rounds as u32
|
||||
}
|
||||
|
||||
// CPU jitter noise source
|
||||
// Noise source based on the CPU execution time jitter
|
||||
//
|
||||
// This function injects the individual bits of the time value into the
|
||||
// entropy pool using an LFSR.
|
||||
//
|
||||
// The code is deliberately inefficient with respect to the bit shifting.
|
||||
// This function not only acts as folding operation, but this function's
|
||||
// execution is used to measure the CPU execution time jitter. Any change to
|
||||
// the loop in this function implies that careful retesting must be done.
|
||||
#[inline(never)]
|
||||
fn lfsr_time(&mut self, time: u64, var_rounds: bool) {
|
||||
fn lfsr(mut data: u64, time: u64) -> u64{
|
||||
for i in 1..65 {
|
||||
let mut tmp = time << (64 - i);
|
||||
tmp = tmp >> (64 - 1);
|
||||
|
||||
// Fibonacci LSFR with polynomial of
|
||||
// x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is
|
||||
// primitive according to
|
||||
// http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf
|
||||
// (the shift values are the polynomial values minus one
|
||||
// due to counting bits from 0 to 63). As the current
|
||||
// position is always the LSB, the polynomial only needs
|
||||
// to shift data in from the left without wrap.
|
||||
data ^= tmp;
|
||||
data ^= (data >> 63) & 1;
|
||||
data ^= (data >> 60) & 1;
|
||||
data ^= (data >> 55) & 1;
|
||||
data ^= (data >> 30) & 1;
|
||||
data ^= (data >> 27) & 1;
|
||||
data ^= (data >> 22) & 1;
|
||||
data = data.rotate_left(1);
|
||||
}
|
||||
data
|
||||
}
|
||||
|
||||
// Note: in the reference implementation only the last round effects
|
||||
// `self.data`, all the other results are ignored. To make sure the
|
||||
// other rounds are not optimised out, we first run all but the last
|
||||
// round on a throw-away value instead of the real `self.data`.
|
||||
let mut lfsr_loop_cnt = 0;
|
||||
if var_rounds { lfsr_loop_cnt = self.random_loop_cnt(4) };
|
||||
|
||||
let mut throw_away: u64 = 0;
|
||||
for _ in 0..lfsr_loop_cnt {
|
||||
throw_away = lfsr(throw_away, time);
|
||||
}
|
||||
black_box(throw_away);
|
||||
|
||||
self.data = lfsr(self.data, time);
|
||||
}
|
||||
|
||||
// Memory Access noise source
|
||||
// This is a noise source based on variations in memory access times
|
||||
//
|
||||
// This function performs memory accesses which will add to the timing
|
||||
// variations due to an unknown amount of CPU wait states that need to be
|
||||
// added when accessing memory. The memory size should be larger than the L1
|
||||
// caches as outlined in the documentation and the associated testing.
|
||||
//
|
||||
// The L1 cache has a very high bandwidth, albeit its access rate is usually
|
||||
// slower than accessing CPU registers. Therefore, L1 accesses only add
|
||||
// minimal variations as the CPU has hardly to wait. Starting with L2,
|
||||
// significant variations are added because L2 typically does not belong to
|
||||
// the CPU any more and therefore a wider range of CPU wait states is
|
||||
// necessary for accesses. L3 and real memory accesses have even a wider
|
||||
// range of wait states. However, to reliably access either L3 or memory,
|
||||
// the `self.mem` memory must be quite large which is usually not desirable.
|
||||
#[inline(never)]
|
||||
fn memaccess(&mut self, var_rounds: bool) {
|
||||
let mut acc_loop_cnt = 128;
|
||||
if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) };
|
||||
|
||||
let mut index = self.mem_prev_index;
|
||||
for _ in 0..acc_loop_cnt {
|
||||
// Addition of memblocksize - 1 to index with wrap around logic to
|
||||
// ensure that every memory location is hit evenly.
|
||||
// The modulus also allows the compiler to remove the indexing
|
||||
// bounds check.
|
||||
index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE;
|
||||
|
||||
// memory access: just add 1 to one byte
|
||||
// memory access implies read from and write to memory location
|
||||
let tmp = self.mem[index];
|
||||
self.mem[index] = tmp.wrapping_add(1);
|
||||
}
|
||||
self.mem_prev_index = index;
|
||||
}
|
||||
|
||||
|
||||
// Stuck test by checking the:
|
||||
// - 1st derivation of the jitter measurement (time delta)
|
||||
// - 2nd derivation of the jitter measurement (delta of time deltas)
|
||||
// - 3rd derivation of the jitter measurement (delta of delta of time
|
||||
// deltas)
|
||||
//
|
||||
// All values must always be non-zero.
|
||||
// This test is a heuristic to see whether the last measurement holds
|
||||
// entropy.
|
||||
fn stuck(&mut self, current_delta: i64) -> bool {
|
||||
let delta2 = self.last_delta - current_delta;
|
||||
let delta3 = delta2 - self.last_delta2;
|
||||
|
||||
self.last_delta = current_delta;
|
||||
self.last_delta2 = delta2;
|
||||
|
||||
current_delta == 0 || delta2 == 0 || delta3 == 0
|
||||
}
|
||||
|
||||
// This is the heart of the entropy generation: calculate time deltas and
|
||||
// use the CPU jitter in the time deltas. The jitter is injected into the
|
||||
// entropy pool.
|
||||
//
|
||||
// Ensure that `self.prev_time` is primed before using the output of this
|
||||
// function. This can be done by calling this function and not using its
|
||||
// result.
|
||||
fn measure_jitter(&mut self) -> Option<()> {
|
||||
// Invoke one noise source before time measurement to add variations
|
||||
self.memaccess(true);
|
||||
|
||||
// Get time stamp and calculate time delta to previous
|
||||
// invocation to measure the timing variations
|
||||
let time = (self.timer)();
|
||||
// Note: wrapping_sub combined with a cast to `i64` generates a correct
|
||||
// delta, even in the unlikely case this is a timer that is not strictly
|
||||
// monotonic.
|
||||
let current_delta = time.wrapping_sub(self.prev_time) as i64;
|
||||
self.prev_time = time;
|
||||
|
||||
// Call the next noise source which also injects the data
|
||||
self.lfsr_time(current_delta as u64, true);
|
||||
|
||||
// Check whether we have a stuck measurement (i.e. does the last
|
||||
// measurement holds entropy?).
|
||||
if self.stuck(current_delta) { return None };
|
||||
|
||||
// Rotate the data buffer by a prime number (any odd number would
|
||||
// do) to ensure that every bit position of the input time stamp
|
||||
// has an even chance of being merged with a bit position in the
|
||||
// entropy pool. We do not use one here as the adjacent bits in
|
||||
// successive time deltas may have some form of dependency. The
|
||||
// chosen value of 7 implies that the low 7 bits of the next
|
||||
// time delta value is concatenated with the current time delta.
|
||||
self.data = self.data.rotate_left(7);
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
// Shuffle the pool a bit by mixing some value with a bijective function
|
||||
// (XOR) into the pool.
|
||||
//
|
||||
// The function generates a mixer value that depends on the bits set and
|
||||
// the location of the set bits in the random number generated by the
|
||||
// entropy source. Therefore, based on the generated random number, this
|
||||
// mixer value can have 2^64 different values. That mixer value is
|
||||
// initialized with the first two SHA-1 constants. After obtaining the
|
||||
// mixer value, it is XORed into the random number.
|
||||
//
|
||||
// The mixer value is not assumed to contain any entropy. But due to the
|
||||
// XOR operation, it can also not destroy any entropy present in the
|
||||
// entropy pool.
|
||||
#[inline(never)]
|
||||
fn stir_pool(&mut self) {
|
||||
// This constant is derived from the first two 32 bit initialization
|
||||
// vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1
|
||||
// The order does not really matter as we do not rely on the specific
|
||||
// numbers. We just pick the SHA-1 constants as they have a good mix of
|
||||
// bit set and unset.
|
||||
const CONSTANT: u64 = 0x67452301efcdab89;
|
||||
|
||||
// The start value of the mixer variable is derived from the third
|
||||
// and fourth 32 bit initialization vector of SHA-1 as defined in
|
||||
// FIPS 180-4 section 5.3.1
|
||||
let mut mixer = 0x98badcfe10325476;
|
||||
|
||||
// This is a constant time function to prevent leaking timing
|
||||
// information about the random number.
|
||||
// The normal code is:
|
||||
// ```
|
||||
// for i in 0..64 {
|
||||
// if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; }
|
||||
// }
|
||||
// ```
|
||||
// This is a bit fragile, as LLVM really wants to use branches here, and
|
||||
// we rely on it to not recognise the opportunity.
|
||||
for i in 0..64 {
|
||||
let apply = (self.data >> i) & 1;
|
||||
let mask = !apply.wrapping_sub(1);
|
||||
mixer ^= CONSTANT & mask;
|
||||
mixer = mixer.rotate_left(1);
|
||||
}
|
||||
|
||||
self.data ^= mixer;
|
||||
}
|
||||
|
||||
fn gen_entropy(&mut self) -> u64 {
|
||||
// Prime `self.prev_time`, and run the noice sources to make sure the
|
||||
// first loop round collects the expected entropy.
|
||||
let _ = self.measure_jitter();
|
||||
|
||||
for _ in 0..self.rounds {
|
||||
// If a stuck measurement is received, repeat measurement
|
||||
// Note: we do not guard against an infinite loop, that would mean
|
||||
// the timer suddenly became broken.
|
||||
while self.measure_jitter().is_none() {}
|
||||
}
|
||||
|
||||
self.stir_pool();
|
||||
self.data
|
||||
}
|
||||
|
||||
/// Basic quality tests on the timer, by measuring CPU timing jitter a few
|
||||
/// hundred times.
|
||||
///
|
||||
/// If succesful, this will return the estimated number of rounds necessary
|
||||
/// to collect 64 bits of entropy. Otherwise a `TimerError` with the cause
|
||||
/// of the failure will be returned.
|
||||
pub fn test_timer(&mut self) -> Result<u32, TimerError> {
|
||||
// We could add a check for system capabilities such as `clock_getres`
|
||||
// or check for `CONFIG_X86_TSC`, but it does not make much sense as the
|
||||
// following sanity checks verify that we have a high-resolution timer.
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
return Err(TimerError::NoTimer);
|
||||
|
||||
let mut delta_sum = 0;
|
||||
let mut old_delta = 0;
|
||||
|
||||
let mut time_backwards = 0;
|
||||
let mut count_mod = 0;
|
||||
let mut count_stuck = 0;
|
||||
|
||||
// TESTLOOPCOUNT needs some loops to identify edge systems.
|
||||
// 100 is definitely too little.
|
||||
const TESTLOOPCOUNT: u64 = 300;
|
||||
const CLEARCACHE: u64 = 100;
|
||||
|
||||
for i in 0..(CLEARCACHE + TESTLOOPCOUNT) {
|
||||
// Measure time delta of core entropy collection logic
|
||||
let time = (self.timer)();
|
||||
self.memaccess(true);
|
||||
self.lfsr_time(time, true);
|
||||
let time2 = (self.timer)();
|
||||
|
||||
// Test whether timer works
|
||||
if time == 0 || time2 == 0 {
|
||||
return Err(TimerError::NoTimer);
|
||||
}
|
||||
let delta = time2.wrapping_sub(time) as i64;
|
||||
|
||||
// Test whether timer is fine grained enough to provide delta even
|
||||
// when called shortly after each other -- this implies that we also
|
||||
// have a high resolution timer
|
||||
if delta == 0 {
|
||||
return Err(TimerError::CoarseTimer);
|
||||
}
|
||||
|
||||
// Up to here we did not modify any variable that will be
|
||||
// evaluated later, but we already performed some work. Thus we
|
||||
// already have had an impact on the caches, branch prediction,
|
||||
// etc. with the goal to clear it to get the worst case
|
||||
// measurements.
|
||||
if i < CLEARCACHE { continue; }
|
||||
|
||||
if self.stuck(delta) { count_stuck += 1; }
|
||||
|
||||
// Test whether we have an increasing timer.
|
||||
if !(time2 > time) { time_backwards += 1; }
|
||||
|
||||
// Count the number of times the counter increases in steps of 100ns
|
||||
// or greater.
|
||||
if (delta % 100) == 0 { count_mod += 1; }
|
||||
|
||||
// Ensure that we have a varying delta timer which is necessary for
|
||||
// the calculation of entropy -- perform this check only after the
|
||||
// first loop is executed as we need to prime the old_delta value
|
||||
delta_sum += (delta - old_delta).abs() as u64;
|
||||
old_delta = delta;
|
||||
}
|
||||
|
||||
// We allow the time to run backwards for up to three times.
|
||||
// This can happen if the clock is being adjusted by NTP operations.
|
||||
// If such an operation just happens to interfere with our test, it
|
||||
// should not fail. The value of 3 should cover the NTP case being
|
||||
// performed during our test run.
|
||||
if time_backwards > 3 {
|
||||
return Err(TimerError::NotMonotonic);
|
||||
}
|
||||
|
||||
// Test that the available amount of entropy per round does not get to
|
||||
// low. We expect 1 bit of entropy per round as a reasonable minimum
|
||||
// (although less is possible, it means the collector loop has to run
|
||||
// much more often).
|
||||
// `assert!(delta_average >= log2(1))`
|
||||
// `assert!(delta_sum / TESTLOOPCOUNT >= 1)`
|
||||
// `assert!(delta_sum >= TESTLOOPCOUNT)`
|
||||
if delta_sum < TESTLOOPCOUNT {
|
||||
return Err(TimerError::TinyVariantions);
|
||||
}
|
||||
|
||||
// Ensure that we have variations in the time stamp below 100 for at
|
||||
// least 10% of all checks -- on some platforms, the counter increments
|
||||
// in multiples of 100, but not always
|
||||
if count_mod > (TESTLOOPCOUNT * 9 / 10) {
|
||||
return Err(TimerError::CoarseTimer);
|
||||
}
|
||||
|
||||
// If we have more than 90% stuck results, then this Jitter RNG is
|
||||
// likely to not work well.
|
||||
if count_stuck > (TESTLOOPCOUNT * 9 / 10) {
|
||||
return Err(TimerError::TooManyStuck);
|
||||
}
|
||||
|
||||
// Estimate the number of `measure_jitter` rounds necessary for 64 bits
|
||||
// of entropy.
|
||||
//
|
||||
// We don't try very hard to come up with a good estimate of the
|
||||
// available bits of entropy per round here for two reasons:
|
||||
// 1. Simple estimates of the available bits (like Shannon entropy) are
|
||||
// too optimistic.
|
||||
// 2) Unless we want to waste a lot of time during intialization, there
|
||||
// only a small number of samples are available.
|
||||
//
|
||||
// Therefore we use a very simple and conservative estimate:
|
||||
// `let bits_of_entropy = log2(delta_average) / 2`.
|
||||
//
|
||||
// The number of rounds `measure_jitter` should run to collect 64 bits
|
||||
// of entropy is `64 / bits_of_entropy`.
|
||||
//
|
||||
// To have smaller rounding errors, intermediate values are multiplied
|
||||
// by `FACTOR`. To compensate for `log2` and division rounding down,
|
||||
// add 1.
|
||||
let delta_average = delta_sum / TESTLOOPCOUNT;
|
||||
// println!("delta_average: {}", delta_average);
|
||||
|
||||
const FACTOR: u32 = 3;
|
||||
fn log2(x: u64) -> u32 { 64 - x.leading_zeros() }
|
||||
|
||||
// pow(δ, FACTOR) must be representable; if you have overflow reduce FACTOR
|
||||
Ok(64 * 2 * FACTOR / (log2(delta_average.pow(FACTOR)) + 1))
|
||||
}
|
||||
|
||||
/// Statistical test: return the timer delta of one normal run of the
|
||||
/// `JitterEntropy` entropy collector.
|
||||
///
|
||||
/// Setting `var_rounds` to `true` will execute the memory access and the
|
||||
/// CPU jitter noice sources a variable amount of times (just like a real
|
||||
/// `JitterEntropy` round).
|
||||
///
|
||||
/// Setting `var_rounds` to `false` will execute the noice sources the
|
||||
/// minimal number of times. This can be used to measure the minimum amount
|
||||
/// of entropy one round of entropy collector can collect in the worst case.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Use `timer_stats` to run the [NIST SP 800-90B Entropy Estimation Suite]
|
||||
/// (https://github.com/usnistgov/SP800-90B_EntropyAssessment).
|
||||
///
|
||||
/// This is the recommended way to test the quality of `JitterRng`. It
|
||||
/// should be run before using the RNG on untested hardware, after changes
|
||||
/// that could effect how the code is optimised, and after major compiler
|
||||
/// compiler changes, like a new LLVM version.
|
||||
///
|
||||
/// First generate two files `jitter_rng_var.bin` and `jitter_rng_var.min`.
|
||||
///
|
||||
/// Execute `python noniid_main.py -v jitter_rng_var.bin 8`, and validate it
|
||||
/// with `restart.py -v jitter_rng_var.bin 8 <min-entropy>`.
|
||||
/// This number is the expected amount of entropy that is at least available
|
||||
/// for each round of the entropy collector. This number should be greater
|
||||
/// than the amount estimated with `64 / test_timer()`.
|
||||
///
|
||||
/// Execute `python noniid_main.py -v -u 4 jitter_rng_var.bin 4`, and
|
||||
/// validate it with `restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>`.
|
||||
/// This number is the expected amount of entropy that is available in the
|
||||
/// last 4 bits of the timer delta after running noice sources. Note that
|
||||
/// a value of 3.70 is the minimum estimated entropy for true randomness.
|
||||
///
|
||||
/// Execute `python noniid_main.py -v -u 4 jitter_rng_var.bin 4`, and
|
||||
/// validate it with `restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>`.
|
||||
/// This number is the expected amount of entropy that is available to the
|
||||
/// entropy collecter if both noice sources only run their minimal number of
|
||||
/// times. This measures the absolute worst-case, and gives a lower bound
|
||||
/// for the available entropy.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use rand::JitterRng;
|
||||
///
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fs::File;
|
||||
/// # use std::io::Write;
|
||||
/// #
|
||||
/// # fn try_main() -> Result<(), Box<Error>> {
|
||||
/// fn get_nstime() -> u64 {
|
||||
/// use std::time::{SystemTime, UNIX_EPOCH};
|
||||
///
|
||||
/// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
/// // The correct way to calculate the current time is
|
||||
/// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
|
||||
/// // But this is faster, and the difference in terms of entropy is
|
||||
/// // negligible (log2(10^9) == 29.9).
|
||||
/// dur.as_secs() << 30 | dur.subsec_nanos() as u64
|
||||
/// }
|
||||
///
|
||||
/// // Do not initialize with `JitterRng::new`, but with `new_with_timer`.
|
||||
/// // 'new' always runst `test_timer`, and can therefore fail to
|
||||
/// // initialize. We want to be able to get the statistics even when the
|
||||
/// // timer test fails.
|
||||
/// let mut rng = JitterRng::new_with_timer(get_nstime);
|
||||
///
|
||||
/// // 1_000_000 results are required for the NIST SP 800-90B Entropy
|
||||
/// // Estimation Suite
|
||||
/// // FIXME: this number is smaller here, otherwise the Doc-test is too slow
|
||||
/// const ROUNDS: usize = 10_000;
|
||||
/// let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS);
|
||||
/// let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS);
|
||||
///
|
||||
/// for _ in 0..ROUNDS {
|
||||
/// deltas_variable.push(rng.timer_stats(true) as u8);
|
||||
/// deltas_minimal.push(rng.timer_stats(false) as u8);
|
||||
/// }
|
||||
///
|
||||
/// // Write out after the statistics collection loop, to not disturb the
|
||||
/// // test results.
|
||||
/// File::create("jitter_rng_var.bin")?.write(&deltas_variable)?;
|
||||
/// File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?;
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # try_main().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature="std")]
|
||||
pub fn timer_stats(&mut self, var_rounds: bool) -> i64 {
|
||||
let time = platform::get_nstime();
|
||||
self.memaccess(var_rounds);
|
||||
self.lfsr_time(time, var_rounds);
|
||||
let time2 = platform::get_nstime();
|
||||
time2.wrapping_sub(time) as i64
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="std")]
|
||||
mod platform {
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows", all(target_arch = "wasm32", not(target_os = "emscripten")))))]
|
||||
pub fn get_nstime() -> u64 {
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
// The correct way to calculate the current time is
|
||||
// `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
|
||||
// But this is faster, and the difference in terms of entropy is negligible
|
||||
// (log2(10^9) == 29.9).
|
||||
dur.as_secs() << 30 | dur.subsec_nanos() as u64
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
pub fn get_nstime() -> u64 {
|
||||
extern crate libc;
|
||||
// On Mac OS and iOS std::time::SystemTime only has 1000ns resolution.
|
||||
// We use `mach_absolute_time` instead. This provides a CPU dependent unit,
|
||||
// to get real nanoseconds the result should by multiplied by numer/denom
|
||||
// from `mach_timebase_info`.
|
||||
// But we are not interested in the exact nanoseconds, just entropy. So we
|
||||
// use the raw result.
|
||||
unsafe { libc::mach_absolute_time() }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn get_nstime() -> u64 {
|
||||
extern crate winapi;
|
||||
unsafe {
|
||||
let mut t = super::mem::zeroed();
|
||||
winapi::um::profileapi::QueryPerformanceCounter(&mut t);
|
||||
*t.QuadPart() as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
pub fn get_nstime() -> u64 {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
// A function that is opaque to the optimizer to assist in avoiding dead-code
|
||||
// elimination. Taken from `bencher`.
|
||||
fn black_box<T>(dummy: T) -> T {
|
||||
unsafe {
|
||||
let ret = ptr::read_volatile(&dummy);
|
||||
mem::forget(dummy);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for JitterRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
// We want to use both parts of the generated entropy
|
||||
if let Some(high) = self.data_remaining.take() {
|
||||
high
|
||||
} else {
|
||||
let data = self.next_u64();
|
||||
self.data_remaining = Some((data >> 32) as u32);
|
||||
data as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.gen_entropy()
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
let mut left = dest;
|
||||
while left.len() >= 8 {
|
||||
let (l, r) = {left}.split_at_mut(8);
|
||||
left = r;
|
||||
let chunk: [u8; 8] = unsafe {
|
||||
mem::transmute(self.next_u64().to_le())
|
||||
};
|
||||
l.copy_from_slice(&chunk);
|
||||
}
|
||||
let n = left.len();
|
||||
if n > 0 {
|
||||
let chunk: [u8; 8] = unsafe {
|
||||
mem::transmute(self.next_u64().to_le())
|
||||
};
|
||||
left.copy_from_slice(&chunk[..n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There are no tests included because (1) this is an "external" RNG, so output
|
||||
// is not reproducible and (2) `test_timer` *will* fail on some platforms.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,656 +0,0 @@
|
|||
// Copyright 2013-2015 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.
|
||||
|
||||
//! Interfaces to the operating system provided random number
|
||||
//! generators.
|
||||
|
||||
use std::{io, fmt};
|
||||
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
use std::mem;
|
||||
|
||||
use Rng;
|
||||
|
||||
/// A random number generator that retrieves randomness straight from
|
||||
/// the operating system. Platform sources:
|
||||
///
|
||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
||||
/// `/dev/urandom`, or from `getrandom(2)` system call if available.
|
||||
/// - OpenBSD: calls `getentropy(2)`
|
||||
/// - FreeBSD: uses the `kern.arandom` `sysctl(2)` mib
|
||||
/// - Windows: calls `RtlGenRandom`, exported from `advapi32.dll` as
|
||||
/// `SystemFunction036`.
|
||||
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
|
||||
/// - PNaCl: calls into the `nacl-irt-random-0.1` IRT interface.
|
||||
///
|
||||
/// This usually does not block. On some systems (e.g. FreeBSD, OpenBSD,
|
||||
/// Max OS X, and modern Linux) this may block very early in the init
|
||||
/// process, if the CSPRNG has not been seeded yet.[1]
|
||||
///
|
||||
/// [1] See <https://www.python.org/dev/peps/pep-0524/> for a more
|
||||
/// in-depth discussion.
|
||||
pub struct OsRng(imp::OsRng);
|
||||
|
||||
impl OsRng {
|
||||
/// Create a new `OsRng`.
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
imp::OsRng::new().map(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 { self.0.next_u32() }
|
||||
fn next_u64(&mut self) -> u64 { self.0.next_u64() }
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) { self.0.fill_bytes(v) }
|
||||
}
|
||||
|
||||
impl fmt::Debug for OsRng {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "OsRng {{}}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
fill_buf(&mut buf);
|
||||
unsafe { mem::transmute::<[u8; 4], u32>(buf) }
|
||||
}
|
||||
|
||||
#[cfg(not(target_env = "sgx"))]
|
||||
fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 {
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
fill_buf(&mut buf);
|
||||
unsafe { mem::transmute::<[u8; 8], u64>(buf) }
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "ios"),
|
||||
not(target_os = "nacl"),
|
||||
not(target_os = "freebsd"),
|
||||
not(target_os = "fuchsia"),
|
||||
not(target_os = "openbsd"),
|
||||
not(target_os = "redox")))]
|
||||
mod imp {
|
||||
extern crate libc;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
use self::OsRngInner::*;
|
||||
|
||||
use std::io;
|
||||
use std::fs::File;
|
||||
use Rng;
|
||||
use read::ReadRng;
|
||||
|
||||
#[cfg(all(target_os = "linux",
|
||||
any(target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc")))]
|
||||
fn getrandom(buf: &mut [u8]) -> libc::c_long {
|
||||
extern "C" {
|
||||
fn syscall(number: libc::c_long, ...) -> libc::c_long;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const NR_GETRANDOM: libc::c_long = 318;
|
||||
#[cfg(target_arch = "x86")]
|
||||
const NR_GETRANDOM: libc::c_long = 355;
|
||||
#[cfg(target_arch = "arm")]
|
||||
const NR_GETRANDOM: libc::c_long = 384;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
const NR_GETRANDOM: libc::c_long = 278;
|
||||
#[cfg(target_arch = "powerpc")]
|
||||
const NR_GETRANDOM: libc::c_long = 359;
|
||||
|
||||
unsafe {
|
||||
syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "linux",
|
||||
any(target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc"))))]
|
||||
fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
|
||||
|
||||
fn getrandom_fill_bytes(v: &mut [u8]) {
|
||||
let mut read = 0;
|
||||
let len = v.len();
|
||||
while read < len {
|
||||
let result = getrandom(&mut v[read..]);
|
||||
if result == -1 {
|
||||
let err = io::Error::last_os_error();
|
||||
if err.kind() == io::ErrorKind::Interrupted {
|
||||
continue
|
||||
} else {
|
||||
panic!("unexpected getrandom error: {}", err);
|
||||
}
|
||||
} else {
|
||||
read += result as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux",
|
||||
any(target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc")))]
|
||||
fn is_getrandom_available() -> bool {
|
||||
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
static CHECKER: Once = ONCE_INIT;
|
||||
static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
CHECKER.call_once(|| {
|
||||
let mut buf: [u8; 0] = [];
|
||||
let result = getrandom(&mut buf);
|
||||
let available = if result == -1 {
|
||||
let err = io::Error::last_os_error().raw_os_error();
|
||||
err != Some(libc::ENOSYS)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
AVAILABLE.store(available, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
AVAILABLE.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_os = "linux",
|
||||
any(target_arch = "x86_64",
|
||||
target_arch = "x86",
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc"))))]
|
||||
fn is_getrandom_available() -> bool { false }
|
||||
|
||||
pub struct OsRng {
|
||||
inner: OsRngInner,
|
||||
}
|
||||
|
||||
enum OsRngInner {
|
||||
OsGetrandomRng,
|
||||
OsReadRng(ReadRng<File>),
|
||||
}
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
if is_getrandom_available() {
|
||||
return Ok(OsRng { inner: OsGetrandomRng });
|
||||
}
|
||||
|
||||
let reader = try!(File::open("/dev/urandom"));
|
||||
let reader_rng = ReadRng::new(reader);
|
||||
|
||||
Ok(OsRng { inner: OsReadRng(reader_rng) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
match self.inner {
|
||||
OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
|
||||
OsReadRng(ref mut rng) => rng.next_u32(),
|
||||
}
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
match self.inner {
|
||||
OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
|
||||
OsReadRng(ref mut rng) => rng.next_u64(),
|
||||
}
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
match self.inner {
|
||||
OsGetrandomRng => getrandom_fill_bytes(v),
|
||||
OsReadRng(ref mut rng) => rng.fill_bytes(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
mod imp {
|
||||
extern crate libc;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
|
||||
use std::io;
|
||||
use Rng;
|
||||
use self::libc::{c_int, size_t};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng;
|
||||
|
||||
enum SecRandom {}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
|
||||
|
||||
#[link(name = "Security", kind = "framework")]
|
||||
extern {
|
||||
fn SecRandomCopyBytes(rnd: *const SecRandom,
|
||||
count: size_t, bytes: *mut u8) -> c_int;
|
||||
}
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
Ok(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
next_u32(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
next_u64(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
let ret = unsafe {
|
||||
SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
|
||||
};
|
||||
if ret == -1 {
|
||||
panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod imp {
|
||||
extern crate libc;
|
||||
|
||||
use std::{io, ptr};
|
||||
use Rng;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng;
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
Ok(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
next_u32(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
next_u64(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
let mib = [libc::CTL_KERN, libc::KERN_ARND];
|
||||
// kern.arandom permits a maximum buffer size of 256 bytes
|
||||
for s in v.chunks_mut(256) {
|
||||
let mut s_len = s.len();
|
||||
let ret = unsafe {
|
||||
libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
|
||||
s.as_mut_ptr() as *mut _, &mut s_len,
|
||||
ptr::null(), 0)
|
||||
};
|
||||
if ret == -1 || s_len != s.len() {
|
||||
panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
|
||||
ret, s.len(), s_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
mod imp {
|
||||
extern crate libc;
|
||||
|
||||
use std::io;
|
||||
use Rng;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng;
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
Ok(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
next_u32(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
next_u64(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
// getentropy(2) permits a maximum buffer size of 256 bytes
|
||||
for s in v.chunks_mut(256) {
|
||||
let ret = unsafe {
|
||||
libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
|
||||
};
|
||||
if ret == -1 {
|
||||
let err = io::Error::last_os_error();
|
||||
panic!("getentropy failed: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
mod imp {
|
||||
use std::io;
|
||||
use std::fs::File;
|
||||
use Rng;
|
||||
use read::ReadRng;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng {
|
||||
inner: ReadRng<File>,
|
||||
}
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
let reader = try!(File::open("rand:"));
|
||||
let reader_rng = ReadRng::new(reader);
|
||||
|
||||
Ok(OsRng { inner: reader_rng })
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.inner.next_u32()
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.inner.next_u64()
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
self.inner.fill_bytes(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
mod imp {
|
||||
extern crate fuchsia_cprng;
|
||||
|
||||
use std::io;
|
||||
use Rng;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng;
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
Ok(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
next_u32(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
next_u64(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
fuchsia_cprng::cprng_draw(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
extern crate winapi;
|
||||
|
||||
use std::io;
|
||||
use Rng;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
|
||||
use self::winapi::shared::minwindef::ULONG;
|
||||
use self::winapi::um::ntsecapi::RtlGenRandom;
|
||||
use self::winapi::um::winnt::PVOID;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng;
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
Ok(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
next_u32(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
next_u64(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
// RtlGenRandom takes an ULONG (u32) for the length so we need to
|
||||
// split up the buffer.
|
||||
for slice in v.chunks_mut(<ULONG>::max_value() as usize) {
|
||||
let ret = unsafe {
|
||||
RtlGenRandom(slice.as_mut_ptr() as PVOID, slice.len() as ULONG)
|
||||
};
|
||||
if ret == 0 {
|
||||
panic!("couldn't generate random bytes: {}",
|
||||
io::Error::last_os_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nacl")]
|
||||
mod imp {
|
||||
extern crate libc;
|
||||
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use Rng;
|
||||
|
||||
use super::{next_u32, next_u64};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng(extern fn(dest: *mut libc::c_void,
|
||||
bytes: libc::size_t,
|
||||
read: *mut libc::size_t) -> libc::c_int);
|
||||
|
||||
extern {
|
||||
fn nacl_interface_query(name: *const libc::c_char,
|
||||
table: *mut libc::c_void,
|
||||
table_size: libc::size_t) -> libc::size_t;
|
||||
}
|
||||
|
||||
const INTERFACE: &'static [u8] = b"nacl-irt-random-0.1\0";
|
||||
|
||||
#[repr(C)]
|
||||
struct NaClIRTRandom {
|
||||
get_random_bytes: Option<extern fn(dest: *mut libc::c_void,
|
||||
bytes: libc::size_t,
|
||||
read: *mut libc::size_t) -> libc::c_int>,
|
||||
}
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
let mut iface = NaClIRTRandom {
|
||||
get_random_bytes: None,
|
||||
};
|
||||
let result = unsafe {
|
||||
nacl_interface_query(INTERFACE.as_ptr() as *const _,
|
||||
mem::transmute(&mut iface),
|
||||
mem::size_of::<NaClIRTRandom>() as libc::size_t)
|
||||
};
|
||||
if result != 0 {
|
||||
assert!(iface.get_random_bytes.is_some());
|
||||
let result = OsRng(iface.get_random_bytes.take().unwrap());
|
||||
Ok(result)
|
||||
} else {
|
||||
let error = io::ErrorKind::NotFound;
|
||||
let error = io::Error::new(error, "IRT random interface missing");
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
next_u32(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
next_u64(&mut |v| self.fill_bytes(v))
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
let mut read = 0;
|
||||
loop {
|
||||
let mut r: libc::size_t = 0;
|
||||
let len = v.len();
|
||||
let error = (self.0)(v[read..].as_mut_ptr() as *mut _,
|
||||
(len - read) as libc::size_t,
|
||||
&mut r as *mut _);
|
||||
assert!(error == 0, "`get_random_bytes` failed!");
|
||||
read += r as usize;
|
||||
|
||||
if read >= v.len() { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
|
||||
mod imp {
|
||||
use std::io;
|
||||
use Rng;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsRng;
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for OsRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
panic!("Not supported")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_env = "sgx")]
|
||||
mod imp {
|
||||
use rdrand::RdRand;
|
||||
use std::io;
|
||||
use rand_core::RngCore;
|
||||
|
||||
pub struct OsRng{
|
||||
gen: RdRand
|
||||
}
|
||||
|
||||
impl OsRng {
|
||||
pub fn new() -> io::Result<OsRng> {
|
||||
match RdRand::new() {
|
||||
Ok(rng) => Ok(OsRng { gen: rng }),
|
||||
Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next_u32(&mut self) -> u32 {
|
||||
match self.gen.try_next_u32() {
|
||||
Some(n) => n,
|
||||
None => panic!("Non-recoverable hardware failure has occured")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next_u64(&mut self) -> u64 {
|
||||
match self.gen.try_next_u64() {
|
||||
Some(n) => n,
|
||||
None => panic!("Non-recoverable hardware failure has occured")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
match self.gen.try_fill_bytes(v) {
|
||||
Ok(_) => {},
|
||||
Err(_) => panic!("Non-recoverable hardware failure has occured")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::mpsc::channel;
|
||||
use Rng;
|
||||
use OsRng;
|
||||
use std::thread;
|
||||
|
||||
#[test]
|
||||
fn test_os_rng() {
|
||||
let mut r = OsRng::new().unwrap();
|
||||
|
||||
r.next_u32();
|
||||
r.next_u64();
|
||||
|
||||
let mut v = [0u8; 1000];
|
||||
r.fill_bytes(&mut v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_rng_tasks() {
|
||||
|
||||
let mut txs = vec!();
|
||||
for _ in 0..20 {
|
||||
let (tx, rx) = channel();
|
||||
txs.push(tx);
|
||||
|
||||
thread::spawn(move|| {
|
||||
// wait until all the tasks are ready to go.
|
||||
rx.recv().unwrap();
|
||||
|
||||
// deschedule to attempt to interleave things as much
|
||||
// as possible (XXX: is this a good test?)
|
||||
let mut r = OsRng::new().unwrap();
|
||||
thread::yield_now();
|
||||
let mut v = [0u8; 1000];
|
||||
|
||||
for _ in 0..100 {
|
||||
r.next_u32();
|
||||
thread::yield_now();
|
||||
r.next_u64();
|
||||
thread::yield_now();
|
||||
r.fill_bytes(&mut v);
|
||||
thread::yield_now();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// start all the tasks
|
||||
for tx in txs.iter() {
|
||||
tx.send(()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,321 +0,0 @@
|
|||
// Copyright 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.
|
||||
|
||||
//! The ChaCha random number generator.
|
||||
|
||||
use core::num::Wrapping as w;
|
||||
use {Rng, SeedableRng, Rand};
|
||||
|
||||
#[allow(bad_style)]
|
||||
type w32 = w<u32>;
|
||||
|
||||
const KEY_WORDS : usize = 8; // 8 words for the 256-bit key
|
||||
const STATE_WORDS : usize = 16;
|
||||
const CHACHA_ROUNDS: u32 = 20; // Cryptographically secure from 8 upwards as of this writing
|
||||
|
||||
/// A random number generator that uses the ChaCha20 algorithm [1].
|
||||
///
|
||||
/// The ChaCha algorithm is widely accepted as suitable for
|
||||
/// cryptographic purposes, but this implementation has not been
|
||||
/// verified as such. Prefer a generator like `OsRng` that defers to
|
||||
/// the operating system for cases that need high security.
|
||||
///
|
||||
/// [1]: D. J. Bernstein, [*ChaCha, a variant of
|
||||
/// Salsa20*](http://cr.yp.to/chacha.html)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ChaChaRng {
|
||||
buffer: [w32; STATE_WORDS], // Internal buffer of output
|
||||
state: [w32; STATE_WORDS], // Initial state
|
||||
index: usize, // Index into state
|
||||
}
|
||||
|
||||
static EMPTY: ChaChaRng = ChaChaRng {
|
||||
buffer: [w(0); STATE_WORDS],
|
||||
state: [w(0); STATE_WORDS],
|
||||
index: STATE_WORDS
|
||||
};
|
||||
|
||||
|
||||
macro_rules! quarter_round{
|
||||
($a: expr, $b: expr, $c: expr, $d: expr) => {{
|
||||
$a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left(16));
|
||||
$c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left(12));
|
||||
$a = $a + $b; $d = $d ^ $a; $d = w($d.0.rotate_left( 8));
|
||||
$c = $c + $d; $b = $b ^ $c; $b = w($b.0.rotate_left( 7));
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! double_round{
|
||||
($x: expr) => {{
|
||||
// Column round
|
||||
quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]);
|
||||
quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]);
|
||||
quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]);
|
||||
quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]);
|
||||
// Diagonal round
|
||||
quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]);
|
||||
quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]);
|
||||
quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]);
|
||||
quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]);
|
||||
}}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn core(output: &mut [w32; STATE_WORDS], input: &[w32; STATE_WORDS]) {
|
||||
*output = *input;
|
||||
|
||||
for _ in 0..CHACHA_ROUNDS / 2 {
|
||||
double_round!(output);
|
||||
}
|
||||
|
||||
for i in 0..STATE_WORDS {
|
||||
output[i] = output[i] + input[i];
|
||||
}
|
||||
}
|
||||
|
||||
impl ChaChaRng {
|
||||
|
||||
/// Create an ChaCha random number generator using the default
|
||||
/// fixed key of 8 zero words.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{Rng, ChaChaRng};
|
||||
///
|
||||
/// let mut ra = ChaChaRng::new_unseeded();
|
||||
/// println!("{:?}", ra.next_u32());
|
||||
/// println!("{:?}", ra.next_u32());
|
||||
/// ```
|
||||
///
|
||||
/// Since this equivalent to a RNG with a fixed seed, repeated executions
|
||||
/// of an unseeded RNG will produce the same result. This code sample will
|
||||
/// consistently produce:
|
||||
///
|
||||
/// - 2917185654
|
||||
/// - 2419978656
|
||||
pub fn new_unseeded() -> ChaChaRng {
|
||||
let mut rng = EMPTY;
|
||||
rng.init(&[0; KEY_WORDS]);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Sets the internal 128-bit ChaCha counter to
|
||||
/// a user-provided value. This permits jumping
|
||||
/// arbitrarily ahead (or backwards) in the pseudorandom stream.
|
||||
///
|
||||
/// Since the nonce words are used to extend the counter to 128 bits,
|
||||
/// users wishing to obtain the conventional ChaCha pseudorandom stream
|
||||
/// associated with a particular nonce can call this function with
|
||||
/// arguments `0, desired_nonce`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{Rng, ChaChaRng};
|
||||
///
|
||||
/// let mut ra = ChaChaRng::new_unseeded();
|
||||
/// ra.set_counter(0u64, 1234567890u64);
|
||||
/// println!("{:?}", ra.next_u32());
|
||||
/// println!("{:?}", ra.next_u32());
|
||||
/// ```
|
||||
pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
|
||||
self.state[12] = w((counter_low >> 0) as u32);
|
||||
self.state[13] = w((counter_low >> 32) as u32);
|
||||
self.state[14] = w((counter_high >> 0) as u32);
|
||||
self.state[15] = w((counter_high >> 32) as u32);
|
||||
self.index = STATE_WORDS; // force recomputation
|
||||
}
|
||||
|
||||
/// Initializes `self.state` with the appropriate key and constants
|
||||
///
|
||||
/// We deviate slightly from the ChaCha specification regarding
|
||||
/// the nonce, which is used to extend the counter to 128 bits.
|
||||
/// This is provably as strong as the original cipher, though,
|
||||
/// since any distinguishing attack on our variant also works
|
||||
/// against ChaCha with a chosen-nonce. See the XSalsa20 [1]
|
||||
/// security proof for a more involved example of this.
|
||||
///
|
||||
/// The modified word layout is:
|
||||
/// ```text
|
||||
/// constant constant constant constant
|
||||
/// key key key key
|
||||
/// key key key key
|
||||
/// counter counter counter counter
|
||||
/// ```
|
||||
/// [1]: Daniel J. Bernstein. [*Extending the Salsa20
|
||||
/// nonce.*](http://cr.yp.to/papers.html#xsalsa)
|
||||
fn init(&mut self, key: &[u32; KEY_WORDS]) {
|
||||
self.state[0] = w(0x61707865);
|
||||
self.state[1] = w(0x3320646E);
|
||||
self.state[2] = w(0x79622D32);
|
||||
self.state[3] = w(0x6B206574);
|
||||
|
||||
for i in 0..KEY_WORDS {
|
||||
self.state[4+i] = w(key[i]);
|
||||
}
|
||||
|
||||
self.state[12] = w(0);
|
||||
self.state[13] = w(0);
|
||||
self.state[14] = w(0);
|
||||
self.state[15] = w(0);
|
||||
|
||||
self.index = STATE_WORDS;
|
||||
}
|
||||
|
||||
/// Refill the internal output buffer (`self.buffer`)
|
||||
fn update(&mut self) {
|
||||
core(&mut self.buffer, &self.state);
|
||||
self.index = 0;
|
||||
// update 128-bit counter
|
||||
self.state[12] = self.state[12] + w(1);
|
||||
if self.state[12] != w(0) { return };
|
||||
self.state[13] = self.state[13] + w(1);
|
||||
if self.state[13] != w(0) { return };
|
||||
self.state[14] = self.state[14] + w(1);
|
||||
if self.state[14] != w(0) { return };
|
||||
self.state[15] = self.state[15] + w(1);
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for ChaChaRng {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
if self.index == STATE_WORDS {
|
||||
self.update();
|
||||
}
|
||||
|
||||
let value = self.buffer[self.index % STATE_WORDS];
|
||||
self.index += 1;
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SeedableRng<&'a [u32]> for ChaChaRng {
|
||||
|
||||
fn reseed(&mut self, seed: &'a [u32]) {
|
||||
// reset state
|
||||
self.init(&[0u32; KEY_WORDS]);
|
||||
// set key in place
|
||||
let key = &mut self.state[4 .. 4+KEY_WORDS];
|
||||
for (k, s) in key.iter_mut().zip(seed.iter()) {
|
||||
*k = w(*s);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a ChaCha generator from a seed,
|
||||
/// obtained from a variable-length u32 array.
|
||||
/// Only up to 8 words are used; if less than 8
|
||||
/// words are used, the remaining are set to zero.
|
||||
fn from_seed(seed: &'a [u32]) -> ChaChaRng {
|
||||
let mut rng = EMPTY;
|
||||
rng.reseed(seed);
|
||||
rng
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for ChaChaRng {
|
||||
fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
|
||||
let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
|
||||
for word in key.iter_mut() {
|
||||
*word = other.gen();
|
||||
}
|
||||
SeedableRng::from_seed(&key[..])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {Rng, SeedableRng};
|
||||
use super::ChaChaRng;
|
||||
|
||||
#[test]
|
||||
fn test_rng_rand_seeded() {
|
||||
let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
|
||||
let mut ra: ChaChaRng = SeedableRng::from_seed(&s[..]);
|
||||
let mut rb: ChaChaRng = SeedableRng::from_seed(&s[..]);
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_seeded() {
|
||||
let seed : &[_] = &[0,1,2,3,4,5,6,7];
|
||||
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
|
||||
let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_reseed() {
|
||||
let s = ::test::rng().gen_iter::<u32>().take(8).collect::<Vec<u32>>();
|
||||
let mut r: ChaChaRng = SeedableRng::from_seed(&s[..]);
|
||||
let string1: String = r.gen_ascii_chars().take(100).collect();
|
||||
|
||||
r.reseed(&s);
|
||||
|
||||
let string2: String = r.gen_ascii_chars().take(100).collect();
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_true_values() {
|
||||
// Test vectors 1 and 2 from
|
||||
// http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
|
||||
let seed : &[_] = &[0u32; 8];
|
||||
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
|
||||
|
||||
let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
|
||||
assert_eq!(v,
|
||||
vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653,
|
||||
0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b,
|
||||
0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8,
|
||||
0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2));
|
||||
|
||||
let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
|
||||
assert_eq!(v,
|
||||
vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73,
|
||||
0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32,
|
||||
0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874,
|
||||
0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));
|
||||
|
||||
|
||||
let seed : &[_] = &[0,1,2,3,4,5,6,7];
|
||||
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
|
||||
|
||||
// Store the 17*i-th 32-bit word,
|
||||
// i.e., the i-th word of the i-th 16-word block
|
||||
let mut v : Vec<u32> = Vec::new();
|
||||
for _ in 0..16 {
|
||||
v.push(ra.next_u32());
|
||||
for _ in 0..16 {
|
||||
ra.next_u32();
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(v,
|
||||
vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036,
|
||||
0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384,
|
||||
0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530,
|
||||
0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_clone() {
|
||||
let seed : &[_] = &[0u32; 8];
|
||||
let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
|
||||
let mut clone = rng.clone();
|
||||
for _ in 0..16 {
|
||||
assert_eq!(rng.next_u64(), clone.next_u64());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,328 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
//! The ISAAC random number generator.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use core::slice;
|
||||
use core::iter::repeat;
|
||||
use core::num::Wrapping as w;
|
||||
use core::fmt;
|
||||
|
||||
use {Rng, SeedableRng, Rand};
|
||||
|
||||
#[allow(bad_style)]
|
||||
type w32 = w<u32>;
|
||||
|
||||
const RAND_SIZE_LEN: usize = 8;
|
||||
const RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
|
||||
const RAND_SIZE_USIZE: usize = 1 << RAND_SIZE_LEN;
|
||||
|
||||
/// A random number generator that uses the ISAAC algorithm[1].
|
||||
///
|
||||
/// The ISAAC algorithm is generally accepted as suitable for
|
||||
/// cryptographic purposes, but this implementation has not be
|
||||
/// verified as such. Prefer a generator like `OsRng` that defers to
|
||||
/// the operating system for cases that need high security.
|
||||
///
|
||||
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
|
||||
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
|
||||
#[derive(Copy)]
|
||||
pub struct IsaacRng {
|
||||
cnt: u32,
|
||||
rsl: [w32; RAND_SIZE_USIZE],
|
||||
mem: [w32; RAND_SIZE_USIZE],
|
||||
a: w32,
|
||||
b: w32,
|
||||
c: w32,
|
||||
}
|
||||
|
||||
static EMPTY: IsaacRng = IsaacRng {
|
||||
cnt: 0,
|
||||
rsl: [w(0); RAND_SIZE_USIZE],
|
||||
mem: [w(0); RAND_SIZE_USIZE],
|
||||
a: w(0), b: w(0), c: w(0),
|
||||
};
|
||||
|
||||
impl IsaacRng {
|
||||
|
||||
/// Create an ISAAC random number generator using the default
|
||||
/// fixed seed.
|
||||
pub fn new_unseeded() -> IsaacRng {
|
||||
let mut rng = EMPTY;
|
||||
rng.init(false);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Initialises `self`. If `use_rsl` is true, then use the current value
|
||||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||
/// randomly).
|
||||
fn init(&mut self, use_rsl: bool) {
|
||||
let mut a = w(0x9e3779b9);
|
||||
let mut b = a;
|
||||
let mut c = a;
|
||||
let mut d = a;
|
||||
let mut e = a;
|
||||
let mut f = a;
|
||||
let mut g = a;
|
||||
let mut h = a;
|
||||
|
||||
macro_rules! mix {
|
||||
() => {{
|
||||
a=a^(b<<11); d=d+a; b=b+c;
|
||||
b=b^(c>>2); e=e+b; c=c+d;
|
||||
c=c^(d<<8); f=f+c; d=d+e;
|
||||
d=d^(e>>16); g=g+d; e=e+f;
|
||||
e=e^(f<<10); h=h+e; f=f+g;
|
||||
f=f^(g>>4); a=a+f; g=g+h;
|
||||
g=g^(h<<8); b=b+g; h=h+a;
|
||||
h=h^(a>>9); c=c+h; a=a+b;
|
||||
}}
|
||||
}
|
||||
|
||||
for _ in 0..4 {
|
||||
mix!();
|
||||
}
|
||||
|
||||
if use_rsl {
|
||||
macro_rules! memloop {
|
||||
($arr:expr) => {{
|
||||
for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) {
|
||||
a=a+$arr[i ]; b=b+$arr[i+1];
|
||||
c=c+$arr[i+2]; d=d+$arr[i+3];
|
||||
e=e+$arr[i+4]; f=f+$arr[i+5];
|
||||
g=g+$arr[i+6]; h=h+$arr[i+7];
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
} else {
|
||||
for i in (0..RAND_SIZE_USIZE/8).map(|i| i * 8) {
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}
|
||||
|
||||
self.isaac();
|
||||
}
|
||||
|
||||
/// Refills the output buffer (`self.rsl`)
|
||||
#[inline]
|
||||
fn isaac(&mut self) {
|
||||
self.c = self.c + w(1);
|
||||
// abbreviations
|
||||
let mut a = self.a;
|
||||
let mut b = self.b + self.c;
|
||||
|
||||
const MIDPOINT: usize = RAND_SIZE_USIZE / 2;
|
||||
|
||||
macro_rules! ind {
|
||||
($x:expr) => ( self.mem[($x >> 2usize).0 as usize & (RAND_SIZE_USIZE - 1)] )
|
||||
}
|
||||
|
||||
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
|
||||
for &(mr_offset, m2_offset) in r.iter() {
|
||||
|
||||
macro_rules! rngstepp {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = $j;
|
||||
let mix = a << $shift;
|
||||
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_LEN) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! rngstepn {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = $j;
|
||||
let mix = a >> $shift;
|
||||
|
||||
let x = self.mem[base + mr_offset];
|
||||
a = (a ^ mix) + self.mem[base + m2_offset];
|
||||
let y = ind!(x) + a + b;
|
||||
self.mem[base + mr_offset] = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_LEN) + x;
|
||||
self.rsl[base + mr_offset] = b;
|
||||
}}
|
||||
}
|
||||
|
||||
for i in (0..MIDPOINT/4).map(|i| i * 4) {
|
||||
rngstepp!(i + 0, 13);
|
||||
rngstepn!(i + 1, 6);
|
||||
rngstepp!(i + 2, 2);
|
||||
rngstepn!(i + 3, 16);
|
||||
}
|
||||
}
|
||||
|
||||
self.a = a;
|
||||
self.b = b;
|
||||
self.cnt = RAND_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot be derived because [u32; 256] does not implement Clone
|
||||
impl Clone for IsaacRng {
|
||||
fn clone(&self) -> IsaacRng {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for IsaacRng {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
if self.cnt == 0 {
|
||||
// make some more numbers
|
||||
self.isaac();
|
||||
}
|
||||
self.cnt -= 1;
|
||||
|
||||
// self.cnt is at most RAND_SIZE, but that is before the
|
||||
// subtraction above. We want to index without bounds
|
||||
// checking, but this could lead to incorrect code if someone
|
||||
// misrefactors, so we check, sometimes.
|
||||
//
|
||||
// (Changes here should be reflected in Isaac64Rng.next_u64.)
|
||||
debug_assert!(self.cnt < RAND_SIZE);
|
||||
|
||||
// (the % is cheaply telling the optimiser that we're always
|
||||
// in bounds, without unsafe. NB. this is a power of two, so
|
||||
// it optimises to a bitwise mask).
|
||||
self.rsl[(self.cnt % RAND_SIZE) as usize].0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
|
||||
fn reseed(&mut self, seed: &'a [u32]) {
|
||||
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
|
||||
// - 1], 0, 0, ...], to fill rng.rsl.
|
||||
let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u32));
|
||||
|
||||
for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) {
|
||||
*rsl_elem = w(seed_elem);
|
||||
}
|
||||
self.cnt = 0;
|
||||
self.a = w(0);
|
||||
self.b = w(0);
|
||||
self.c = w(0);
|
||||
|
||||
self.init(true);
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator with a seed. This can
|
||||
/// be any length, although the maximum number of elements used is
|
||||
/// 256 and any more will be silently ignored. A generator
|
||||
/// constructed with a given seed will generate the same sequence
|
||||
/// of values as all other generators constructed with that seed.
|
||||
fn from_seed(seed: &'a [u32]) -> IsaacRng {
|
||||
let mut rng = EMPTY;
|
||||
rng.reseed(seed);
|
||||
rng
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for IsaacRng {
|
||||
fn rand<R: Rng>(other: &mut R) -> IsaacRng {
|
||||
let mut ret = EMPTY;
|
||||
unsafe {
|
||||
let ptr = ret.rsl.as_mut_ptr() as *mut u8;
|
||||
|
||||
let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_USIZE * 4);
|
||||
other.fill_bytes(slice);
|
||||
}
|
||||
ret.cnt = 0;
|
||||
ret.a = w(0);
|
||||
ret.b = w(0);
|
||||
ret.c = w(0);
|
||||
|
||||
ret.init(true);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for IsaacRng {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "IsaacRng {{}}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {Rng, SeedableRng};
|
||||
use super::IsaacRng;
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_rand_seeded() {
|
||||
let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(&s[..]);
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(&s[..]);
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_seeded() {
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_reseed() {
|
||||
let s = ::test::rng().gen_iter::<u32>().take(256).collect::<Vec<u32>>();
|
||||
let mut r: IsaacRng = SeedableRng::from_seed(&s[..]);
|
||||
let string1: String = r.gen_ascii_chars().take(100).collect();
|
||||
|
||||
r.reseed(&s[..]);
|
||||
|
||||
let string2: String = r.gen_ascii_chars().take(100).collect();
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_true_values() {
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = (0..10).map(|_| ra.next_u32()).collect::<Vec<_>>();
|
||||
assert_eq!(v,
|
||||
vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709,
|
||||
4203127393, 264982119, 2765226902, 2737944514, 3900253796));
|
||||
|
||||
let seed: &[_] = &[12345, 67890, 54321, 9876];
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in 0..10000 { rb.next_u32(); }
|
||||
|
||||
let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>();
|
||||
assert_eq!(v,
|
||||
vec!(3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
|
||||
1576568959, 3507990155, 179069555, 141456972, 2478885421));
|
||||
}
|
||||
}
|
|
@ -1,340 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
//! The ISAAC-64 random number generator.
|
||||
|
||||
use core::slice;
|
||||
use core::iter::repeat;
|
||||
use core::num::Wrapping as w;
|
||||
use core::fmt;
|
||||
|
||||
use {Rng, SeedableRng, Rand};
|
||||
|
||||
#[allow(bad_style)]
|
||||
type w64 = w<u64>;
|
||||
|
||||
const RAND_SIZE_64_LEN: usize = 8;
|
||||
const RAND_SIZE_64: usize = 1 << RAND_SIZE_64_LEN;
|
||||
|
||||
/// A random number generator that uses ISAAC-64[1], the 64-bit
|
||||
/// variant of the ISAAC algorithm.
|
||||
///
|
||||
/// The ISAAC algorithm is generally accepted as suitable for
|
||||
/// cryptographic purposes, but this implementation has not be
|
||||
/// verified as such. Prefer a generator like `OsRng` that defers to
|
||||
/// the operating system for cases that need high security.
|
||||
///
|
||||
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
|
||||
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
|
||||
#[derive(Copy)]
|
||||
pub struct Isaac64Rng {
|
||||
cnt: usize,
|
||||
rsl: [w64; RAND_SIZE_64],
|
||||
mem: [w64; RAND_SIZE_64],
|
||||
a: w64,
|
||||
b: w64,
|
||||
c: w64,
|
||||
}
|
||||
|
||||
static EMPTY_64: Isaac64Rng = Isaac64Rng {
|
||||
cnt: 0,
|
||||
rsl: [w(0); RAND_SIZE_64],
|
||||
mem: [w(0); RAND_SIZE_64],
|
||||
a: w(0), b: w(0), c: w(0),
|
||||
};
|
||||
|
||||
impl Isaac64Rng {
|
||||
/// Create a 64-bit ISAAC random number generator using the
|
||||
/// default fixed seed.
|
||||
pub fn new_unseeded() -> Isaac64Rng {
|
||||
let mut rng = EMPTY_64;
|
||||
rng.init(false);
|
||||
rng
|
||||
}
|
||||
|
||||
/// Initialises `self`. If `use_rsl` is true, then use the current value
|
||||
/// of `rsl` as a seed, otherwise construct one algorithmically (not
|
||||
/// randomly).
|
||||
fn init(&mut self, use_rsl: bool) {
|
||||
macro_rules! init {
|
||||
($var:ident) => (
|
||||
let mut $var = w(0x9e3779b97f4a7c13);
|
||||
)
|
||||
}
|
||||
init!(a); init!(b); init!(c); init!(d);
|
||||
init!(e); init!(f); init!(g); init!(h);
|
||||
|
||||
macro_rules! mix {
|
||||
() => {{
|
||||
a=a-e; f=f^(h>>9); h=h+a;
|
||||
b=b-f; g=g^(a<<9); a=a+b;
|
||||
c=c-g; h=h^(b>>23); b=b+c;
|
||||
d=d-h; a=a^(c<<15); c=c+d;
|
||||
e=e-a; b=b^(d>>14); d=d+e;
|
||||
f=f-b; c=c^(e<<20); e=e+f;
|
||||
g=g-c; d=d^(f>>17); f=f+g;
|
||||
h=h-d; e=e^(g<<14); g=g+h;
|
||||
}}
|
||||
}
|
||||
|
||||
for _ in 0..4 {
|
||||
mix!();
|
||||
}
|
||||
|
||||
if use_rsl {
|
||||
macro_rules! memloop {
|
||||
($arr:expr) => {{
|
||||
for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
|
||||
a=a+$arr[i ]; b=b+$arr[i+1];
|
||||
c=c+$arr[i+2]; d=d+$arr[i+3];
|
||||
e=e+$arr[i+4]; f=f+$arr[i+5];
|
||||
g=g+$arr[i+6]; h=h+$arr[i+7];
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
memloop!(self.rsl);
|
||||
memloop!(self.mem);
|
||||
} else {
|
||||
for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
|
||||
mix!();
|
||||
self.mem[i ]=a; self.mem[i+1]=b;
|
||||
self.mem[i+2]=c; self.mem[i+3]=d;
|
||||
self.mem[i+4]=e; self.mem[i+5]=f;
|
||||
self.mem[i+6]=g; self.mem[i+7]=h;
|
||||
}
|
||||
}
|
||||
|
||||
self.isaac64();
|
||||
}
|
||||
|
||||
/// Refills the output buffer (`self.rsl`)
|
||||
fn isaac64(&mut self) {
|
||||
self.c = self.c + w(1);
|
||||
// abbreviations
|
||||
let mut a = self.a;
|
||||
let mut b = self.b + self.c;
|
||||
const MIDPOINT: usize = RAND_SIZE_64 / 2;
|
||||
const MP_VEC: [(usize, usize); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
|
||||
macro_rules! ind {
|
||||
($x:expr) => {
|
||||
*self.mem.get_unchecked((($x >> 3usize).0 as usize) & (RAND_SIZE_64 - 1))
|
||||
}
|
||||
}
|
||||
|
||||
for &(mr_offset, m2_offset) in MP_VEC.iter() {
|
||||
for base in (0..MIDPOINT / 4).map(|i| i * 4) {
|
||||
|
||||
macro_rules! rngstepp {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = base + $j;
|
||||
let mix = a ^ (a << $shift);
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
|
||||
unsafe {
|
||||
let x = *self.mem.get_unchecked(base + mr_offset);
|
||||
a = mix + *self.mem.get_unchecked(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
*self.mem.get_unchecked_mut(base + mr_offset) = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! rngstepn {
|
||||
($j:expr, $shift:expr) => {{
|
||||
let base = base + $j;
|
||||
let mix = a ^ (a >> $shift);
|
||||
let mix = if $j == 0 {!mix} else {mix};
|
||||
|
||||
unsafe {
|
||||
let x = *self.mem.get_unchecked(base + mr_offset);
|
||||
a = mix + *self.mem.get_unchecked(base + m2_offset);
|
||||
let y = ind!(x) + a + b;
|
||||
*self.mem.get_unchecked_mut(base + mr_offset) = y;
|
||||
|
||||
b = ind!(y >> RAND_SIZE_64_LEN) + x;
|
||||
*self.rsl.get_unchecked_mut(base + mr_offset) = b;
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
rngstepp!(0, 21);
|
||||
rngstepn!(1, 5);
|
||||
rngstepp!(2, 12);
|
||||
rngstepn!(3, 33);
|
||||
}
|
||||
}
|
||||
|
||||
self.a = a;
|
||||
self.b = b;
|
||||
self.cnt = RAND_SIZE_64;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot be derived because [u32; 256] does not implement Clone
|
||||
impl Clone for Isaac64Rng {
|
||||
fn clone(&self) -> Isaac64Rng {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for Isaac64Rng {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.next_u64() as u32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
if self.cnt == 0 {
|
||||
// make some more numbers
|
||||
self.isaac64();
|
||||
}
|
||||
self.cnt -= 1;
|
||||
|
||||
// See corresponding location in IsaacRng.next_u32 for
|
||||
// explanation.
|
||||
debug_assert!(self.cnt < RAND_SIZE_64);
|
||||
self.rsl[(self.cnt % RAND_SIZE_64) as usize].0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SeedableRng<&'a [u64]> for Isaac64Rng {
|
||||
fn reseed(&mut self, seed: &'a [u64]) {
|
||||
// make the seed into [seed[0], seed[1], ..., seed[seed.len()
|
||||
// - 1], 0, 0, ...], to fill rng.rsl.
|
||||
let seed_iter = seed.iter().map(|&x| x).chain(repeat(0u64));
|
||||
|
||||
for (rsl_elem, seed_elem) in self.rsl.iter_mut().zip(seed_iter) {
|
||||
*rsl_elem = w(seed_elem);
|
||||
}
|
||||
self.cnt = 0;
|
||||
self.a = w(0);
|
||||
self.b = w(0);
|
||||
self.c = w(0);
|
||||
|
||||
self.init(true);
|
||||
}
|
||||
|
||||
/// Create an ISAAC random number generator with a seed. This can
|
||||
/// be any length, although the maximum number of elements used is
|
||||
/// 256 and any more will be silently ignored. A generator
|
||||
/// constructed with a given seed will generate the same sequence
|
||||
/// of values as all other generators constructed with that seed.
|
||||
fn from_seed(seed: &'a [u64]) -> Isaac64Rng {
|
||||
let mut rng = EMPTY_64;
|
||||
rng.reseed(seed);
|
||||
rng
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for Isaac64Rng {
|
||||
fn rand<R: Rng>(other: &mut R) -> Isaac64Rng {
|
||||
let mut ret = EMPTY_64;
|
||||
unsafe {
|
||||
let ptr = ret.rsl.as_mut_ptr() as *mut u8;
|
||||
|
||||
let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE_64 * 8);
|
||||
other.fill_bytes(slice);
|
||||
}
|
||||
ret.cnt = 0;
|
||||
ret.a = w(0);
|
||||
ret.b = w(0);
|
||||
ret.c = w(0);
|
||||
|
||||
ret.init(true);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Isaac64Rng {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Isaac64Rng {{}}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {Rng, SeedableRng};
|
||||
use super::Isaac64Rng;
|
||||
|
||||
#[test]
|
||||
fn test_rng_64_rand_seeded() {
|
||||
let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(&s[..]);
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(&s[..]);
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_64_seeded() {
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_64_reseed() {
|
||||
let s = ::test::rng().gen_iter::<u64>().take(256).collect::<Vec<u64>>();
|
||||
let mut r: Isaac64Rng = SeedableRng::from_seed(&s[..]);
|
||||
let string1: String = r.gen_ascii_chars().take(100).collect();
|
||||
|
||||
r.reseed(&s[..]);
|
||||
|
||||
let string2: String = r.gen_ascii_chars().take(100).collect();
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_64_true_values() {
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = (0..10).map(|_| ra.next_u64()).collect::<Vec<_>>();
|
||||
assert_eq!(v,
|
||||
vec!(547121783600835980, 14377643087320773276, 17351601304698403469,
|
||||
1238879483818134882, 11952566807690396487, 13970131091560099343,
|
||||
4469761996653280935, 15552757044682284409, 6860251611068737823,
|
||||
13722198873481261842));
|
||||
|
||||
let seed: &[_] = &[12345, 67890, 54321, 9876];
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in 0..10000 { rb.next_u64(); }
|
||||
|
||||
let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>();
|
||||
assert_eq!(v,
|
||||
vec!(18143823860592706164, 8491801882678285927, 2699425367717515619,
|
||||
17196852593171130876, 2606123525235546165, 15790932315217671084,
|
||||
596345674630742204, 9947027391921273664, 11788097613744130851,
|
||||
10391409374914919106));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_clone() {
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
let mut clone = rng.clone();
|
||||
for _ in 0..16 {
|
||||
assert_eq!(rng.next_u64(), clone.next_u64());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
//! Pseudo random number generators are algorithms to produce *apparently
|
||||
//! random* numbers deterministically, and usually fairly quickly.
|
||||
//!
|
||||
//! So long as the algorithm is computationally secure, is initialised with
|
||||
//! sufficient entropy (i.e. unknown by an attacker), and its internal state is
|
||||
//! also protected (unknown to an attacker), the output will also be
|
||||
//! *computationally secure*. Computationally Secure Pseudo Random Number
|
||||
//! Generators (CSPRNGs) are thus suitable sources of random numbers for
|
||||
//! cryptography. There are a couple of gotchas here, however. First, the seed
|
||||
//! used for initialisation must be unknown. Usually this should be provided by
|
||||
//! the operating system and should usually be secure, however this may not
|
||||
//! always be the case (especially soon after startup). Second, user-space
|
||||
//! memory may be vulnerable, for example when written to swap space, and after
|
||||
//! forking a child process should reinitialise any user-space PRNGs. For this
|
||||
//! reason it may be preferable to source random numbers directly from the OS
|
||||
//! for cryptographic applications.
|
||||
//!
|
||||
//! PRNGs are also widely used for non-cryptographic uses: randomised
|
||||
//! algorithms, simulations, games. In these applications it is usually not
|
||||
//! important for numbers to be cryptographically *unguessable*, but even
|
||||
//! distribution and independence from other samples (from the point of view
|
||||
//! of someone unaware of the algorithm used, at least) may still be important.
|
||||
//! Good PRNGs should satisfy these properties, but do not take them for
|
||||
//! granted; Wikipedia's article on
|
||||
//! [Pseudorandom number generators](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
|
||||
//! provides some background on this topic.
|
||||
//!
|
||||
//! Care should be taken when seeding (initialising) PRNGs. Some PRNGs have
|
||||
//! short periods for some seeds. If one PRNG is seeded from another using the
|
||||
//! same algorithm, it is possible that both will yield the same sequence of
|
||||
//! values (with some lag).
|
||||
|
||||
mod chacha;
|
||||
mod isaac;
|
||||
mod isaac64;
|
||||
mod xorshift;
|
||||
|
||||
pub use self::chacha::ChaChaRng;
|
||||
pub use self::isaac::IsaacRng;
|
||||
pub use self::isaac64::Isaac64Rng;
|
||||
pub use self::xorshift::XorShiftRng;
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
//! Xorshift generators
|
||||
|
||||
use core::num::Wrapping as w;
|
||||
use {Rng, SeedableRng, Rand};
|
||||
|
||||
/// An Xorshift[1] random number
|
||||
/// generator.
|
||||
///
|
||||
/// The Xorshift algorithm is not suitable for cryptographic purposes
|
||||
/// but is very fast. If you do not know for sure that it fits your
|
||||
/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
|
||||
///
|
||||
/// [1]: Marsaglia, George (July 2003). ["Xorshift
|
||||
/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
|
||||
/// Statistical Software*. Vol. 8 (Issue 14).
|
||||
#[allow(missing_copy_implementations)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct XorShiftRng {
|
||||
x: w<u32>,
|
||||
y: w<u32>,
|
||||
z: w<u32>,
|
||||
w: w<u32>,
|
||||
}
|
||||
|
||||
impl XorShiftRng {
|
||||
/// Creates a new XorShiftRng instance which is not seeded.
|
||||
///
|
||||
/// The initial values of this RNG are constants, so all generators created
|
||||
/// by this function will yield the same stream of random numbers. It is
|
||||
/// highly recommended that this is created through `SeedableRng` instead of
|
||||
/// this function
|
||||
pub fn new_unseeded() -> XorShiftRng {
|
||||
XorShiftRng {
|
||||
x: w(0x193a6754),
|
||||
y: w(0xa8a7d469),
|
||||
z: w(0x97830e05),
|
||||
w: w(0x113ba7bb),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rng for XorShiftRng {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
let x = self.x;
|
||||
let t = x ^ (x << 11);
|
||||
self.x = self.y;
|
||||
self.y = self.z;
|
||||
self.z = self.w;
|
||||
let w_ = self.w;
|
||||
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
|
||||
self.w.0
|
||||
}
|
||||
}
|
||||
|
||||
impl SeedableRng<[u32; 4]> for XorShiftRng {
|
||||
/// Reseed an XorShiftRng. This will panic if `seed` is entirely 0.
|
||||
fn reseed(&mut self, seed: [u32; 4]) {
|
||||
assert!(!seed.iter().all(|&x| x == 0),
|
||||
"XorShiftRng.reseed called with an all zero seed.");
|
||||
|
||||
self.x = w(seed[0]);
|
||||
self.y = w(seed[1]);
|
||||
self.z = w(seed[2]);
|
||||
self.w = w(seed[3]);
|
||||
}
|
||||
|
||||
/// Create a new XorShiftRng. This will panic if `seed` is entirely 0.
|
||||
fn from_seed(seed: [u32; 4]) -> XorShiftRng {
|
||||
assert!(!seed.iter().all(|&x| x == 0),
|
||||
"XorShiftRng::from_seed called with an all zero seed.");
|
||||
|
||||
XorShiftRng {
|
||||
x: w(seed[0]),
|
||||
y: w(seed[1]),
|
||||
z: w(seed[2]),
|
||||
w: w(seed[3]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for XorShiftRng {
|
||||
fn rand<R: Rng>(rng: &mut R) -> XorShiftRng {
|
||||
let mut tuple: (u32, u32, u32, u32) = rng.gen();
|
||||
while tuple == (0, 0, 0, 0) {
|
||||
tuple = rng.gen();
|
||||
}
|
||||
let (x, y, z, w_) = tuple;
|
||||
XorShiftRng { x: w(x), y: w(y), z: w(z), w: w(w_) }
|
||||
}
|
||||
}
|
|
@ -1,299 +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.
|
||||
|
||||
//! The implementations of `Rand` for the built-in types.
|
||||
|
||||
use core::{char, mem};
|
||||
|
||||
use {Rand,Rng};
|
||||
|
||||
impl Rand for isize {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> isize {
|
||||
if mem::size_of::<isize>() == 4 {
|
||||
rng.gen::<i32>() as isize
|
||||
} else {
|
||||
rng.gen::<i64>() as isize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i8 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i8 {
|
||||
rng.next_u32() as i8
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i16 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i16 {
|
||||
rng.next_u32() as i16
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i32 {
|
||||
rng.next_u32() as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for i64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i64 {
|
||||
rng.next_u64() as i64
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "i128_support")]
|
||||
impl Rand for i128 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> i128 {
|
||||
rng.gen::<u128>() as i128
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for usize {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> usize {
|
||||
if mem::size_of::<usize>() == 4 {
|
||||
rng.gen::<u32>() as usize
|
||||
} else {
|
||||
rng.gen::<u64>() as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u8 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u8 {
|
||||
rng.next_u32() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u16 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u16 {
|
||||
rng.next_u32() as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u32 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u32 {
|
||||
rng.next_u32()
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for u64 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u64 {
|
||||
rng.next_u64()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "i128_support")]
|
||||
impl Rand for u128 {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> u128 {
|
||||
((rng.next_u64() as u128) << 64) | (rng.next_u64() as u128)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! float_impls {
|
||||
($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident) => {
|
||||
mod $mod_name {
|
||||
use {Rand, Rng, Open01, Closed01};
|
||||
|
||||
const SCALE: $ty = (1u64 << $mantissa_bits) as $ty;
|
||||
|
||||
impl Rand for $ty {
|
||||
/// Generate a floating point number in the half-open
|
||||
/// interval `[0,1)`.
|
||||
///
|
||||
/// See `Closed01` for the closed interval `[0,1]`,
|
||||
/// and `Open01` for the open interval `(0,1)`.
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> $ty {
|
||||
rng.$method_name()
|
||||
}
|
||||
}
|
||||
impl Rand for Open01<$ty> {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
|
||||
// add a small amount (specifically 2 bits below
|
||||
// the precision of f64/f32 at 1.0), so that small
|
||||
// numbers are larger than 0, but large numbers
|
||||
// aren't pushed to/above 1.
|
||||
Open01(rng.$method_name() + 0.25 / SCALE)
|
||||
}
|
||||
}
|
||||
impl Rand for Closed01<$ty> {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> Closed01<$ty> {
|
||||
// rescale so that 1.0 - epsilon becomes 1.0
|
||||
// precisely.
|
||||
Closed01(rng.$method_name() * SCALE / (SCALE - 1.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
float_impls! { f64_rand_impls, f64, 53, next_f64 }
|
||||
float_impls! { f32_rand_impls, f32, 24, next_f32 }
|
||||
|
||||
impl Rand for char {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> char {
|
||||
// a char is 21 bits
|
||||
const CHAR_MASK: u32 = 0x001f_ffff;
|
||||
loop {
|
||||
// Rejection sampling. About 0.2% of numbers with at most
|
||||
// 21-bits are invalid codepoints (surrogates), so this
|
||||
// will succeed first go almost every time.
|
||||
match char::from_u32(rng.next_u32() & CHAR_MASK) {
|
||||
Some(c) => return c,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for bool {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> bool {
|
||||
rng.gen::<u8>() & 1 == 1
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuple_impl {
|
||||
// use variables to indicate the arity of the tuple
|
||||
($($tyvar:ident),* ) => {
|
||||
// the trailing commas are for the 1 tuple
|
||||
impl<
|
||||
$( $tyvar : Rand ),*
|
||||
> Rand for ( $( $tyvar ),* , ) {
|
||||
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
|
||||
(
|
||||
// use the $tyvar's to get the appropriate number of
|
||||
// repeats (they're not actually needed)
|
||||
$(
|
||||
_rng.gen::<$tyvar>()
|
||||
),*
|
||||
,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rand for () {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_: &mut R) -> () { () }
|
||||
}
|
||||
tuple_impl!{A}
|
||||
tuple_impl!{A, B}
|
||||
tuple_impl!{A, B, C}
|
||||
tuple_impl!{A, B, C, D}
|
||||
tuple_impl!{A, B, C, D, E}
|
||||
tuple_impl!{A, B, C, D, E, F}
|
||||
tuple_impl!{A, B, C, D, E, F, G}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
|
||||
|
||||
macro_rules! array_impl {
|
||||
{$n:expr, $t:ident, $($ts:ident,)*} => {
|
||||
array_impl!{($n - 1), $($ts,)*}
|
||||
|
||||
impl<T> Rand for [T; $n] where T: Rand {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(_rng: &mut R) -> [T; $n] {
|
||||
[_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*]
|
||||
}
|
||||
}
|
||||
};
|
||||
{$n:expr,} => {
|
||||
impl<T> Rand for [T; $n] {
|
||||
fn rand<R: Rng>(_rng: &mut R) -> [T; $n] { [] }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
|
||||
|
||||
impl<T:Rand> Rand for Option<T> {
|
||||
#[inline]
|
||||
fn rand<R: Rng>(rng: &mut R) -> Option<T> {
|
||||
if rng.gen() {
|
||||
Some(rng.gen())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {Rng, thread_rng, Open01, Closed01};
|
||||
|
||||
struct ConstantRng(u64);
|
||||
impl Rng for ConstantRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
let ConstantRng(v) = *self;
|
||||
v as u32
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
let ConstantRng(v) = *self;
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floating_point_edge_cases() {
|
||||
// the test for exact equality is correct here.
|
||||
assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0);
|
||||
assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rand_open() {
|
||||
// this is unlikely to catch an incorrect implementation that
|
||||
// generates exactly 0 or 1, but it keeps it sane.
|
||||
let mut rng = thread_rng();
|
||||
for _ in 0..1_000 {
|
||||
// strict inequalities
|
||||
let Open01(f) = rng.gen::<Open01<f64>>();
|
||||
assert!(0.0 < f && f < 1.0);
|
||||
|
||||
let Open01(f) = rng.gen::<Open01<f32>>();
|
||||
assert!(0.0 < f && f < 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rand_closed() {
|
||||
let mut rng = thread_rng();
|
||||
for _ in 0..1_000 {
|
||||
// strict inequalities
|
||||
let Closed01(f) = rng.gen::<Closed01<f64>>();
|
||||
assert!(0.0 <= f && f <= 1.0);
|
||||
|
||||
let Closed01(f) = rng.gen::<Closed01<f32>>();
|
||||
assert!(0.0 <= f && f <= 1.0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
// Copyright 2013 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 wrapper around any Read to treat it as an RNG.
|
||||
|
||||
use std::io::{self, Read};
|
||||
use std::mem;
|
||||
use Rng;
|
||||
|
||||
/// An RNG that reads random bytes straight from a `Read`. This will
|
||||
/// work best with an infinite reader, but this is not required.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// It will panic if it there is insufficient data to fulfill a request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{read, Rng};
|
||||
///
|
||||
/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8];
|
||||
/// let mut rng = read::ReadRng::new(&data[..]);
|
||||
/// println!("{:x}", rng.gen::<u32>());
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct ReadRng<R> {
|
||||
reader: R
|
||||
}
|
||||
|
||||
impl<R: Read> ReadRng<R> {
|
||||
/// Create a new `ReadRng` from a `Read`.
|
||||
pub fn new(r: R) -> ReadRng<R> {
|
||||
ReadRng {
|
||||
reader: r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Rng for ReadRng<R> {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
// This is designed for speed: reading a LE integer on a LE
|
||||
// platform just involves blitting the bytes into the memory
|
||||
// of the u32, similarly for BE on BE; avoiding byteswapping.
|
||||
let mut buf = [0; 4];
|
||||
fill(&mut self.reader, &mut buf).unwrap();
|
||||
unsafe { *(buf.as_ptr() as *const u32) }
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
// see above for explanation.
|
||||
let mut buf = [0; 8];
|
||||
fill(&mut self.reader, &mut buf).unwrap();
|
||||
unsafe { *(buf.as_ptr() as *const u64) }
|
||||
}
|
||||
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||
if v.len() == 0 { return }
|
||||
fill(&mut self.reader, v).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn fill(r: &mut Read, mut buf: &mut [u8]) -> io::Result<()> {
|
||||
while buf.len() > 0 {
|
||||
match try!(r.read(buf)) {
|
||||
0 => return Err(io::Error::new(io::ErrorKind::Other,
|
||||
"end of file reached")),
|
||||
n => buf = &mut mem::replace(&mut buf, &mut [])[n..],
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::ReadRng;
|
||||
use Rng;
|
||||
|
||||
#[test]
|
||||
fn test_reader_rng_u64() {
|
||||
// transmute from the target to avoid endianness concerns.
|
||||
let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
|
||||
0 , 0, 0, 0, 0, 0, 0, 2,
|
||||
0, 0, 0, 0, 0, 0, 0, 3];
|
||||
let mut rng = ReadRng::new(&v[..]);
|
||||
|
||||
assert_eq!(rng.next_u64(), 1_u64.to_be());
|
||||
assert_eq!(rng.next_u64(), 2_u64.to_be());
|
||||
assert_eq!(rng.next_u64(), 3_u64.to_be());
|
||||
}
|
||||
#[test]
|
||||
fn test_reader_rng_u32() {
|
||||
let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
|
||||
let mut rng = ReadRng::new(&v[..]);
|
||||
|
||||
assert_eq!(rng.next_u32(), 1_u32.to_be());
|
||||
assert_eq!(rng.next_u32(), 2_u32.to_be());
|
||||
assert_eq!(rng.next_u32(), 3_u32.to_be());
|
||||
}
|
||||
#[test]
|
||||
fn test_reader_rng_fill_bytes() {
|
||||
let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
|
||||
let mut w = [0u8; 8];
|
||||
|
||||
let mut rng = ReadRng::new(&v[..]);
|
||||
rng.fill_bytes(&mut w);
|
||||
|
||||
assert!(v == w);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_reader_rng_insufficient_bytes() {
|
||||
let mut rng = ReadRng::new(&[][..]);
|
||||
let mut v = [0u8; 3];
|
||||
rng.fill_bytes(&mut v);
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
// Copyright 2013 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 wrapper around another RNG that reseeds it after it
|
||||
//! generates a certain number of random bytes.
|
||||
|
||||
use core::default::Default;
|
||||
|
||||
use {Rng, SeedableRng};
|
||||
|
||||
/// How many bytes of entropy the underling RNG is allowed to generate
|
||||
/// before it is reseeded
|
||||
const DEFAULT_GENERATION_THRESHOLD: u64 = 32 * 1024;
|
||||
|
||||
/// A wrapper around any RNG which reseeds the underlying RNG after it
|
||||
/// has generated a certain number of random bytes.
|
||||
#[derive(Debug)]
|
||||
pub struct ReseedingRng<R, Rsdr> {
|
||||
rng: R,
|
||||
generation_threshold: u64,
|
||||
bytes_generated: u64,
|
||||
/// Controls the behaviour when reseeding the RNG.
|
||||
pub reseeder: Rsdr,
|
||||
}
|
||||
|
||||
impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
|
||||
/// Create a new `ReseedingRng` with the given parameters.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `rng`: the random number generator to use.
|
||||
/// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
|
||||
/// * `reseeder`: the reseeding object to use.
|
||||
pub fn new(rng: R, generation_threshold: u64, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
|
||||
ReseedingRng {
|
||||
rng: rng,
|
||||
generation_threshold: generation_threshold,
|
||||
bytes_generated: 0,
|
||||
reseeder: reseeder
|
||||
}
|
||||
}
|
||||
|
||||
/// Reseed the internal RNG if the number of bytes that have been
|
||||
/// generated exceed the threshold.
|
||||
pub fn reseed_if_necessary(&mut self) {
|
||||
if self.bytes_generated >= self.generation_threshold {
|
||||
self.reseeder.reseed(&mut self.rng);
|
||||
self.bytes_generated = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.reseed_if_necessary();
|
||||
self.bytes_generated += 4;
|
||||
self.rng.next_u32()
|
||||
}
|
||||
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.reseed_if_necessary();
|
||||
self.bytes_generated += 8;
|
||||
self.rng.next_u64()
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
self.reseed_if_necessary();
|
||||
self.bytes_generated += dest.len() as u64;
|
||||
self.rng.fill_bytes(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
|
||||
SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
|
||||
fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
|
||||
self.rng.reseed(seed);
|
||||
self.reseeder = rsdr;
|
||||
self.bytes_generated = 0;
|
||||
}
|
||||
|
||||
/// Create a new `ReseedingRng` from the given reseeder and
|
||||
/// seed. This uses a default value for `generation_threshold`.
|
||||
fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
|
||||
ReseedingRng {
|
||||
rng: SeedableRng::from_seed(seed),
|
||||
generation_threshold: DEFAULT_GENERATION_THRESHOLD,
|
||||
bytes_generated: 0,
|
||||
reseeder: rsdr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that can be used to reseed an RNG via `ReseedingRng`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{Rng, SeedableRng, StdRng};
|
||||
/// use rand::reseeding::{Reseeder, ReseedingRng};
|
||||
///
|
||||
/// struct TickTockReseeder { tick: bool }
|
||||
/// impl Reseeder<StdRng> for TickTockReseeder {
|
||||
/// fn reseed(&mut self, rng: &mut StdRng) {
|
||||
/// let val = if self.tick {0} else {1};
|
||||
/// rng.reseed(&[val]);
|
||||
/// self.tick = !self.tick;
|
||||
/// }
|
||||
/// }
|
||||
/// fn main() {
|
||||
/// let rsdr = TickTockReseeder { tick: true };
|
||||
///
|
||||
/// let inner = StdRng::new().unwrap();
|
||||
/// let mut rng = ReseedingRng::new(inner, 10, rsdr);
|
||||
///
|
||||
/// // this will repeat, because it gets reseeded very regularly.
|
||||
/// let s: String = rng.gen_ascii_chars().take(100).collect();
|
||||
/// println!("{}", s);
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
pub trait Reseeder<R> {
|
||||
/// Reseed the given RNG.
|
||||
fn reseed(&mut self, rng: &mut R);
|
||||
}
|
||||
|
||||
/// Reseed an RNG using a `Default` instance. This reseeds by
|
||||
/// replacing the RNG with the result of a `Default::default` call.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ReseedWithDefault;
|
||||
|
||||
impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
|
||||
fn reseed(&mut self, rng: &mut R) {
|
||||
*rng = Default::default();
|
||||
}
|
||||
}
|
||||
impl Default for ReseedWithDefault {
|
||||
fn default() -> ReseedWithDefault { ReseedWithDefault }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::default::Default;
|
||||
use std::iter::repeat;
|
||||
use super::{ReseedingRng, ReseedWithDefault};
|
||||
use {SeedableRng, Rng};
|
||||
|
||||
struct Counter {
|
||||
i: u32
|
||||
}
|
||||
|
||||
impl Rng for Counter {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.i += 1;
|
||||
// very random
|
||||
self.i - 1
|
||||
}
|
||||
}
|
||||
impl Default for Counter {
|
||||
fn default() -> Counter {
|
||||
Counter { i: 0 }
|
||||
}
|
||||
}
|
||||
impl SeedableRng<u32> for Counter {
|
||||
fn reseed(&mut self, seed: u32) {
|
||||
self.i = seed;
|
||||
}
|
||||
fn from_seed(seed: u32) -> Counter {
|
||||
Counter { i: seed }
|
||||
}
|
||||
}
|
||||
type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
|
||||
|
||||
#[test]
|
||||
fn test_reseeding() {
|
||||
let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
|
||||
|
||||
let mut i = 0;
|
||||
for _ in 0..1000 {
|
||||
assert_eq!(rs.next_u32(), i % 100);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_seeded() {
|
||||
let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
|
||||
let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
|
||||
assert!(::test::iter_eq(ra.gen_ascii_chars().take(100),
|
||||
rb.gen_ascii_chars().take(100)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_reseed() {
|
||||
let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
|
||||
let string1: String = r.gen_ascii_chars().take(100).collect();
|
||||
|
||||
r.reseed((ReseedWithDefault, 3));
|
||||
|
||||
let string2: String = r.gen_ascii_chars().take(100).collect();
|
||||
assert_eq!(string1, string2);
|
||||
}
|
||||
|
||||
const FILL_BYTES_V_LEN: usize = 13579;
|
||||
#[test]
|
||||
fn test_rng_fill_bytes() {
|
||||
let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
|
||||
::test::rng().fill_bytes(&mut v);
|
||||
|
||||
// Sanity test: if we've gotten here, `fill_bytes` has not infinitely
|
||||
// recursed.
|
||||
assert_eq!(v.len(), FILL_BYTES_V_LEN);
|
||||
|
||||
// To test that `fill_bytes` actually did something, check that the
|
||||
// average of `v` is not 0.
|
||||
let mut sum = 0.0;
|
||||
for &x in v.iter() {
|
||||
sum += x as f64;
|
||||
}
|
||||
assert!(sum / v.len() as f64 != 0.0);
|
||||
}
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
//! Functions for randomly accessing and sampling sequences.
|
||||
|
||||
use super::Rng;
|
||||
|
||||
// This crate is only enabled when either std or alloc is available.
|
||||
// BTreeMap is not as fast in tests, but better than nothing.
|
||||
#[cfg(feature="std")] use std::collections::HashMap;
|
||||
#[cfg(not(feature="std"))] use alloc::btree_map::BTreeMap;
|
||||
|
||||
#[cfg(not(feature="std"))] use alloc::Vec;
|
||||
|
||||
/// Randomly sample `amount` elements from a finite iterator.
|
||||
///
|
||||
/// The following can be returned:
|
||||
/// - `Ok`: `Vec` of `amount` non-repeating randomly sampled elements. The order is not random.
|
||||
/// - `Err`: `Vec` of all the elements from `iterable` in sequential order. This happens when the
|
||||
/// length of `iterable` was less than `amount`. This is considered an error since exactly
|
||||
/// `amount` elements is typically expected.
|
||||
///
|
||||
/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{thread_rng, seq};
|
||||
///
|
||||
/// let mut rng = thread_rng();
|
||||
/// let sample = seq::sample_iter(&mut rng, 1..100, 5).unwrap();
|
||||
/// println!("{:?}", sample);
|
||||
/// ```
|
||||
pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Result<Vec<T>, Vec<T>>
|
||||
where I: IntoIterator<Item=T>,
|
||||
R: Rng,
|
||||
{
|
||||
let mut iter = iterable.into_iter();
|
||||
let mut reservoir = Vec::with_capacity(amount);
|
||||
reservoir.extend(iter.by_ref().take(amount));
|
||||
|
||||
// Continue unless the iterator was exhausted
|
||||
//
|
||||
// note: this prevents iterators that "restart" from causing problems.
|
||||
// If the iterator stops once, then so do we.
|
||||
if reservoir.len() == amount {
|
||||
for (i, elem) in iter.enumerate() {
|
||||
let k = rng.gen_range(0, i + 1 + amount);
|
||||
if let Some(spot) = reservoir.get_mut(k) {
|
||||
*spot = elem;
|
||||
}
|
||||
}
|
||||
Ok(reservoir)
|
||||
} else {
|
||||
// Don't hang onto extra memory. There is a corner case where
|
||||
// `amount` was much less than `len(iterable)`.
|
||||
reservoir.shrink_to_fit();
|
||||
Err(reservoir)
|
||||
}
|
||||
}
|
||||
|
||||
/// Randomly sample exactly `amount` values from `slice`.
|
||||
///
|
||||
/// The values are non-repeating and in random order.
|
||||
///
|
||||
/// This implementation uses `O(amount)` time and memory.
|
||||
///
|
||||
/// Panics if `amount > slice.len()`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{thread_rng, seq};
|
||||
///
|
||||
/// let mut rng = thread_rng();
|
||||
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
|
||||
/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
|
||||
/// ```
|
||||
pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
|
||||
where R: Rng,
|
||||
T: Clone
|
||||
{
|
||||
let indices = sample_indices(rng, slice.len(), amount);
|
||||
|
||||
let mut out = Vec::with_capacity(amount);
|
||||
out.extend(indices.iter().map(|i| slice[*i].clone()));
|
||||
out
|
||||
}
|
||||
|
||||
/// Randomly sample exactly `amount` references from `slice`.
|
||||
///
|
||||
/// The references are non-repeating and in random order.
|
||||
///
|
||||
/// This implementation uses `O(amount)` time and memory.
|
||||
///
|
||||
/// Panics if `amount > slice.len()`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rand::{thread_rng, seq};
|
||||
///
|
||||
/// let mut rng = thread_rng();
|
||||
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
|
||||
/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
|
||||
/// ```
|
||||
pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
|
||||
where R: Rng
|
||||
{
|
||||
let indices = sample_indices(rng, slice.len(), amount);
|
||||
|
||||
let mut out = Vec::with_capacity(amount);
|
||||
out.extend(indices.iter().map(|i| &slice[*i]));
|
||||
out
|
||||
}
|
||||
|
||||
/// Randomly sample exactly `amount` indices from `0..length`.
|
||||
///
|
||||
/// The values are non-repeating and in random order.
|
||||
///
|
||||
/// This implementation uses `O(amount)` time and memory.
|
||||
///
|
||||
/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
|
||||
/// have the indices themselves so this is provided as an alternative.
|
||||
///
|
||||
/// Panics if `amount > length`
|
||||
pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
|
||||
where R: Rng,
|
||||
{
|
||||
if amount > length {
|
||||
panic!("`amount` must be less than or equal to `slice.len()`");
|
||||
}
|
||||
|
||||
// We are going to have to allocate at least `amount` for the output no matter what. However,
|
||||
// if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
|
||||
// it inserts an element for every loop.
|
||||
//
|
||||
// Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
|
||||
// In fact, benchmarks show the inplace version is faster for length up to about 20 times
|
||||
// faster than amount.
|
||||
//
|
||||
// TODO: there is probably even more fine-tuning that can be done here since
|
||||
// `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
|
||||
// and a trade off could probably be made between memory/cpu, since hashmap operations
|
||||
// are slower than array index swapping.
|
||||
if amount >= length / 20 {
|
||||
sample_indices_inplace(rng, length, amount)
|
||||
} else {
|
||||
sample_indices_cache(rng, length, amount)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample an amount of indices using an inplace partial fisher yates method.
|
||||
///
|
||||
/// This allocates the entire `length` of indices and randomizes only the first `amount`.
|
||||
/// It then truncates to `amount` and returns.
|
||||
///
|
||||
/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
|
||||
/// require allocating an extra cache and is much faster.
|
||||
fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
|
||||
where R: Rng,
|
||||
{
|
||||
debug_assert!(amount <= length);
|
||||
let mut indices: Vec<usize> = Vec::with_capacity(length);
|
||||
indices.extend(0..length);
|
||||
for i in 0..amount {
|
||||
let j: usize = rng.gen_range(i, length);
|
||||
let tmp = indices[i];
|
||||
indices[i] = indices[j];
|
||||
indices[j] = tmp;
|
||||
}
|
||||
indices.truncate(amount);
|
||||
debug_assert_eq!(indices.len(), amount);
|
||||
indices
|
||||
}
|
||||
|
||||
|
||||
/// This method performs a partial fisher-yates on a range of indices using a HashMap
|
||||
/// as a cache to record potential collisions.
|
||||
///
|
||||
/// The cache avoids allocating the entire `length` of values. This is especially useful when
|
||||
/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
|
||||
fn sample_indices_cache<R>(
|
||||
rng: &mut R,
|
||||
length: usize,
|
||||
amount: usize,
|
||||
) -> Vec<usize>
|
||||
where R: Rng,
|
||||
{
|
||||
debug_assert!(amount <= length);
|
||||
#[cfg(feature="std")] let mut cache = HashMap::with_capacity(amount);
|
||||
#[cfg(not(feature="std"))] let mut cache = BTreeMap::new();
|
||||
let mut out = Vec::with_capacity(amount);
|
||||
for i in 0..amount {
|
||||
let j: usize = rng.gen_range(i, length);
|
||||
|
||||
// equiv: let tmp = slice[i];
|
||||
let tmp = match cache.get(&i) {
|
||||
Some(e) => *e,
|
||||
None => i,
|
||||
};
|
||||
|
||||
// equiv: slice[i] = slice[j];
|
||||
let x = match cache.get(&j) {
|
||||
Some(x) => *x,
|
||||
None => j,
|
||||
};
|
||||
|
||||
// equiv: slice[j] = tmp;
|
||||
cache.insert(j, tmp);
|
||||
|
||||
// note that in the inplace version, slice[i] is automatically "returned" value
|
||||
out.push(x);
|
||||
}
|
||||
debug_assert_eq!(out.len(), amount);
|
||||
out
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use {thread_rng, XorShiftRng, SeedableRng};
|
||||
|
||||
#[test]
|
||||
fn test_sample_iter() {
|
||||
let min_val = 1;
|
||||
let max_val = 100;
|
||||
|
||||
let mut r = thread_rng();
|
||||
let vals = (min_val..max_val).collect::<Vec<i32>>();
|
||||
let small_sample = sample_iter(&mut r, vals.iter(), 5).unwrap();
|
||||
let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5).unwrap_err();
|
||||
|
||||
assert_eq!(small_sample.len(), 5);
|
||||
assert_eq!(large_sample.len(), vals.len());
|
||||
// no randomization happens when amount >= len
|
||||
assert_eq!(large_sample, vals.iter().collect::<Vec<_>>());
|
||||
|
||||
assert!(small_sample.iter().all(|e| {
|
||||
**e >= min_val && **e <= max_val
|
||||
}));
|
||||
}
|
||||
#[test]
|
||||
fn test_sample_slice_boundaries() {
|
||||
let empty: &[u8] = &[];
|
||||
|
||||
let mut r = thread_rng();
|
||||
|
||||
// sample 0 items
|
||||
assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
|
||||
assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);
|
||||
|
||||
// sample 1 item
|
||||
assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
|
||||
let v = sample_slice(&mut r, &[1, 42], 1)[0];
|
||||
assert!(v == 1 || v == 42);
|
||||
|
||||
// sample "all" the items
|
||||
let v = sample_slice(&mut r, &[42, 133], 2);
|
||||
assert!(v == vec![42, 133] || v == vec![133, 42]);
|
||||
|
||||
assert_eq!(sample_indices_inplace(&mut r, 0, 0), vec![]);
|
||||
assert_eq!(sample_indices_inplace(&mut r, 1, 0), vec![]);
|
||||
assert_eq!(sample_indices_inplace(&mut r, 1, 1), vec![0]);
|
||||
|
||||
assert_eq!(sample_indices_cache(&mut r, 0, 0), vec![]);
|
||||
assert_eq!(sample_indices_cache(&mut r, 1, 0), vec![]);
|
||||
assert_eq!(sample_indices_cache(&mut r, 1, 1), vec![0]);
|
||||
|
||||
// Make sure lucky 777's aren't lucky
|
||||
let slice = &[42, 777];
|
||||
let mut num_42 = 0;
|
||||
let total = 1000;
|
||||
for _ in 0..total {
|
||||
let v = sample_slice(&mut r, slice, 1);
|
||||
assert_eq!(v.len(), 1);
|
||||
let v = v[0];
|
||||
assert!(v == 42 || v == 777);
|
||||
if v == 42 {
|
||||
num_42 += 1;
|
||||
}
|
||||
}
|
||||
let ratio_42 = num_42 as f64 / 1000 as f64;
|
||||
assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sample_slice() {
|
||||
let xor_rng = XorShiftRng::from_seed;
|
||||
|
||||
let max_range = 100;
|
||||
let mut r = thread_rng();
|
||||
|
||||
for length in 1usize..max_range {
|
||||
let amount = r.gen_range(0, length);
|
||||
let seed: [u32; 4] = [
|
||||
r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
|
||||
];
|
||||
|
||||
println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);
|
||||
|
||||
// assert that the two index methods give exactly the same result
|
||||
let inplace = sample_indices_inplace(
|
||||
&mut xor_rng(seed), length, amount);
|
||||
let cache = sample_indices_cache(
|
||||
&mut xor_rng(seed), length, amount);
|
||||
assert_eq!(inplace, cache);
|
||||
|
||||
// assert the basics work
|
||||
let regular = sample_indices(
|
||||
&mut xor_rng(seed), length, amount);
|
||||
assert_eq!(regular.len(), amount);
|
||||
assert!(regular.iter().all(|e| *e < length));
|
||||
assert_eq!(regular, inplace);
|
||||
|
||||
// also test that sampling the slice works
|
||||
let vec: Vec<usize> = (0..length).collect();
|
||||
{
|
||||
let result = sample_slice(&mut xor_rng(seed), &vec, amount);
|
||||
assert_eq!(result, regular);
|
||||
}
|
||||
|
||||
{
|
||||
let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
|
||||
let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2013 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.
|
||||
|
||||
# This creates the tables used for distributions implemented using the
|
||||
# ziggurat algorithm in `rand::distributions;`. They are
|
||||
# (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
|
||||
# They are changed rarely, so the generated file should be checked in
|
||||
# to git.
|
||||
#
|
||||
# It creates 3 tables: X as in the paper, F which is f(x_i), and
|
||||
# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached
|
||||
# values which is not done in that paper (but is done in other
|
||||
# variants). Note that the adZigR table is unnecessary because of
|
||||
# algebra.
|
||||
#
|
||||
# It is designed to be compatible with Python 2 and 3.
|
||||
|
||||
from math import exp, sqrt, log, floor
|
||||
import random
|
||||
|
||||
# The order should match the return value of `tables`
|
||||
TABLE_NAMES = ['X', 'F']
|
||||
|
||||
# The actual length of the table is 1 more, to stop
|
||||
# index-out-of-bounds errors. This should match the bitwise operation
|
||||
# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and
|
||||
# *_V constants below depend on this value.
|
||||
TABLE_LEN = 256
|
||||
|
||||
# equivalent to `zigNorInit` in Doornik2005, but generalised to any
|
||||
# distribution. r = dR, v = dV, f = probability density function,
|
||||
# f_inv = inverse of f
|
||||
def tables(r, v, f, f_inv):
|
||||
# compute the x_i
|
||||
xvec = [0]*(TABLE_LEN+1)
|
||||
|
||||
xvec[0] = v / f(r)
|
||||
xvec[1] = r
|
||||
|
||||
for i in range(2, TABLE_LEN):
|
||||
last = xvec[i-1]
|
||||
xvec[i] = f_inv(v / last + f(last))
|
||||
|
||||
# cache the f's
|
||||
fvec = [0]*(TABLE_LEN+1)
|
||||
for i in range(TABLE_LEN+1):
|
||||
fvec[i] = f(xvec[i])
|
||||
|
||||
return xvec, fvec
|
||||
|
||||
# Distributions
|
||||
# N(0, 1)
|
||||
def norm_f(x):
|
||||
return exp(-x*x/2.0)
|
||||
def norm_f_inv(y):
|
||||
return sqrt(-2.0*log(y))
|
||||
|
||||
NORM_R = 3.6541528853610088
|
||||
NORM_V = 0.00492867323399
|
||||
|
||||
NORM = tables(NORM_R, NORM_V,
|
||||
norm_f, norm_f_inv)
|
||||
|
||||
# Exp(1)
|
||||
def exp_f(x):
|
||||
return exp(-x)
|
||||
def exp_f_inv(y):
|
||||
return -log(y)
|
||||
|
||||
EXP_R = 7.69711747013104972
|
||||
EXP_V = 0.0039496598225815571993
|
||||
|
||||
EXP = tables(EXP_R, EXP_V,
|
||||
exp_f, exp_f_inv)
|
||||
|
||||
|
||||
# Output the tables/constants/types
|
||||
|
||||
def render_static(name, type, value):
|
||||
# no space or
|
||||
return 'pub static %s: %s =%s;\n' % (name, type, value)
|
||||
|
||||
# static `name`: [`type`, .. `len(values)`] =
|
||||
# [values[0], ..., values[3],
|
||||
# values[4], ..., values[7],
|
||||
# ... ];
|
||||
def render_table(name, values):
|
||||
rows = []
|
||||
# 4 values on each row
|
||||
for i in range(0, len(values), 4):
|
||||
row = values[i:i+4]
|
||||
rows.append(', '.join('%.18f' % f for f in row))
|
||||
|
||||
rendered = '\n [%s]' % ',\n '.join(rows)
|
||||
return render_static(name, '[f64, .. %d]' % len(values), rendered)
|
||||
|
||||
|
||||
with open('ziggurat_tables.rs', 'w') as f:
|
||||
f.write('''// Copyright 2013 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.
|
||||
|
||||
// Tables for distributions which are sampled using the ziggurat
|
||||
// algorithm. Autogenerated by `ziggurat_tables.py`.
|
||||
|
||||
pub type ZigTable = &\'static [f64, .. %d];
|
||||
''' % (TABLE_LEN + 1))
|
||||
for name, tables, r in [('NORM', NORM, NORM_R),
|
||||
('EXP', EXP, EXP_R)]:
|
||||
f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r))
|
||||
for (tabname, table) in zip(TABLE_NAMES, tables):
|
||||
f.write(render_table('ZIG_%s_%s' % (name, tabname), table))
|
|
@ -1 +0,0 @@
|
|||
{"files":{"Cargo.toml":"01199fa6ca6337a7513e9ef8951268b8882347e5affaa50e710ac4960d9c65e0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"0aebc3beb6fc32d6073582d5fea170761689a2c83cddb5436aa26e57b7d04e7b","appveyor.yml":"da991211b72fa6f231af7adb84c9fb72f5a9131d1c0a3d47b8ceffe5a82c8542","benches/base64.rs":"96f7d0c7d260362e41b8cefb4839f1e1b3c18c2f10344f6ccafac7c434f99ca9","benches/hex.rs":"057821307b4b7de02f2c267f9248457386035382916c5afe4b72d6f2e905062c","benches/json.rs":"659f2ae2e1ad5ed022fafce6418d17dfe09c3dcb3f054857dce0effc907da850","src/base64.rs":"57649c590c1fba643ff955910f1d4427feda43414bb0863cd279bea56c3ff178","src/collection_impls.rs":"8ae6bc0d61a4777d834c2b24fa987550cb13c570e1564f87ee32eceff3cb2d5b","src/hex.rs":"a2ba86cf47035b5d9cbf4adf8dc3e941d4e0a6ce1a61a29cbb14ea1fdabac6bb","src/json.rs":"75a788a46612c73bfd14af20fb48855dc8c930747c5255a288d2d09de25ea960","src/lib.rs":"a0e4a368a609f019434e7584f54448cf33ebf3e37e3fb1dd5537d300088184b1","src/serialize.rs":"7ddcc3c32843850e30d05b82a8cda8ae63ec0016e2b0bfbcc46a03ea3ea986e8"},"package":"dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"}
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.24"
|
||||
authors = ["The Rust Project Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/rust-lang/rustc-serialize"
|
||||
homepage = "https://github.com/rust-lang/rustc-serialize"
|
||||
documentation = "https://doc.rust-lang.org/rustc-serialize"
|
||||
description = """
|
||||
Generic serialization/deserialization support corresponding to the
|
||||
`derive(RustcEncodable, RustcDecodable)` mode in the compiler. Also includes
|
||||
support for hex, base64, and json encoding and decoding.
|
||||
"""
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.3"
|
|
@ -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,31 +0,0 @@
|
|||
# rustc-serialize
|
||||
|
||||
> **NOTE**: This crate is deprecated in favor of [`serde`]. No new feature
|
||||
> development will happen in this crate, although bug fixes proposed through PRs
|
||||
> will still be merged. It is very highly recommended by the Rust Library Team
|
||||
> that you use [`serde`], not this crate.
|
||||
|
||||
[`serde`]: https://serde.rs
|
||||
|
||||
Serialization and deserialization support provided by the compiler in the form
|
||||
of `derive(RustcEncodable, RustcDecodable)`.
|
||||
|
||||
[![Linux Build Status](https://travis-ci.org/rust-lang-nursery/rustc-serialize.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustc-serialize)
|
||||
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/ka194de75aapwpft?svg=true)](https://ci.appveyor.com/project/alexcrichton/rustc-serialize)
|
||||
|
||||
[Documentation](https://doc.rust-lang.org/rustc-serialize)
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rustc-serialize = "0.3"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate rustc_serialize;
|
||||
```
|
|
@ -1,17 +0,0 @@
|
|||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
install:
|
||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
|
||||
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
||||
- SET PATH=%PATH%;C:\MinGW\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test --verbose
|
|
@ -1,48 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_to_base64(b: &mut Bencher) {
|
||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
||||
b.iter(|| {
|
||||
s.as_bytes().to_base64(STANDARD);
|
||||
});
|
||||
b.bytes = s.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_from_base64(b: &mut Bencher) {
|
||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
||||
let sb = s.as_bytes().to_base64(STANDARD);
|
||||
b.iter(|| {
|
||||
sb.from_base64().unwrap();
|
||||
});
|
||||
b.bytes = sb.len() as u64;
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn bench_to_base64_large(b: &mut Bencher) {
|
||||
let s: Vec<_> = (0..10000).map(|i| ((i as u32 * 12345) % 256) as u8).collect();
|
||||
b.iter(|| {
|
||||
s.to_base64(STANDARD);
|
||||
});
|
||||
b.bytes = s.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_from_base64_large(b: &mut Bencher) {
|
||||
let s: Vec<_> = (0..10000).map(|i| ((i as u32 * 12345) % 256) as u8).collect();
|
||||
let sb = s.to_base64(STANDARD);
|
||||
b.iter(|| {
|
||||
sb.from_base64().unwrap();
|
||||
});
|
||||
b.bytes = sb.len() as u64;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use test::Bencher;
|
||||
use rustc_serialize::hex::{FromHex, ToHex};
|
||||
|
||||
#[bench]
|
||||
fn bench_to_hex(b: &mut Bencher) {
|
||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
||||
b.iter(|| {
|
||||
s.as_bytes().to_hex();
|
||||
});
|
||||
b.bytes = s.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_from_hex(b: &mut Bencher) {
|
||||
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
|
||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
|
||||
let sb = s.as_bytes().to_hex();
|
||||
b.iter(|| {
|
||||
sb.from_hex().unwrap();
|
||||
});
|
||||
b.bytes = sb.len() as u64;
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use std::string;
|
||||
use rustc_serialize::json::{Json, Parser};
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_streaming_small(b: &mut Bencher) {
|
||||
b.iter( || {
|
||||
let mut parser = Parser::new(
|
||||
r#"{
|
||||
"a": 1.0,
|
||||
"b": [
|
||||
true,
|
||||
"foo\nbar",
|
||||
{ "c": {"d": null} }
|
||||
]
|
||||
}"#.chars()
|
||||
);
|
||||
loop {
|
||||
match parser.next() {
|
||||
None => return,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#[bench]
|
||||
fn bench_small(b: &mut Bencher) {
|
||||
b.iter( || {
|
||||
let _ = Json::from_str(r#"{
|
||||
"a": 1.0,
|
||||
"b": [
|
||||
true,
|
||||
"foo\nbar",
|
||||
{ "c": {"d": null} }
|
||||
]
|
||||
}"#);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_decode_hex_escape(b: &mut Bencher) {
|
||||
let mut src = "\"".to_string();
|
||||
for _ in 0..10 {
|
||||
src.push_str("\\uF975\\uf9bc\\uF9A0\\uF9C4\\uF975\\uf9bc\\uF9A0\\uF9C4");
|
||||
}
|
||||
src.push_str("\"");
|
||||
b.iter( || {
|
||||
let _ = Json::from_str(&src);
|
||||
});
|
||||
}
|
||||
|
||||
fn big_json() -> string::String {
|
||||
let mut src = "[\n".to_string();
|
||||
for _ in 0..500 {
|
||||
src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
|
||||
[1,2,3]},"#);
|
||||
}
|
||||
src.push_str("{}]");
|
||||
return src;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_streaming_large(b: &mut Bencher) {
|
||||
let src = big_json();
|
||||
b.iter( || {
|
||||
let mut parser = Parser::new(src.chars());
|
||||
loop {
|
||||
match parser.next() {
|
||||
None => return,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#[bench]
|
||||
fn bench_large(b: &mut Bencher) {
|
||||
let src = big_json();
|
||||
b.iter( || { let _ = Json::from_str(&src); });
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче