定位因整数除法导致的数值错误

Posted

技术标签:

【中文标题】定位因整数除法导致的数值错误【英文标题】:Locating numerical errors due to Integer division 【发布时间】:2011-05-20 19:46:04 【问题描述】:

是否有 g++ 警告或其他工具可以识别整数除法(向零截断)?我有数千行代码的计算不可避免地会出现数字错误,通常是由于需要定位的“float = int/int”。我需要一个合理的方法来找到这些。

【问题讨论】:

有操作系统限制吗? (用于静态分析工具推荐)。 目前使用 Debian 5.06,近期可能会使用 6.01。 我使用 gcc,但我找不到任何警告可以捕捉到这个 `double alpha = 4/9/M_PI;. I tried -Wall, -Wextra` 和 -Wconversion .在我看来,涉及浮点数和整数除法的表达式应该给出警告。 【参考方案1】:

试试-Wconversion

来自 gcc 的手册页:

对可能的隐式转换发出警告 改变一个值。这包括 实数和整数之间的转换, 当“x”为“double”时,如“abs (x)”; 签名和之间的转换 无符号,如“无符号 ui = -1”;和 转换为较小的类型,例如 “sqrtf (M_PI)”。不要警告 像“abs ((int) x)”这样的显式转换 和“ui = (unsigned) -1”,或者如果 值不会因转换而改变 就像在“abs (2.0)”中一样。关于警告 签名和之间的转换 无符号整数可以通过 使用 -Wno-sign-conversion。

对于 C++,还警告转换 在“NULL”和非指针类型之间; 令人困惑的重载解决方案 用户定义的转换;和 永远不会使用类型的转换 转换运算符:转换为 “void”,相同类型,基类或 对他们的引用。关于警告 签名和之间的转换 无符号整数被禁用 C++ 中的默认值,除非 -Wsign-conversion 已显式启用。

对于以下示例程序 (test.cpp),我收到错误 test.cpp: In function ‘int main()’: test.cpp:7: warning: conversion to ‘float’ from ‘int’ may alter its value

#include <iostream>

int main()

    int a = 2;
    int b = 3;
    float f = a / b;

    std::cout << f;

    return 0;

【讨论】:

我之前尝试过这个警告,但不幸的是,代码中有太多隐式转换,因此无法挑选出与整数除法相关的转换。在进行任何类型的代码清理之前,我需要解决数字错误,这将使 Wconversion 在这种情况下有用。 如果你有那么多转换错误,为什么不直接通过grep 过滤它们并过滤float【参考方案2】:

我很难说出这些数字错误。您要求进行整数计算,并获得了正确的整数计算数字。如果这些数字不可接受,则要求进行浮点计算:

int x = 3;
int y = 10;

int z = x / y;

// "1." is the same thing as "1.0", you may want to read up on
// "the usual arithmetic conversions."  You could add some
// parentheses here, but they aren't needed for this specific
// statement.
double zz = 1. * x / y;

【讨论】:

是的,完全正确。与数字错误相比,它们更准确地称为“不正确的类型选择”。【参考方案3】:

This page contains info about g++ warnings. If you've already tried -Wall then the only thing left could be the warnings in this link. On second look -Wconversion might do the trick.

注意:完全编辑了响应。

【讨论】:

重载仅涉及原始类型的运算符是非法的;即,重载必须涉及至少一个 UDT。【参考方案4】:

-Wconversion 的gcc 的备注:

将浮点变量的类型从 float 更改为 double 会使警告消失:

$ cat 'file.cpp'

#include <iostream>

int main()

   int a = 2;
   int b = 3;
   double f = a / b;

   std::cout << f;

使用$ g++-4.7 -Wconversion 'file.cpp' 编译不会返回任何警告(如$ clang++ -Weverything 'file.cpp')。

解释:

使用类型 float 时的警告不会返回,因为整数算术完全有效,而是因为 float 无法存储 int 的所有可能值(float 无法捕获更大的值,而是 @ 987654339@)。因此,在浮点数的情况下将 RHS 分配给 f 时,值可能会发生变化,但在双精度数的情况下则不会。说清楚:警告不是因为int/int而返回的,而是因为分配float = int

为此,请参阅以下问题:what the difference between the float and integer data type when the size is same in java、Storing ints as floats 和 Rounding to use for int -> float -> int round trip conversion

但是,当使用float -Wconversion 时,仍然可以用于识别可能受影响的行,但并不全面,实际上并不适用于此。对于-Wconversion,请参阅docs/gcc/Warning-Options.html 和此处gcc.gnu.org/wiki/NewWconversion

可能感兴趣的还关注讨论'Implicit casting Integer calculation to float in C++'

【讨论】:

【参考方案5】:

找到此类错误的最佳方法是进行非常好的单元测试。所有替代品都不够好。

【讨论】:

【参考方案6】:

看看这个clang-tidy detection。

它会捕获这样的情况:

d = 32 * 8 / (2 + i);
d = 8 * floatFunc(1 + 7 / 2);
d = i / (1 << 4);

【讨论】:

以上是关于定位因整数除法导致的数值错误的主要内容,如果未能解决你的问题,请参考以下文章

excel2007除法结果为啥只有整数,怎样才能保留两位小数?

整数除法总是零[重复]

整数除法 (%) Python 中是不是存在错误?

每日一题「整数除法」

每日一题「整数除法」

剑指offer-001-整数的除法