C++ 大整数和双整数之间的乘法
我正在用gmp管理一些大整数(128~256位)。我想将它们相乘,得到接近1的双精度(0.1C++ 大整数和双整数之间的乘法,c++,c++11,integer,double,gmp,C++,C++11,Integer,Double,Gmp,我正在用gmp管理一些大整数(128~256位)。我想将它们相乘,得到接近1的双精度(0.1=0;i--)//进位 { 双aa,bb; cc+=q[i]; c[i]=cc&255; cc>>=8; } } _N是每个大整数的位数/8,大整数是_N字节数组,其中第一个字节是MSB(最高有效字节),最后一个字节是LSB(最低有效字节) 函数不处理signum,但它只是一个if和一些要添加的xor/inc 麻烦的是,double的精度很低,即使是您的数字1.23456789!!!由于精度损失,结果也
int i = 1000000000000000000 * 1.23456789
我在gmp文档中进行了搜索,但没有找到用于此的函数,因此我最终编写了此代码,该代码似乎运行良好:
mpz_mult_d(mpz_class & r, const mpz_class & i, double d, int prec=10) {
if (prec > 15) prec=15; //avoids overflows
uint_fast64_t m = (uint_fast64_t) floor(d);
r = i * m;
uint_fast64_t pos=1;
for (uint_fast8_t j=0; j<prec; j++) {
const double posd = (double) pos;
m = ((uint_fast64_t) floor(d * posd * 10.)) -
((uint_fast64_t) floor(d * posd)) * 10;
pos*=10;
r += (i * m) /pos;
}
}
mpz_mult_d(mpz_class&r,const mpz_class&i,双d,int prec=10){
如果(prec>15)prec=15;//避免溢出
uint_fast64_t m=(uint_fast64_t)层(d);
r=i*m;
uint_fast64_t pos=1;
对于(uint_fast8_t j=0;j这就是您想要的:
// BYTE lint[_N] ... lint[0]=MSB, lint[_N-1]=LSB
void mul(BYTE *c,BYTE *a,double b) // c[_N]=a[_N]*b
{
int i; DWORD cc;
double q[_N+1],aa,bb;
for (q[0]=0.0,i=0;i<_N;) // mul,carry down
{
bb=double(a[i])*b; aa=floor(bb); bb-=aa;
q[i]+=aa; i++;
q[i]=bb*256.0;
}
cc=0; if (q[_N]>127.0) cc=1.0; // round
for (i=_N-1;i>=0;i--) // carry up
{
double aa,bb;
cc+=q[i];
c[i]=cc&255;
cc>>=8;
}
}
//字节lint[\N]…lint[0]=MSB,lint[\N-1]=LSB
void mul(字节*c,字节*a,双b)//c[\N]=a[\N]*b
{
国际一级;德沃德cc;
双q[_N+1],aa,bb;
对于(q[0]=0.0,i=0;i127.0)cc=1.0;//四舍五入
对于(i=\N-1;i>=0;i--)//进位
{
双aa,bb;
cc+=q[i];
c[i]=cc&255;
cc>>=8;
}
}
_N是每个大整数的位数/8,大整数是_N字节数组,其中第一个字节是MSB(最高有效字节),最后一个字节是LSB(最低有效字节)
函数不处理signum,但它只是一个if和一些要添加的xor/inc
麻烦的是,double的精度很低,即使是您的数字1.23456789!!!由于精度损失,结果也不准确(1234387129122386944而不是123456780000000000)我认为我的代码比你的更快,更精确,因为我不需要将数字mul/mod/div乘以10,而是在可能的情况下使用位移位,不是按10位,而是按256位(8位)。如果你需要比使用长算术更高的精度,你可以通过使用更大的数字(16,32,…位)来加快代码的速度
我的精确天文计算的长算法通常是固定点256。256位数字由2*8 DWORDs+符号组成,但当然要慢得多,而且一些测角函数的实现非常棘手,但如果你只需要基本函数而不需要编码,你自己的长算法就不那么难了
也可以说,如果你想要数字是可读的,在速度和大小之间妥协是很好的,不要考虑使用二进制编码的数字,但是BCD编码的数字< /P> < P>我不太熟悉C++或GMP,我可以建议没有语法错误的源代码,但是你所做的比它应该和可以介绍的要复杂得多。不必要的近似
相反,我建议您编写函数mpz\u mult\u d()
,如下所示:
mpz_mult_d(mpz_class & r, const mpz_class & i, double d) {
d = ldexp(d, 52); /* exact, no overflow because 1 <= d <= 10 */
unsigned long long l = d; /* exact because d is an integer */
p = l * i; /* exact, in GMP */
(quotient, remainder) = p / 2^52; /* in GMP */
PS:我通过随机浏览找到了你的问题,但如果你把它标记为“浮点”,那么比我更有能力的人可以很快回答它。试试这个策略:
将整数值转换为大浮点
将双精度值转换为大浮点值
制作产品
将结果转换为整数
mpf_set_z(...)
mpf_set_d(...)
mpf_mul(...)
mpz_set_f(...)
这是一个针对,而不是针对StackOverflow的问题:)哦,对不起,我不知道那个分支。不过,这只是我解决一个非常精确的问题的方法。请考虑回答一般问题,最后只对代码进行注释。谢谢!如果你需要一个近似值,为什么不把大整数转换成双?GMP支持任意精度的有理数和浮点数。将两个值转换为其中一种格式,让GMP进行乘法运算。您应该查看MPFR(),它相当于GMP中的浮点数。它与GMP一样易于使用。
mpf_set_z(...)
mpf_set_d(...)
mpf_mul(...)
mpz_set_f(...)