Изучая си...
Oct. 8th, 2009 04:49 pmСтолкнулся с забавным затыком, нужно было исключить срабатывания при переменной xtra равной 1, 5, 25 и 125. Я записал:
В результате срабатывало всегда! Просто взорвал себе мозг, оказывается надо было записать
Банально, но был долгий затык. Народ, скажите, как мне сравнивать значения типа float? Задача определить чётко, после вычислений - равно ли оно заданному значению.
Округляю число так:
При каждом запуске программы младшие биты разные, хотя вычисление идёт со строго вбитыми в программу константами (т.е. метод неизменен).
UPD Сей дурацкий на первый взгляд вопрос, возник при разборе полётов одной программы. Она выводит число с кучей знаков после запятой. Когда я компилятором вывожу число с 7 знаками после запятой, то выходит другое число, когда я округляю алгоритмом приведёным выше (5 знаков после запятой), то близкое к округленю компилятором, но очень отличающееся от исходного. Вот например:

...
if ((xtra != 1) || (xtra != 5) || (xtra != 25) || (xtra != 125)) {
...}
В результате срабатывало всегда! Просто взорвал себе мозг, оказывается надо было записать
...
if ((xtra != 1) && (xtra != 5) && (xtra != 25) && (xtra != 125)) {
...}
Банально, но был долгий затык. Народ, скажите, как мне сравнивать значения типа float? Задача определить чётко, после вычислений - равно ли оно заданному значению.
Округляю число так:
ErValue *= 100000; ErValue = ceil(ErValue); ErValue /= 100000;
При каждом запуске программы младшие биты разные, хотя вычисление идёт со строго вбитыми в программу константами (т.е. метод неизменен).
UPD Сей дурацкий на первый взгляд вопрос, возник при разборе полётов одной программы. Она выводит число с кучей знаков после запятой. Когда я компилятором вывожу число с 7 знаками после запятой, то выходит другое число, когда я округляю алгоритмом приведёным выше (5 знаков после запятой), то близкое к округленю компилятором, но очень отличающееся от исходного. Вот например:

no subject
Date: 2009-10-08 01:21 pm (UTC)#define EPS 1E-5 // с точностью до пяти знаков после запятой
// skipped some code
if( fabs(a - 1.0) < EPS){
printf("a = 1.0!");
} else {
printf("a =/= 1.0!");
}
Это актуально для _всех_ реализаций арифметики с плавающей запятой. Естественно, надо подключать math.h
no subject
Date: 2009-10-08 01:56 pm (UTC)no subject
Date: 2009-10-08 02:05 pm (UTC)etalon - число с которым надо сравнить
threshold - максимальная разница между float_result и etalon, после первышения которой считается что числа не равны
diff = float_result - etalon;
if (diff < 0)
diff = -diff;
if (diff < threshold)
printf("the number are eqaul (sort of..)\n");
else
printf("numbers are not equal\n");
no subject
Date: 2009-10-08 02:12 pm (UTC)no subject
Date: 2009-10-08 02:20 pm (UTC)no subject
Date: 2009-10-08 02:24 pm (UTC)no subject
Date: 2009-10-08 02:25 pm (UTC)для хоть сколь-нибудь серьезных/точных вычислений float не используют, используют double, потому что float довольно таки не точен. Маловато разрядов. Раньше был понт, типа float быстрее было. На современных компьютерах разницы между ними фактически нет.
no subject
Date: 2009-10-08 02:33 pm (UTC)no subject
Date: 2009-10-08 02:50 pm (UTC)no subject
Date: 2009-10-08 03:18 pm (UTC)no subject
Date: 2009-10-08 03:26 pm (UTC)no subject
Date: 2009-10-08 07:47 pm (UTC)no subject
Date: 2009-10-08 08:27 pm (UTC)Гм, я сначала сам даже не очень допетрил, просто интуиция/опыт подсказали что double надо. А счас вот вспомнил почему именно так.
Вобщем фишка в том, что у float мало разрядов и еще в том что число разрядов конечное. А если число разрядов конечное, то количество различных комбинаций которые можно составить ограничено. То есть получается что только ограниченное количество дробей можно представить.
И получается что когда ты делаешь что-то типа
fvar = 0.00001;
Там на самом деле записывается (утрированно конечно) 0.000010000001..
Ну и чем больше ты всяких операций проведешь с этой переменной, тем больше будет нарастать эта "погрешность".
У double просто количество разрядов большое, и он может довольно точно отображать дробные числа. И ошибка копится намного медленее.
no subject
Date: 2009-10-09 04:44 am (UTC)no subject
Date: 2009-10-09 05:12 am (UTC)Проще говоря, у меня возникла глупая проблема, я о ней рассказал, чтобы люди её не допускали. А потом задал вопрос о насущной проблеме (работа с дробными числами). Там какая-то хитрость которую я не понимаю (и такое ощущение что никто не понимает). Например, банально: в некоторую переменную "а" записываем число 0,000000001:
а=0.000000001;
Затем вычитаем из неё это же число
а=а-0.000000001;
Так вот удивительно, что после такой операции, по всем правилам математики "а" ДОЛЖНО быть равно нулю, но оно НЕ будет равно нулю! Т.к. там будет некий мусор в младших разрядах, которые мы не видим. Вот я и задаю вопрос: как же округлять.
no subject
Date: 2009-10-09 01:38 pm (UTC)no subject
Date: 2009-10-09 01:46 pm (UTC)no subject
Date: 2009-10-11 09:01 pm (UTC)то бишь букву f после числа ставь - сразу обнаружишь как быстро у этого обрезка теряется точность.