Кто-нибудь может сказать мне, почему float не может содержать 3153600000?

#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.

Попробуйте умножать числа с плавающей точкой вместо целых.