Почему "для (i = 0,1; я!= 1,0; я + = 0,1)" не нарушается при я = 1,0?

Сегодня у меня был экзамен на C, и мне задали вопрос, похожий на:

Что не так с этой программой:

for( x = .1 ; x != 1.0 ; x += .1)
    printf("%f\n", x);

Я не мог решить эту проблему, так как мне пришлось написать что-то, что помечено как .1 как ошибка. Но когда я вернулся домой, я запустил эту программу. Оказалось, что она не ломается, когда x равна 1.0 и застревает в бесконечном цикле:

$ cat exam.c
#include <stdio.h>

int main(int argc, char **argv)
{
    float x;

    for(x = .1 ; x != 1.0 ; x += .1)
        printf("%f\n", x);

    return 0;
}
$ gcc exam.c -o exam
$ ./exam
0.100000
0.200000
0.300000
0.400000
0.500000
0.600000
0.700000
0.800000
0.900000
1.000000 <- ?
1.100000
1.200000
1.300000
1.400000
1.500000
....

Может кто-нибудь объяснить, почему это происходит.

Ответы

Ответ 1

Это типичный вопрос для домашнего задания.

Проблема в том, что 0,1 не может быть точно сохранен в правильной проверке float для <= 1.0

Однако это работает только в очень ограниченном диапазоне, как сказал Ктулху. Я полностью упустил эту проблему. Для причины лучше использовать int и делить его значение позже.

Ответ 2

<= или < не является решением!

Использование плавающих точек в цикле не без проблем. Ошибка округления. Даже с <= цикл может не запускать правильное количество раз.

Он работает для <=1.0 (10 раз), но работает на один раз меньше, чем ожидалось для <=50.0 (499 раз).

 for(i = 0.1 ; i <= 50.0 ; i += 0.1)
       { ... }//runs 499 times, not 500!

Это проблема, которая может быть не очень легко обнаружить, если вы столкнулись с ней. Округление перед сравнением (функции округления) может помочь, но единственное решение с уверенным выстрелом -...

Использовать целые числа в качестве управляющих переменных в циклах.

Ответ 3

никогда не используйте != в цикле for, это приводит к очень сложному обнаружению ошибок, когда переменная цикла никогда не достигает ожидаемого значения. всегда используйте <.

Ответ 5

0,1 не может быть сохранен точно в поплавке. Числа с плавающей запятой содержат приблизительное значение, и вы пытаетесь скорректировать его на точное значение.

Ответ 6

Предложение, каждый раз, когда вам нужны циклы, используйте целые числа.

int x;
float y = 0;
for( x = 1; x < 11; x += 1){
    y += 0.1; 
    printf("%f\n", y);
}

В качестве альтернативы вы также можете использовать это:

for( x = 1; x < 11; x += 1){
    printf("%f\n", ( x / 10.0 ) );
}

В обоих случаях вы сохраняете значения циклов как целые числа.