Skip to content

Commit f496ab6

Browse files
committed
num: Slightly optimize bigint
1 parent 5cd17b8 commit f496ab6

File tree

1 file changed

+32
-44
lines changed

1 file changed

+32
-44
lines changed

src/libnum/bigint.rs

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ A `BigDigit` is half the size of machine word size.
4747
pub type BigDigit = u32;
4848

4949
pub static ZERO_BIG_DIGIT: BigDigit = 0;
50+
static ZERO_VEC: [BigDigit, ..1] = [ZERO_BIG_DIGIT];
5051

5152
pub mod BigDigit {
5253
use super::BigDigit;
@@ -140,37 +141,28 @@ impl Num for BigUint {}
140141

141142
impl BitAnd<BigUint, BigUint> for BigUint {
142143
fn bitand(&self, other: &BigUint) -> BigUint {
143-
let new_len = cmp::min(self.data.len(), other.data.len());
144-
let anded = vec::from_fn(new_len, |i| {
145-
// i will never be less than the size of either data vector
146-
let ai = self.data[i];
147-
let bi = other.data[i];
148-
ai & bi
149-
});
150-
return BigUint::new(anded);
144+
BigUint::new(self.data.iter().zip(other.data.iter()).map(|(ai, bi)| *ai & *bi).collect())
151145
}
152146
}
153147

154148
impl BitOr<BigUint, BigUint> for BigUint {
155149
fn bitor(&self, other: &BigUint) -> BigUint {
156-
let new_len = cmp::max(self.data.len(), other.data.len());
157-
let ored = vec::from_fn(new_len, |i| {
158-
let ai = if i < self.data.len() { self.data[i] } else { 0 };
159-
let bi = if i < other.data.len() { other.data[i] } else { 0 };
160-
ai | bi
161-
});
150+
let zeros = ZERO_VEC.iter().cycle();
151+
let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) };
152+
let ored = a.data.iter().zip(b.data.iter().chain(zeros)).map(
153+
|(ai, bi)| *ai | *bi
154+
).collect();
162155
return BigUint::new(ored);
163156
}
164157
}
165158

166159
impl BitXor<BigUint, BigUint> for BigUint {
167160
fn bitxor(&self, other: &BigUint) -> BigUint {
168-
let new_len = cmp::max(self.data.len(), other.data.len());
169-
let xored = vec::from_fn(new_len, |i| {
170-
let ai = if i < self.data.len() { self.data[i] } else { 0 };
171-
let bi = if i < other.data.len() { other.data[i] } else { 0 };
172-
ai ^ bi
173-
});
161+
let zeros = ZERO_VEC.iter().cycle();
162+
let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) };
163+
let xored = a.data.iter().zip(b.data.iter().chain(zeros)).map(
164+
|(ai, bi)| *ai ^ *bi
165+
).collect();
174166
return BigUint::new(xored);
175167
}
176168
}
@@ -210,18 +202,15 @@ impl Unsigned for BigUint {}
210202

211203
impl Add<BigUint, BigUint> for BigUint {
212204
fn add(&self, other: &BigUint) -> BigUint {
213-
let new_len = cmp::max(self.data.len(), other.data.len());
205+
let zeros = ZERO_VEC.iter().cycle();
206+
let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) };
214207

