Skip to content

Commit cdd017e

Browse files
author
Andronik Ordian
committed
uint: fast path for mul by u64
1 parent 2f2997c commit cdd017e

File tree

1 file changed

+88
-73
lines changed

1 file changed

+88
-73
lines changed

uint/src/uint.rs

Lines changed: 88 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -303,16 +303,63 @@ macro_rules! impl_mul_from {
303303
result
304304
}
305305
}
306+
307+
impl $crate::core_::ops::MulAssign<$other> for $name {
308+
fn mul_assign(&mut self, other: $other) {
309+
let result = *self * other;
310+
*self = result
311+
}
312+
}
306313
}
307314
}
308315

309316
#[macro_export]
310317
#[doc(hidden)]
311-
macro_rules! impl_mulassign_from {
312-
($name: ident, $other: ident) => {
318+
macro_rules! impl_mul_for_primitive {
319+
($name: ty, $other: ident) => {
320+
impl $crate::core_::ops::Mul<$other> for $name {
321+
type Output = $name;
322+
323+
fn mul(self, other: $other) -> $name {
324+
let (result, carry) = self.overflowing_mul_u64(other as u64);
325+
panic_on_overflow!(carry > 0);
326+
result
327+
}
328+
}
329+
330+
impl<'a> $crate::core_::ops::Mul<&'a $other> for $name {
331+
type Output = $name;
332+
333+
fn mul(self, other: &'a $other) -> $name {
334+
let (result, carry) = self.overflowing_mul_u64(*other as u64);
335+
panic_on_overflow!(carry > 0);
336+
result
337+
}
338+
}
339+
340+
impl<'a> $crate::core_::ops::Mul<&'a $other> for &'a $name {
341+
type Output = $name;
342+
343+
fn mul(self, other: &'a $other) -> $name {
344+
let (result, carry) = self.overflowing_mul_u64(*other as u64);
345+
panic_on_overflow!(carry > 0);
346+
result
347+
}
348+
}
349+
350+
impl<'a> $crate::core_::ops::Mul<$other> for &'a $name {
351+
type Output = $name;
352+
353+
fn mul(self, other: $other) -> $name {
354+
let (result, carry) = self.overflowing_mul_u64(other as u64);
355+
panic_on_overflow!(carry > 0);
356+
result
357+
}
358+
}
359+
313360
impl $crate::core_::ops::MulAssign<$other> for $name {
314361
fn mul_assign(&mut self, other: $other) {
315-
let result = *self * other;
362+
let result = *self * (other as u64);
316363
*self = result
317364
}
318365
}
@@ -321,15 +368,9 @@ macro_rules! impl_mulassign_from {
321368

322369
#[inline(always)]
323370
#[doc(hidden)]
324-
pub fn mul_u32(a: (u64, u64), b: u64, carry: u64) -> (u64, u64) {
325-
let upper = b * a.0;
326-
let lower = b * a.1;
327-
328-
let (res1, overflow1) = lower.overflowing_add(upper << 32);
329-
let (res2, overflow2) = res1.overflowing_add(carry);
330-
331-
let carry = (upper >> 32) + overflow1 as u64 + overflow2 as u64;
332-
(res2, carry)
371+
pub fn mul_u64(a: u64, b: u64, carry: u64) -> (u64, u64) {
372+
let (hi, lo) = split_u128(u128::from(a) * u128::from(b) + u128::from(carry));
373+
(lo, hi)
333374
}
334375

335376
#[inline(always)]
@@ -428,8 +469,8 @@ macro_rules! construct_uint {
428469

429470
let mut res = Self::default();
430471
for b in value.bytes().map(|b| b - 48) {
431-
let (r, overflow) = res.overflowing_mul_u32(10);
432-
if overflow {
472+
let (r, overflow) = res.overflowing_mul_u64(10);
473+
if overflow > 0 {
433474
return Err($crate::FromDecStrErr::InvalidLength);
434475
}
435476
let (r, overflow) = r.overflowing_add(b.into());
@@ -512,6 +553,15 @@ macro_rules! construct_uint {
512553
return true;
513554
}
514555

556+
// Whether this fits u64.
557+
#[inline]
558+
fn fits_word(&self) -> bool {
559+
let &$name(ref arr) = self;
560+
for i in 1..$n_words { if arr[i] != 0 { return false; } }
561+
return true;
562+
}
563+
564+
515565
/// Return the least number of bits needed to represent the number
516566
#[inline]
517567
pub fn bits(&self) -> usize {
@@ -734,6 +784,11 @@ macro_rules! construct_uint {
734784
/// Multiply with overflow, returning a flag if it does.
735785
#[inline(always)]
736786
pub fn overflowing_mul(self, other: $name) -> ($name, bool) {
787+
// Fast path if other fits u64
788+
if other.fits_word() {
789+
let (res, carry) = self.overflowing_mul_u64(other.low_u64());
790+
return (res, carry > 0);
791+
}
737792
uint_overflowing_mul!($name, $n_words, self, other)
738793
}
739794

@@ -788,20 +843,18 @@ macro_rules! construct_uint {
788843
}
789844
}
790845

791-
/// Overflowing multiplication by u32.
792-
fn overflowing_mul_u32(self, other: u32) -> (Self, bool) {
793-
let $name(ref arr) = self;
794-
let mut ret = [0u64; $n_words];
795-
let mut carry = 0;
796-
let o = other as u64;
846+
/// Overflowing multiplication by u64.
847+
/// Returns the result and carry.
848+
fn overflowing_mul_u64(mut self, other: u64) -> (Self, u64) {
849+
let mut carry = 0u64;
797850

798-
for i in 0..$n_words {
799-
let (res, carry2) = $crate::mul_u32($crate::split(arr[i]), o, carry);
800-
ret[i] = res;
801-
carry = carry2;
851+
for d in self.0.iter_mut() {
852+
let (res, c) = $crate::mul_u64(*d, other, carry);
853+
*d = res;
854+
carry = c;
802855
}
803856

804-
($name(ret), carry > 0)
857+
(self, carry)
805858
}
806859

807860
/// Converts from big endian representation bytes in memory.
@@ -950,56 +1003,18 @@ macro_rules! construct_uint {
9501003
}
9511004
}
9521005

953-
// specialization for u32
954-
impl $crate::core_::ops::Mul<u32> for $name {
955-
type Output = $name;
956-
957-
fn mul(self, other: u32) -> $name {
958-
let (ret, overflow) = self.overflowing_mul_u32(other);
959-
panic_on_overflow!(overflow);
960-
ret
961-
}
962-
}
963-
964-
impl<'a> $crate::core_::ops::Mul<u32> for &'a $name {
965-
type Output = $name;
966-
967-
fn mul(self, other: u32) -> $name {
968-
*self * other
969-
}
970-
}
971-
972-
impl $crate::core_::ops::MulAssign<u32> for $name {
973-
fn mul_assign(&mut self, other: u32) {
974-
let result = *self * other;
975-
*self = result
976-
}
977-
}
978-
9791006
// all other impls
980-
impl_mul_from!($name, u8);
981-
impl_mul_from!($name, u16);
982-
impl_mul_from!($name, u64);
983-
impl_mul_from!($name, usize);
984-
985-
impl_mul_from!($name, i8);
986-
impl_mul_from!($name, i16);
987-
impl_mul_from!($name, i64);
988-
impl_mul_from!($name, isize);
989-
9901007
impl_mul_from!($name, $name);
991-
992-
impl_mulassign_from!($name, u8);
993-
impl_mulassign_from!($name, u16);
994-
impl_mulassign_from!($name, u64);
995-
impl_mulassign_from!($name, usize);
996-
997-
impl_mulassign_from!($name, i8);
998-
impl_mulassign_from!($name, i16);
999-
impl_mulassign_from!($name, i64);
1000-
impl_mulassign_from!($name, isize);
1001-
1002-
impl_mulassign_from!($name, $name);
1008+
impl_mul_for_primitive!($name, u8);
1009+
impl_mul_for_primitive!($name, u16);
1010+
impl_mul_for_primitive!($name, u32);
1011+
impl_mul_for_primitive!($name, u64);
1012+
impl_mul_for_primitive!($name, usize);
1013+
impl_mul_for_primitive!($name, i8);
1014+
impl_mul_for_primitive!($name, i16);
1015+
impl_mul_for_primitive!($name, i32);
1016+
impl_mul_for_primitive!($name, i64);
1017+
impl_mul_for_primitive!($name, isize);
10031018

10041019
impl<T> $crate::core_::ops::Div<T> for $name where T: Into<$name> {
10051020
type Output = $name;

0 commit comments

Comments
 (0)