P
Paul
Paul said:Ttodir said:Hello,
I need a fast way to calculate (a * b) % B, with the following
constraints:
- a, b, B are int
- B = 10^N , N>0 arbitrary (B always fits in an int)
- the result must be valid even if the multiplication overflows
- portable code, no assumptions on the sizeof(int) and no types larger
than int can be used.
Any help will be much appreciated.
If you convert the integer into an array such that 543 was {5,4,3}, or in
a vector you can do it.
Here is an example of how to overcome such a problem using vectors, it may
not be perfect but it should give you the idea:
#include <iostream>
#include <vector>
typedef unsigned int uint;
typedef std::vector<uint> v_uint;
v_uint foo(v_uint v1, v_uint v2, uint N){
uint pow = N;
v_uint retv;
uint carry=0;
uint temp_prod =0;
//v1 must contain the largest.
for(int i=0; i<v1.size() && pow>=10; i++, pow/=10){
for (int j=i; j>=0; j-- ){
if(i<v2.size()){
temp_prod += v1[i-j]* v2[j];
}
if( i>v2.size() ){
if( (i-j)<v2.size() )
temp_prod+= v1[j]* v2[i-j];
}
}
temp_prod +=carry;
retv.push_back( temp_prod%10 );
carry = temp_prod/10;
temp_prod=0;
}
return retv;
}
int main(){
uint N = 100000;
v_uint a(5, 3);
v_uint b(4,5);
v_uint v = foo(a,b, N);
for(int i=0; i<v.size() ; i++){
std::cout<< v << std::endl;
}
std::cout<< (33333*5555)%100000;
}
Previous code was a bit buggy I will include a revised version which
includes a couple of helper functions.
Obviously there is room for improvement but it seems to work ok.
#include <iostream>
#include <vector>
typedef unsigned int uint;
typedef std::vector<uint> v_uint;
v_uint int_to_vect(uint arg, uint base){
v_uint retv;
while(arg){
retv.push_back(arg%base);
arg/=base;
}
return retv;
}
uint vect_to_int(v_uint v, uint B){
uint temp=0;
uint pow=1;
for (int i=0; i<v.size(); i++, pow*=B){
temp+=v*pow;
}
return temp;
}
uint power_mag(uint B, uint pow){
uint temp=(pow)?B:1;
for (int i=1; i<pow; i++){
if(temp*B>temp)
temp*=B;
}
return temp;
}
uint foo(uint a, uint b, uint B, uint p){
v_uint v1= int_to_vect((a>=b)?a:b, B);
v_uint v2= int_to_vect((a>=b)?b:a, B);
int v1s= v1.size();
int v2s= v2.size();
uint pow = power_mag(B,p);
v_uint retv;
uint carry=0;
uint temp_prod =0;
for(int i=0; i<(v1s+v2s-1) && pow>=B; i++, pow/=B){
for (int j=i; j>=0; j-- ){
if(i<v2s){
temp_prod += v1[i-j]* v2[j];
}
if( i>=v2s && i<v1s && (i-j)<v2s ){
temp_prod += v1[j]* v2[i-j];
}
if(i>=v1s && j<(v2s-1)-(i-v1s) ){
temp_prod+= v1[v1s-1-j] * v2[j+(i-(v1s-1))];
}
}
temp_prod +=carry;
retv.push_back( temp_prod%B );
carry = temp_prod/B;
temp_prod=0;
}
while(pow>=B && carry){
retv.push_back(carry%B);
carry/=B;
pow/=B;
}
return vect_to_int(retv,B);
}
int main(){
uint B = 8; //Base for divisor
uint pow = 6; //Power for divisor
uint x = foo(96,9677,B, pow);
//Example (9677*96)%8^6
}
Please let me know if you find a better way of doing it, It is alot simpler
if B==2 but unfortunately your requirement was B==10.