什么是2乘以或将数字加到自身更好?大数

时间:2009-08-11 15:13:54

标签: performance biginteger multiplication addition

我需要一些帮助来决定什么是更好的性能明智的。 我正在使用 bigints (超过500万个数字),并且大部分计算(如果不是全部)都是将当前bigint加倍的部分。所以我想知道将乘以每个单元格(bigint的一部分)更好2然后修改它并且你知道其余的更好。或者只是添加更好。

我正在考虑一下实现的简易性(添加2个bigint更复杂然后乘以2),但我更关心的是性能,而不是代码的大小或易于实现。 / p>

其他信息: 我会用 C ++ 编写代码,我对bigints非常熟悉(只是从未遇到过这个问题)。 我不需要任何源代码或类似的东西我只需要一个很好的意见和解释/证明它,因为我需要从一开始做出一个很好的决定,因为项目将相当大,并且主要围绕这部分构建这在很大程度上取决于我现在选择的内容。

感谢。

7 个答案:

答案 0 :(得分:9)

尝试每位移位。这可能是最快的方法。当你将一个整数向左移位时,你将它加倍(乘以2)。如果链中有多个长整数,则需要存储最高位,因为在移位之后,它将消失,并且您需要将其用作下一个长整数的最低有效位。

这实际上并不重要。现代64位计算机可以在对它们进行位移(1个时钟周期)的同时添加两个整数,因此它需要同样长的时间。我建议你尝试不同的方法,然后报告是否有任何重大的时间差异。所有这三种方法都应该易于实现,使用随机数生成器生成5mb的数字也应该很容易。

答案 1 :(得分:5)

要存储一个500万位的整数,你需要相当多的位 - 如果你指的是二进制数字,则需要500万,如果是十进制数字,则需要大约1700万位。假设数字以二进制表示形式存储,并且算术以某种大小的块发生,例如32位或64位。

  • 如果将数字添加到自身,则每个块都会添加到自身以及添加前一个块的进位。任何结转都保留在下一个块中。这是一些额外的操作,还有一些用于跟踪进位的簿记。

  • 如果通过左移乘以2,则为乘法的一个左移操作,一个右移操作+和1以获得进位。携带簿记比较简单。

表面上看,换档版本看起来略快一些。然而,将数量加倍的总成本很大程度上受到数量的影响。一个1700万位的数字超过了cpu的L1缓存,处理时间很可能被内存提取操作所淹没。在现代PC硬件上,内存提取比添加和移位慢几个数量级。

有了这个,你可能想选择一个更容易实现的那个。我倾向于左移版本。

答案 2 :(得分:1)

你试过换位吗?
<<乘以2
>>除以2

答案 3 :(得分:1)

左移一位与乘二乘相同! 这个link解释了机制并举例说明。

int A = 10; //...01010 = 10
int B = A<<1; //..010100 = 20

答案 4 :(得分:0)

如果真的很重要,你需要在各种输入上编写所有三种方法(包括位移!),并对它们进行分析。 (使用小数字,大数字和随机数字,以避免偏差结果。)

对不起“自己动手”的答案,但这确实是最好的方法。没有人比你更关心这个结果,这只会让你成为最好的解决方法。

答案 5 :(得分:0)

  

大多数计算(如果不是全部)都是将当前bigint加倍的部分

如果你的所有计算都在加倍,你为什么不保留一个独特的(基数为2)比例字段?然后只需添加一个到scale,这可能只是一个普通的int。这肯定会比任何奇数百万位的操作更快。

IOW,使用bigfloat。

随机基准

use Math::GMP;
use Time::HiRes qw(clock_gettime CLOCK_REALTIME CLOCK_PROCESS_CPUTIME_ID);

my $n = Math::GMP->new(2);
$n = $n ** 1_000_000;

my $m = Math::GMP->new(2);
$m = $m ** 10_000;

my $str;
for ($bits = 1_000_000; $bits <= 2_000_000; $bits += 10_000) {
    my $start = clock_gettime(CLOCK_PROCESS_CPUTIME_ID);
    $str = "$n" for (1..3);
    my $stop = clock_gettime(CLOCK_PROCESS_CPUTIME_ID);
    print "$bits,@{[($stop-$start)/3]}\n";
    $n = $n * $m;
}

似乎表明某种程度上GMP正在O(n)时间内进行转换(其中n是二进制数中的位数)。这可能是由于特殊情况下有一个1后跟一百万(或两个)零; GNU MP docs说它应该更慢(但仍然优于O(N ^ 2)。

http://img197.imageshack.us/img197/6527/chartp.png

答案 6 :(得分:0)

良好实现multiplication of BigNums是O(N log(N)log(log(N))。加法是O(n)。因此,加到自身应该比加2倍。但是这只是真的如果你将两个任意的bignums相乘;如果你的库知道你将bignum乘以一个小整数,它可以优化为O(n)。

正如其他人所说,比特移位也是一种选择。它也应该是O(n)但是更快的恒定时间。但这只有在你的bignum库支持位移的情况下才有效。