用于除以大整数乘积的乘积的商和余数

时间:2011-11-02 07:53:20

标签: c++ algorithm overflow biginteger

long long signed  A, B, C;

long long unsigned A, B, C;

我需要计算表达式A * B / C的商和余数,其中ABC是大整数,因此产品A * B会导致溢出并A < CB < C。禁止使用浮点数和使用第三方库。怎么做?

6 个答案:

答案 0 :(得分:3)

A*B/C的余数等于余数A/CB/CC的乘积。

//编辑:上传,看不到条件A<CB<C。在这种情况下尝试这样的事情:

tmp = A;
for (var i = 1; i<=B; i++)
{
   if (tmp + A == overflow || tmp + A >= C)
      tmp -= C;
   tmp += A;
}

结果tmp应该是您寻求的余数。只要所有输入都是正数,我们就会在签名情况下这样做。也许它对无符号也有用,但是没有检查它。

当然,您需要一些奇特的功能来检查oveflow条件。

至于商,您只需评估A/C,然后将其乘以B,不是吗?

答案 1 :(得分:3)

使用任意大整数进行乘法非常简单:你完全像在scool时那样做,并在纸上手工完成。但是,不是在基数10中使用十进制数,而是使用字节或整数。

例如:

A = 12340;
B = 56789;
aa = new byte[] { A/256, A%256 };
bb = new byte[] { B/256, B%256 };

现在你可以遍历数组并以较小的步长进行乘法。

答案 2 :(得分:1)

我认为一个好的开始应该是使用带有gmp的c / c ++。 gmp是一个任意精度库,它具有为任意精度实现的所有这些操作。它适用于整数和浮点数。

编辑:(没有第三方库)

我的第二个虽然关于它(在gmp之后)是素数分解。你需要一个算法。您可以使用Afactorization,Bfactorization和Cfactorization创建一个向量,该向量具有分解的素数列表。然后你测试A / B的素数与C中的素数,并开始删除它们的A / B和C矢量。在对所有这些元素进行测试之后,将所有向量的成员相乘并进行正常除法。

答案 3 :(得分:1)

对于没有64位算术的32位数乘法,有Schrage的方法。也许你可以把它扩展到64位乘法。

答案 4 :(得分:1)

你必须将A和B分成上下32位部分

A = Au * (1<<32) + Al
B = Bu * (1<<32) + Bl

(计算为Au=A>>32; Al=A&(1<<(32)-1;)并分别考虑这些部分的产品:

A*B = Au*Bu * (1<<64) + (Au*Bl+Al*Bu) * (1<<32) + Al*Bl

接下来你必须将每个术语除以C并累加商和余数(小心避免溢出!)。特别是,由于您的初始要求,Au * Bu> C是不可能的。

答案 5 :(得分:1)

例如:

typedef long long ll;

const ll base = 1000*1000*1000; // 10^9 for example, could be also 1<<32 
               // or smth convenient, the goal is to store
               // the numbers and a result in 'base'-based numerical system
               // to avoid overflow

pair<ll, ll> p1 = make_pair( A/base, A%base ); // store the numbers in 
pair<ll, ll> p2 = make_pair( B/base, B%base ); // 'base'-based numerical system

vector<ll> v1(4);
v1[ 0 ] = p1.second * p2.second;
v1[ 1 ] = p1.first * p2.second + v1[ 0 ] / base; v1[ 0 ] %= base;
v1[ 2 ] = v1[ 1 ] / base; v1[ 1 ] %= base;

vector<ll> v2(4);
v2[ 1 ] = p1.second * p2.first;
v2[ 2 ] = p1.first * p2.first + v2[ 1 ] / base; v2[ 1 ] %= base;
v2[ 3 ] = v2[ 1 ] / base; v2[ 2 ] %= base;

ll tmp = 0;
for( i = 0; i < 4; ++i )
{
    v1[ i ] = v1[ i ] + v2[ i ] + tmp;
    tmp = v1[ i ] / base;
    v1[ i ] %= base;
}

现在v1存储以基数10 ^ 9表示的A * B的值。剩下的就是仔细地将它划分为C,这是一个简单的数学挑战:)