#c #c #overflow
#c #c #переполнение
Вопрос:
Я знаю, что это глупо, но я тихий новичок в мире программирования, вот мой код.
Это работает отлично:
#include <stdio.h>
int main() {
float x = 3153600000 ;
printf("%f", x);
return 0;
}
Но у этого есть проблема:
#include <stdio.h>
int main() {
float x = 60 * 60 * 24 * 365 * 100 ;
printf("%f", x);
return 0;
}
Итак 60 * 60 * 24 * 365 * 100 правильно ли 3153600000??? если да, то почему это привело к другим результатам??? В результате я получил переполнение во втором, в котором было напечатано «-1141367296.000000». Кто-нибудь может сказать мне, почему?
Комментарии:
1. Вот что происходит, когда вы пытаетесь измерить год в сантисекундах. Увеличьте уровень предупреждения вашего компилятора до одиннадцати тысяч сантикликов.
Ответ №1:
Вы умножаете целые числа, а затем помещаете результат в float. К тому времени он уже переполнен.
Попробуйте float x = 60.0f * 60.0f * 24.0f * 365.0f * 100.0f;
. Вы должны получить желаемый результат.
Комментарии:
1.
f
В этом нет необходимости (можно выполнитьdouble
арифметику и сохранить ее в float). Компилятору вdouble
любом случае нравится делать такого рода вещи. (По крайней мере, GCC делает.)2. @greyfade: Бывают случаи, когда это имеет значение. Они довольно загадочные, но они существуют. (К счастью, это не один из них.)
3. @greyfade: О, и если компилятор все равно выполняет свертку константы в
double
, то это не работает…4. @Oli Charlesworth: Я согласен, но в этом случае выражение, вероятно, будет вычислено компилятором, что делает его более или менее не вызывающим проблем. : P
5. @greyfade: Да, я имел в виду конкретно константы, вычисляемые компилятором. Иногда это имеет значение…
Ответ №2:
60
является целым числом, как 24
, 365
и 100
. Следовательно, все выражение 60 * 60 * 24 * 365 * 100
выполняется с использованием целочисленной арифметики (компилятор оценивает выражение, прежде чем он увидит, к какому типу переменной вы его относите).
В типичной 32-разрядной архитектуре целое число со знаком может содержать значения до 2 147 483 647. Таким образом, значение будет усечено до 32 бит, прежде чем оно будет присвоено вашей float
переменной.
Если вы скажете компилятору использовать арифметику с плавающей запятой, например, путем привязки f
к первому значению, чтобы оно стало плавающим, тогда вы получите ожидаемый результат. (Значение float, умноженное на int, является значением float, поэтому значение float распространяется на все выражение.) Например.:
float x = 60f * 60 * 24 * 365 * 100;
Ответ №3:
Разве ваш компилятор не выдает это предупреждение? У меня есть:
предупреждение: переполнение целых чисел в выражении
Переполнение происходит до того, как целочисленное выражение преобразуется в float перед сохранением в x. Добавьте 0f ко всем числам в выражении, чтобы сделать их плавающими.
Комментарии:
1. Это происходит, только если компилятор выполняет выражение во время компиляции.
2. Почему компилятор не вычислит это во время компиляции?
Ответ №4:
Если вы умножите два целых числа, результатом тоже будет целое число.
60 * 60 * 24 * 365 * 100
является целым числом.
Поскольку целые числа могут достигать 2^31-1
( 2147483647
), такие значения переполняются и становятся -1141367296
, которые только затем преобразуются в float.
Попробуйте умножать числа с плавающей точкой вместо целых.