定位由于整数除法引起的数值误差

Locating numerical errors due to Integer division

本文关键字:误差 除法 于整数 整数 定位      更新时间:2023-10-16

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

试试-Wconversion .

来自 gcc 的手册页:

警告可能出现的隐式转换 更改值。这包括 实数和整数之间的转换, 如"abs (x)",当"x"为"双倍"时; 已签名和 之间的转换 无符号,例如"未签名的 UI = -1";和 转换为较小的类型,例如 "sqrtf (M_PI)"。不要警告 显式转换,如"abs ((int) x)" 和"UI = (无符号) -1",或者如果 值不会因转换而改变 就像在"腹肌(2.0)"中一样。 关于以下方面的警告 已签名和 之间的转换 无符号整数可以通过以下方式禁用 使用 -Wno-sign-conversion。

对于C++,还要警告转化 在"NULL"和非指针类型之间; 令人困惑的重载分辨率 用户定义的转换;和 永远不会使用类型的转化 转换运算符:转换为 "void",相同类型,基类或 对它们的引用。关于以下方面的警告 已签名和 之间的转换 无符号整数由 默认为C++,除非 -显式启用 wsign 转换。

对于以下示例程序(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;
}

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

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;

此页包含有关 g++ 警告的信息。 如果您已经尝试过-Wall那么唯一剩下的可能是此链接中的警告。 再看一眼-Wconversion可能会解决问题。

注意:已完全编辑响应。

关于 gcc -Wconversion的评论:

将浮点变量的类型从 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捕获,而只能由double捕获)。因此,在浮点数的情况下将 RHS 分配给 f 时,值可能会发生变化,但在双精度的情况下则不会。明确说明:返回警告不是因为int/int,而是因为分配float = int

为此,请参阅以下问题:当 java 中大小相同时,浮点数和整数数据类型之间有什么区别,将整数存储为浮点数和舍入以用于 int -> 浮点数 -> int 往返转换

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

可能感兴趣的也是在讨论"隐式强制转换整数计算以浮点C++"

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

看看这个叮叮当当的检测。

它捕获了这样的情况:

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