Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 大整数和双整数之间的乘法_C++_C++11_Integer_Double_Gmp - Fatal编程技术网

C++ 大整数和双整数之间的乘法

C++ 大整数和双整数之间的乘法,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!!!由于精度损失,结果也

我正在用gmp管理一些大整数(128~256位)。我想将它们相乘,得到接近1的双精度(0.1
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(...)