C:处理大数字时避免溢出

时间:2011-02-15 15:10:27

标签: c linux 64-bit overflow

我在C中实现了一些排序算法(排序整数),小心地使用uint64_t来存储与数据大小有关的任何东西(因此也是计数器和东西),因为算法应该是也测试了几千兆整数的数据集。

算法应该没问题,分配的数据量应该没有问题:数据存储在文件中,我们每次只加载很少的块,即使我们将内存缓冲区扼流到任何规模。

使用高达4千兆字节的数据集进行测试(因此16GB的数据)工作正常(排序4Gint需要2228秒,约37分钟),但是当我们超过那个(即:8 Gints)时算法似乎没有停了(现在已经跑了大约16个小时了。)

我担心问题可能是由于整数溢出,也许循环中的计数器存储在32位变量上,或者我们可能正在调用一些与32位整数一起工作的函数。 还有什么呢?

有没有简单的方法来检查运行时是否发生整数溢出?

5 个答案:

答案 0 :(得分:15)

这是特定于编译器的,但如果您正在使用gcc,那么当签名的整数溢出发生时,您可以使用-ftrapv进行编译以发出SIGABRT

例如:

/* compile with gcc -ftrapv <filename> */
#include <signal.h>
#include <stdio.h>
#include <limits.h>

void signalHandler(int sig) {
  printf("Overflow detected\n");
}

int main() {
  signal(SIGABRT, &signalHandler);

  int largeInt = INT_MAX;
  int normalInt = 42;
  int overflowInt = largeInt + normalInt;  /* should cause overflow */

  /* if compiling with -ftrapv, we shouldn't get here */
  return 0;
}

当我在本地运行此代码时,输​​出为

Overflow detected
Aborted

答案 1 :(得分:11)

看看-ftrapv and -fwrapv

  

-ftrapv

     

此选项为加法,减法,乘法运算的带符号溢出生成陷阱。

     

-fwrapv

     

该选项指示编译器假设加法,减法和乘法的有符号算术溢出使用二进制补码表示。此标志启用一些优化并禁用其他优化。默认情况下,Java前端根据Java语言规范的要求启用此选项。

另请参阅Integer overflow in C: standards and compilersUseful GCC flags for C

答案 2 :(得分:1)

如果您使用的是Microsoft编译器,则有一些选项可以生成在整数转换切断非零位时触发SEH异常的代码。在实际需要的地方,在进行转换之前使用按位AND删除高位。

答案 3 :(得分:1)

clang 现在支持有符号和无符号整数的动态溢出检查。请参阅-fsanitize=integer开关。目前,只有一个C ++编译器具有完全支持的动态溢出检查以用于调试目的。

答案 4 :(得分:0)

唯一可靠的解决方法是将对这些整数的操作包装为执行边界违规检查的函数。这当然会减慢整数运算速度,但是如果你的代码在一个有意义的错误消息的边界违规上断言或停止,那么这将有助于你找出问题的位置。

至于你的特定问题,请记住,一般情况排序是O(nlogn),因此算法花费更长时间的原因可能是由于时间的增加与数据不相关的事实设定尺寸。由于也没有提到框中有多少物理内存以及有多少物理内存用于您的算法,因此可能存在具有较大数据集的磁盘页面错误,从而可能减慢爬行速度。