Вопрос

Итак, у меня есть функция, которая выглядит примерно так:

float function(){
    float x = SomeValue;
    return x / SomeOtherValue;
}

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

float function(){
    float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

и это сработало!Я, конечно, вообще решил проблему, воспользовавшись дублем.Но мне любопытно, почему функция работала правильно, когда я ее придумал.Это типично или может быть где-то еще ошибка, которую я упускаю?

(Если это вам поможет, значение, хранящееся в веществе с плавающей запятой, представляет собой просто целое число, причем не особенно большое.Я просто поместил его в число с плавающей запятой, чтобы избежать приведения.)

Это было полезно?

Решение

Добро пожаловать в чудесный мир чисел с плавающей запятой.Ответ, который вы получите, скорее всего, будет зависеть от модели с плавающей запятой, с которой вы скомпилировали код.

Это происходит из-за разницы между спецификацией IEEE и оборудованием, на котором выполняется код.Ваш процессор, вероятно, имеет 80-битные регистры с плавающей запятой, которые используются для хранения 32-битного значения с плавающей запятой.Это означает, что точность остается гораздо выше, пока значение остается в регистре, чем когда оно принудительно переносится по адресу памяти (также известное как «возврат» регистра).

Когда вы передавали значение в cout, компилятору приходилось записывать число с плавающей запятой в память, что приводило к потере точности и интересному поведению в случаях переполнения WRT.

См. документацию MSDN по VC++. переключатели с плавающей запятой.Вы можете попробовать скомпилировать с /fp:strict и посмотреть, что произойдет.

Другие советы

Вывод значения в cout вообще не должен изменять значение параметра.

Однако я видел подобное поведение: добавление операторов отладки приводит к изменению значения.В этих случаях, а возможно и в этом, я предполагал, что дополнительные операторы заставляли оптимизатор компилятора вести себя по-другому, поэтому сгенерируйте другой код для вашей функции.

Добавление оператора cout означает, что значение x используется напрямую.Без этого оптимизатор мог бы удалить переменную, изменив тем самым порядок вычислений и, следовательно, изменив ответ.

Кроме того, всегда полезно объявлять неизменяемые переменные, используя const:

float function(){
    const float x = SomeValue;
    cout << x;
    return x / SomeOtherValue;
}

Помимо прочего, это предотвратит непреднамеренную передачу переменных функциям, которые могут изменить их посредством несанкционированного доступа.const Рекомендации.

cout вызывает ссылку на переменную, что часто приводит к тому, что компилятор заставляет его передать ее в стек.

Поскольку это число с плавающей запятой, это, вероятно, приведет к усечению его значения от представления double или long double, которое оно обычно имеет.

Вызов любой функции (не встраиваемой), которая принимает указатель или ссылку на x, должен в конечном итоге вызывать такое же поведение, но если позже компилятор станет умнее и научится встраивать ее, вы тоже будете в тупике :)

Я не думаю, что cout каким-либо образом влияет на переменную, проблема должна быть где-то еще.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top