215208
let mut carry = 0;
216-
let mut sum = vec::from_fn(new_len, |i| {
217-
let ai = if i < self.data.len() { self.data[i] } else { 0 };
218-
let bi = if i < other.data.len() { other.data[i] } else { 0 };
219-
let (hi, lo) = BigDigit::from_uint(
220-
(ai as uint) + (bi as uint) + (carry as uint)
221-
);
209+
let mut sum: ~[BigDigit] = a.data.iter().zip(b.data.iter().chain(zeros)).map(|(ai, bi)| {
210+
let (hi, lo) = BigDigit::from_uint((*ai as uint) + (*bi as uint) + (carry as uint));
222211
carry = hi;
223212
lo
224-
});
213+
}).collect();
225214
if carry != 0 { sum.push(carry); }
226215
return BigUint::new(sum);
227216
}
@@ -230,22 +219,21 @@ impl Add<BigUint, BigUint> for BigUint {
230219
impl Sub<BigUint, BigUint> for BigUint {
231220
fn sub(&self, other: &BigUint) -> BigUint {
232221
let new_len = cmp::max(self.data.len(), other.data.len());
222+
let zeros = ZERO_VEC.iter().cycle();
223+
let (a, b) = (self.data.iter().chain(zeros.clone()), other.data.iter().chain(zeros));
233224

234225
let mut borrow = 0;
235-
let diff = vec::from_fn(new_len, |i| {
236-
let ai = if i < self.data.len() { self.data[i] } else { 0 };
237-
let bi = if i < other.data.len() { other.data[i] } else { 0 };
226+
let diff: ~[BigDigit] = a.take(new_len).zip(b).map(|(ai, bi)| {
238227
let (hi, lo) = BigDigit::from_uint(
239-
(BigDigit::base) +
240-
(ai as uint) - (bi as uint) - (borrow as uint)
228+
BigDigit::base + (*ai as uint) - (*bi as uint) - (borrow as uint)
241229
);
242230
/*
243231
hi * (base) + lo == 1*(base) + ai - bi - borrow
244232
=> ai - bi - borrow < 0 <=> hi == 0
245233
*/
246234
borrow = if hi == 0 { 1 } else { 0 };
247235
lo
248-
});
236+
}).collect();
249237

250238
assert_eq!(borrow, 0); // <=> assert!((self >= other));
251239
return BigUint::new(diff);
@@ -451,17 +439,18 @@ impl Integer for BigUint {
451439
return (Zero::zero(), Zero::zero(), (*a).clone());
452440
}
453441

454-
let an = a.data.slice(a.data.len() - n, a.data.len());
442+
let an = a.data.tailn(a.data.len() - n);
455443
let bn = *b.data.last().unwrap();
456-
let mut d = ~[];
444+
let mut d = vec::with_capacity(an.len());
457445
let mut carry = 0;
458446
for elt in an.rev_iter() {
459447
let ai = BigDigit::to_uint(carry, *elt);
460448
let di = ai / (bn as uint);
461449
assert!(di < BigDigit::base);
462450
carry = (ai % (bn as uint)) as BigDigit;
463-
d = ~[di as BigDigit] + d;
451+
d.push(di as BigDigit)
464452
}
453+
d.reverse();
465454

466455
let shift = (a.data.len() - an.len()) - (b.data.len() - 1);
467456
if shift == 0 {
@@ -506,10 +495,9 @@ impl Integer for BigUint {
506495
#[inline]
507496
fn is_even(&self) -> bool {
508497
// Considering only the last digit.
509-
if self.data.is_empty() {
510-
true
511-
} else {
512-
self.data[0].is_even()
498+
match self.data.head() {
499+
Some(x) => x.is_even(),
500+
None => true
513501
}
514502
}
515503

@@ -664,12 +652,12 @@ impl ToStrRadix for BigUint {
664652
if base == BigDigit::base {
665653
return fill_concat(self.data, radix, max_len)
666654
}
667-
return fill_concat(convert_base((*self).clone(), base), radix, max_len);
655+
return fill_concat(convert_base(self, base), radix, max_len);
668656

669-
fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] {
657+
fn convert_base(n: &BigUint, base: uint) -> ~[BigDigit] {
670658
let divider = FromPrimitive::from_uint(base).unwrap();
671659
let mut result = ~[];
672-
let mut m = n;
660+
let mut m = n.clone();
673661
while m >= divider {
674662
let (d, m0) = m.div_mod_floor(&divider);
675663
result.push(m0.to_uint().unwrap() as BigDigit);

0 commit comments

Comments
 (0)