除法的商数和余数大整数与一个大整数的乘积

Quotient and remainder for division a product of big integers by a big integer

本文关键字:整数 一个 余数大 除法      更新时间:2023-10-16
long long signed  A, B, C;

long long unsigned A, B, C;

我需要计算表达式A * B / C的商和余数,其中A, B, C是大整数,因此A * B的乘积导致溢出,A < CB < C。禁止使用浮点数和使用第三方库。怎样才能做到呢?

A*B/C的余数等于A/CB/C余数的乘积再模C

//编辑:Ups,没有看到条件A<C, B<C。在这种情况下,尝试这样做:

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

结果tmp应该是您所寻找的余数。只要所有的输入都是正的,我们在有符号的情况下这样做就可以。也许它也可以用于unsigned,但没有检查。

当然你需要一些花哨的函数来检查oveflow条件。

对于商,你可以求出A/C,然后乘以B,对吗?

用任意大整数做乘法其实很简单:你只要像在学校时那样在纸上手抄就行了。但是,与以10为基数的十进制数字不同,您可以使用字节或整数。

例如:

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

现在您可以循环遍历数组并以更小的步骤执行乘法。

我相信一个好的开始应该是使用c/c++与gmp。GMP是一个任意精度的库,它为任意精度实现了所有这些操作。

编辑:(没有第三方库)

我对它的第二个想法(gmp之后)是质因数分解。你需要一个算法。你用因子分解、b因子分解和c因子分解创建一个向量,它们有因子分解的素数列表。然后将A/B中的质数与C中的质数进行比较,并开始将它们从A/B和C向量中删除。在测试完所有元素之后,将vector的所有元素相乘,然后进行常规除法。

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

例如:

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,这是一个相当简单的数学挑战:)

必须将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是不可能的,因为你最初的要求。

相关文章: