非常大的A除以非常大的B
very large A divide at a very large B
我已经编写了一个长数的乘法、长数的加法、长数的减法和长数的除法的函数。但是除法需要很长时间,如何改进呢?下面是我的代码:
/// removes unnecessary zeros
vector<int> zero(vector<int> a)
{
bool f=false;
int size=0;
for(int i=a.size()-1;i>=0;i--)
{
if(a[i]!=0)
{
f=true;
size=i;
break;
}
}
if(f)
{
vector<int> b(size+1);
for(int i=0;i<size+1;i++)
b[i]=a[size-i];
return b;
}
else
return a;
}
/// a+b
vector<int> sum(vector<int> a,vector<int> b)
{
if(a.size()>b.size())
{
vector<int> rez(3000);
int a_end=a.size()-1;
int remainder=0,k=0,ans;
for(int i=b.size()-1;i>=0;i--)
{
ans=a[a_end]+b[i]+remainder;
if(ans>9)
{
rez[k]=ans%10;
remainder=ans/10;
}
else
{
rez[k]=ans;
remainder=0;
}
k++;
a_end--;
}
int kk=k;
for(int i=a.size();i>kk;i--)
{
ans=a[a_end]+remainder;
if(ans>9)
{
rez[k]=ans%10;
remainder=ans/10;
}
else
{
rez[k]=ans;
remainder=0;
}
k++;
a_end--;
}
if(remainder!=0)
rez[k]=remainder;
return zero(rez);
}
else
{
vector<int> rez(3000);
int b_end=b.size()-1;
int remainder=0,k=0,ans;
for(int i=a.size()-1;i>=0;i--)
{
ans=b[b_end]+a[i]+remainder;
if(ans>9)
{
rez[k]=ans%10;
remainder=ans/10;
}
else
{
rez[k]=ans;
remainder=0;
}
k++;
b_end--;
}
int kk=k;
for(int i=b.size();i>kk;i--)
{
ans=b[b_end]+remainder;
if(ans>9)
{
rez[k]=ans%10;
remainder=ans/10;
}
else
{
rez[k]=ans;
remainder=0;
}
k++;
b_end--;
}
if(remainder!=0)
rez[k]=remainder;
return zero(rez);
}
}
/// a & b comparison
int compare(vector<int> a,vector<int> b)
{
if(a.size()>b.size())
return 1;
if(b.size()>a.size())
return 2;
int r=0;
for(int i=0;i<a.size();i++)
{
if(a[i]>b[i])
{
r=1;
break;
}
if(b[i]>a[i])
{
r=2;
break;
}
}
return r;
}
/// a-b
vector<int> subtraction(vector<int> a,vector<int> b)
{
vector<int> rez(1000);
int a_end=a.size()-1;
int k=0,ans;
for(int i=b.size()-1;i>=0;i--)
{
ans=a[a_end]-b[i];
if(ans<0)
{
rez[k]=10+ans;
a[a_end-1]--;
}
else
rez[k]=ans;
k++;
a_end--;
}
int kk=k;
for(int i=a.size();i>kk;i--)
{
ans=a[a_end];
if(ans<0)
{
rez[k]=10+ans;
a[a_end-1]--;
}
else
rez[k]=ans;
k++;
a_end--;
}
return zero(rez);
}
/// a div b
vector<int> div(vector<int> a,vector<int> b)
{
vector<int> rez(a.size());
rez=a;
int comp=-1;
vector<int> count(1000);
vector<int> one(1);
one[0]=1;
while(comp!=0 || comp!=2)
{
comp=compare(rez,b);
if(comp==0)
break;
rez=subtraction(rez,b);
count=sum(count,one);
}
count=sum(count,one);
return count;
}
您的问题是您正在重复地减法,这意味着您正在为大量的数字运行非常大量的迭代。这将导致非常糟糕的性能。
我在年初(在一次单位作业中)就遇到了这个问题。我估计我最初的除法(使用重复减法)需要大约100年才能完成。我实现了长除法(与手工除法相同),相同的计算花费了约5毫秒。不错的进步:)
不幸的是,我已经很多年没用过长除法了,所以我已经忘记怎么做了。我很快找到了我能找到的最专业的网站,试图重新学习,然后实现长除法。我用了这个:http://www.coolmath4kids.com/long-division/long-division-lesson-1.html。是的,没错,哈哈哈。这个网站确实有帮助。我在几个小时内就把算法修好了。
显然你不必使用那个网站,但你必须使你的算法更好。有比长除法更有效的方法,但我发现长除法在效率和易于实现之间取得了很好的平衡。
您的整个大数实现可能相当慢。作为一般规则,您可能应该使用base-216(在32位机器中),而不是使用base-10,也就是说,在机器的每个单词中使用一半的位。
确保乘法运算不会溢出32位寄存器。开始实现一个normalize
函数,该函数将规范化大数(即对于每个存储的数字检查它是否溢出216以及是否将余数应用于下一个数字)。因为数字的范围更大,所以需要更少的内存,以及更少的取模和除法操作。此外,基数是2的幂,模和除法运算要比基数为10的方法快得多。
所有操作基本上都可以按元素执行。加法是保留比两位中较大的一位多一位的数字,然后逐位相加,最后对结果进行规范化。
在除法函数中,它将删除大量的向量复制。目前,您正在创建一个3000 int
的向量,该向量在每次循环迭代中被复制和处理,您可能需要考虑实现一个就地+=(vector,int)
操作,该操作将修改向量,而不是创建一个包含所有复制的新向量。
使用慢速除法算法,也有快速除法算法http://en.wikipedia.org/wiki/Division_%28digital%29
- OpenGL大的3D纹理(>2GB)非常慢
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 为什么std::互斥需要很长的、非常不规则的时间来共享
- G++ C++17 类模板参数推导在非常特殊的情况下不起作用
- 使用浮点数和双精度数的非常小数字的数学
- 在打开多个其他窗口时使用全屏窗口时帧速率非常低
- 我从int x[3]得到的一个非常奇怪的输出;
- 反向迭代器在C++中非常奇怪的行为
- 将非常大的 int 转换为双倍,在某些计算机上会损失精度
- 我的自定义使用 std::unordered_map 的性能非常慢
- ifstream 尝试读取 9 到 13 之间的无符号字符时非常奇怪的行为
- 一个非常简单的win32套接字代码,但工作错误
- 非常快速地阅读 CSV 文件
- max_element() 给出非常奇怪的错误消息
- 将 mmap 内存用于开销非常低的循环缓冲区
- 内存映射文件访问非常慢
- 超过CPU时间限制:当MPI_Sent一个非常大的int*时
- QtWebengine 5.7.1的性能非常慢
- 如何非常快速地将数字添加到 Vector 中的一系列元素中
- 我在运行函数 GetVolumeInformation() 时得到非常随机的结果