1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
use rand::Rng;
use std::cmp::Ordering;
use crate::number::*;
pub fn rand_f64() -> f64 {
rand::thread_rng().gen_range(0.0..1.0)
}
impl Integer {
pub fn abs(&self) -> Integer {
let mut res = self.clone();
res.negative = false;
res
}
pub fn fact(&self) -> Result<Integer, String> {
let one: Integer = Integer::new(false, vec!(1));
let mut res = one.clone();
let mut cpy = self.clone();
while !cpy.is_zero() {
res *= &cpy;
cpy -= &one;
}
Ok(res)
}
/*
╒═══════════════════╕
============================================= │ AUX MATHEMATICS │ =============================================
╘═══════════════════╛
*/
pub fn rand_int_range(from: &Integer, to: &Integer) -> Result<Integer, String> {
let mut rng = rand::thread_rng();
let mut rand_limbs_range = |f: &Vec<u64>, t: &Vec<u64>| {
let max_bits = t.len();
let min_bits = f.len();
let mut res = vec!(0; max_bits);
// First number
if max_bits > min_bits {
res[max_bits - 1] = rng.gen_range(0..=*t.last().unwrap());
} else {
res[max_bits - 1] = rng.gen_range(*f.last().unwrap()..=*t.last().unwrap());
}
let mut zeroed = res[max_bits - 1] == 0;
// First zeroes
for i in res.iter_mut().take(max_bits - 1).skip(min_bits) {
let digit = rng.gen::<u64>();
zeroed &= digit == 0;
*i = digit;
}
// Next zeroes
if zeroed {
for i in 0..(min_bits - 1) {
res[i] = rng.gen_range(f[i]..=u64::MAX);
}
} else {
for i in res.iter_mut().take(min_bits - 1) {
*i = rng.gen::<u64>();
}
}
res
};
if from >= to {
return Err(format!("Invalid range for random generation [{}, {}]", String::from(from), String::from(to)));
}
match (from.negative, to.negative) {
(false, false) => Ok(Integer::new(false, rand_limbs_range(&from.limbs, &to.limbs))),
(true, true) => Ok(Integer::new(true, rand_limbs_range(&to.limbs, &from.limbs))),
(true, false) => {
let limbs;
if let Ordering::Less = comp_limbs(&from.limbs, &to.limbs) {
limbs = rand_limbs_range(&vec!(0), &to.limbs);
} else {
limbs = rand_limbs_range(&vec!(0), &from.limbs);
}
let mut res = Integer::new(false, limbs);
// Set as negative uniformly
if &res > to {
res.negative = true;
} else if &res <= from {
res.negative = rng.gen::<bool>();
}
Ok(res)
},
_ => unreachable!()
}
}
}
/*
╒═════════╕
============================================= │ TESTS │ =============================================
╘═════════╛
*/
#[cfg(test)]
mod tests {
use crate::number::*;
use num_bigint::BigInt;
use rand::distributions::{
Distribution,
Uniform
};
#[test]
fn integer_exponentiation() {
let mut rng = rand::thread_rng();
let distribution = Uniform::from(1..5);
for _ in 0..100{
let a = Integer::rand_with_size(distribution.sample(&mut rng), false);
let b = Integer::rand_with_size(distribution.sample(&mut rng), false);
let a2 = a.to_string().parse::<BigInt>().unwrap();
assert_eq!(pow(&a, &b).unwrap().to_string(), a2.pow(b.limbs[0] as u32).to_string());
}
}
/*
TODO: check this
#[test]
fn integer_modular_exponentiation() {
let mut rng = rand::thread_rng();
let distribution = Uniform::from(1..30);
for _ in 0..10000{
let a = Integer::rand_with_size(distribution.sample(&mut rng), false);
let mut b = Integer::rand_with_size(distribution.sample(&mut rng), false);
let mut m = Integer::rand_with_size(distribution.sample(&mut rng), false);
while b.is_zero() {
b = Integer::rand_with_size(distribution.sample(&mut rng), false);
}
while m.is_zero() {
m = Integer::rand_with_size(distribution.sample(&mut rng), false);
}
println!("{}, {}, {}", a, b, m);
let a2 = a.to_string().parse::<BigInt>().unwrap();
let b2 = b.to_string().parse::<BigInt>().unwrap();
let m2 = m.to_string().parse::<BigInt>().unwrap();
assert_eq!(modpow(&a, &b, &m).unwrap().to_string(), a2.modpow(&b2, &m2).to_string());
}
}*/
}