定位因整数除法导致的数值错误
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);
【讨论】:
以上是关于定位因整数除法导致的数值错误的主要内容,如果未能解决你的问题,请参考以下文章