Поиск числовых ошибок из-за целочисленного деления - PullRequest
7 голосов
/ 20 мая 2011

Существует ли предупреждение g ++ или другой инструмент, который может идентифицировать целочисленное деление (усечение до нуля)?У меня есть тысячи строк кода с вычислениями, которые неизбежно будут иметь числовые ошибки, как правило, из-за "float = int / int", которые должны быть расположены.Мне нужен разумный метод для их нахождения.

Ответы [ 6 ]

2 голосов
/ 21 мая 2011

Мне трудно назвать эти числовые ошибки.Вы запросили целочисленные вычисления и получили правильные числа для целочисленных вычислений.Если эти числа неприемлемы, запросите вычисления с плавающей запятой:

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;
2 голосов
/ 21 мая 2011

Попробуйте -Wconversion.

со справочной страницы gcc:

Предупреждать о неявных преобразованиях, которые могут изменить значение. Это включает преобразования между действительным и целым числом, например, «abs (x)», когда «x» означает «double»; преобразования между подписанным и unsigned, например, "unsigned ui = -1"; а также преобразования в меньшие типы, такие как "sqrtf (M_PI)". Не предупреждаю за явное приведение типа "abs ((int) x)" и "ui = (без знака) -1", или если значение не изменяется при конвертации как в "abs (2.0)". Предупреждения о преобразования между подписанным и целые числа без знака могут быть отключены используя -Wno-sign-преобразование.

Для 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;
}
1 голос
/ 25 февраля 2013

Примечание по -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, но double). Так что может быть изменение значения при назначении RHS f в случае с плавающей запятой, но не в случае double. Чтобы было понятно: предупреждение возвращается не из-за int/int, а из-за назначения float = int.

Для этого см. Следующие вопросы: в чем разница между типом данных с плавающей точкой и целочисленным типом данных, когда размер одинаков в Java , Хранение целых чисел в виде чисел с плавающей запятой и Округление для использования для int -> float -> int конверсия туда и обратно

Тем не менее, при использовании float -Wconversion все еще может быть полезно определить возможные линии, которые затронуты, но не являются исчерпывающими и фактически не предназначены для этого. Для -Wconversion см. docs / gcc / Warning-Options.html и здесь gcc.gnu.org / wiki / NewWconversion

Возможно, интерес представляет также обсуждение ' Неявное приведение вычисления целых чисел для плавания в C ++ '

0 голосов
/ 17 июня 2019

Посмотрите на это обнаружение лягушки .

Ловит такие случаи:

d = 32 * 8 / (2 + i);
d = 8 * floatFunc(1 + 7 / 2);
d = i / (1 << 4);
0 голосов
/ 21 мая 2011

Лучший способ найти такую ​​ошибку - провести действительно хорошие юнит-тесты.Все альтернативы недостаточно хороши.

...