乘以和比较大数字

时间:2015-06-22 19:38:02

标签: c++ algorithm optimization biginteger

我有这个问题: 有N行数的K行(32位)。我必须选择具有最大数字乘积的行。

主要问题是N可以达到20。 我试图用对数来做这个:

ld sum = 0, max = 0;
int index = 0;

for(int i = 0; i < k; i ++) { // K lines
    sum = 0, c = 0;
    for(int j = 0; j < n; j ++) { // N numbers
        cin >> t;
        if(t < 0)
            c++; // If the number is less than 0 i memorize it

        if(t == 1 || t == -1) { // if numbers = 1 OR -1
            sum += 0.00000001; // Because log(1) = 0
            if(t == -1)
                c ++;
        }
        else if(t == 0) { // if some number is equal to zero then the sum is = 0
            sum = 0;
            break;
        }
        else {
            sum += log10(fabs(t));
        }
    }

    if(c % 2 == 1) // if c is odd than multiply by -1
        sum *= -1;

    if(sum >= max) { 
        max = sum;
        index = i;
    }
    if((sum - max) < eps) { // if sum is equal to max i'm also have to choose it
        max = sum;
        index = i;
    }
}
cout << index + 1 << endl;

该程序适用于50%的测试用例。有没有办法优化我的代码?

3 个答案:

答案 0 :(得分:1)

在t == -1的情况下,你将c增加两次。

答案 1 :(得分:0)

我认为这一行肯定是错误的:

if(c % 2 == 1) // if c is odd than multiply by -1
    sum *= -1;

如果您的产品在[0,1]范围内,则其对数将为负数,这将使其为正数。我认为你应该把它分开。

答案 2 :(得分:0)

如果你想避免bignum libs你可以利用它,如果你乘以b1b2位数,那么结果是b1+b2位长

  1. 所以只需将一行中所有被乘数的位数相加

    • 并比较
    • 记住某些数组中的结果

      int bits(DWORD p) // count how many bits is p DWORD is 32bit unsigned int
          {
          DWORD m=0x80000000; int b=32;
          for (;m;m>>=1,b--)
           if (p>=m) break;
          return b;
          } 
      
  2. index按结果位计数降序排序

  3. 如果排序后的第一个bitcount也是最大值,那么它的行就是答案
  4. 如果你有多个最大值(更多行具有相同的bitcount并且也是最大值)
    • 只有这样你才能将它们相乘
  5. 现在乘法

    • 你知道应该一次乘以所有最大线
    • 每次所有子结果都可以被相同的素数整除
    • 除以它
    • 这样结果将被截断为更少的位数
    • 所以它应该适合64位值
    • 你应该查看最高为sqrt(最大值)的素数
    • 当您的最大值为32位时,请检查素数最多为65536
    • 所以你可以制作一个静态的素数表来检查以加快速度
    • 也没有必要检查比实际子结果更大的素数
    • 如果你知道如何通过Eratosthenes筛子极其加速
    • 但是你需要在每次除法后跟踪索引偏移并使用周期性的筛选表,这有点复杂但可行
    • 如果你没有检查所有素数而只选择少数几个素数
    • 然后结果仍然会溢出
    • 所以你也应该处理它(抛出一些错误或其他东西)
    • 或将所有子结果除以某个值,但这会使结果无效

    另一种乘法方法

    • 您还可以按值
    • 对乘数进行排序
    • 并检查所有最大行中是否存在某些
    • 如果是,则将其更改为一个(或从列表中删除)
    • 这可以与之前的方法结合使用

    bignum multiplication

    • 你可以制作自己的bignum乘法
    • 结果是最大20 * 32 = 640位
    • 所以结果将是无符号整数数组(位宽8,16,32 ......无论你喜欢什么)
    • 您也可以将数字作为字符串处理
    • 查看此处了解如何计算fast exact bignum square in C++
    • 它还包含乘法方法
    • NTT based Schönhage-Strassen multiplication in C++
    • 但对于像你这样的小数字来说会慢一点
    • 最后你需要比较结果
    • 所以比较来自MSW做的LSW和哪一行中有更大的数字就是最大线
    • (MSW是最重要的词,LSW是最不重要的词)