Почему "для (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
, это приводит к очень сложному обнаружению ошибок, когда переменная цикла никогда не достигает ожидаемого значения. всегда используйте <
.
Ответ 4
Это связано со стандартом IEEE с плавающей запятой. Проверить Википедию
0.1 + 0.2 = 0.3 => FALSE - Expected: 0.3 | Real: 0.30000000000000004
Посмотрите демоверсию (JavaScript) здесь: http://k8.no-ip.org/stackoverflow/13542220.htm
Ответ 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 ) );
}
В обоих случаях вы сохраняете значения циклов как целые числа.