dlinyj: (Default)
[personal profile] dlinyj
Столкнулся с забавным затыком, нужно было исключить срабатывания при переменной xtra равной 1, 5, 25 и 125. Я записал:

...
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 знаков после запятой), то близкое к округленю компилятором, но очень отличающееся от исходного. Вот например:

Date: 2009-10-08 01:21 pm (UTC)
From: [identity profile] Шура Люберецкий (from livejournal.com)
Сравниваем так:

#define EPS 1E-5 // с точностью до пяти знаков после запятой

// skipped some code

if( fabs(a - 1.0) < EPS){
printf("a = 1.0!");
} else {
printf("a =/= 1.0!");
}

Это актуально для _всех_ реализаций арифметики с плавающей запятой. Естественно, надо подключать math.h

Date: 2009-10-08 01:56 pm (UTC)
From: [identity profile] dlinyj.livejournal.com
не так всё просто, у меня число вида: 0.75110864639282227

Date: 2009-10-08 02:12 pm (UTC)
From: [identity profile] cluster-d.livejournal.com
Ну и в чём сложность? Сравниваешь с заданной точностью.

Date: 2009-10-08 03:26 pm (UTC)
From: [identity profile] aterentiev.livejournal.com
у 4х-байтового флоата только 7 значащих цифр, поэтому Шурино решение ИМХО подходит

Date: 2009-10-08 02:05 pm (UTC)
From: [identity profile] 0x1392.livejournal.com
float_result - результат вычислений
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");

Date: 2009-10-08 02:24 pm (UTC)
From: [identity profile] dlinyj.livejournal.com
Попробую, см. апдейт

Date: 2009-10-08 03:18 pm (UTC)
From: [identity profile] Шура Люберецкий (from livejournal.com)
Это примерно то же самое, что и приведенный мной код.

Date: 2009-10-08 02:25 pm (UTC)
From: [identity profile] 0x1392.livejournal.com
"компилятором вывожу" -- это типа printf'ом чтоли? =) ну printf я очень сомневаюсь что округляет число, просто печатает столько знаков после запятой сколько скажешь.

для хоть сколь-нибудь серьезных/точных вычислений float не используют, используют double, потому что float довольно таки не точен. Маловато разрядов. Раньше был понт, типа float быстрее было. На современных компьютерах разницы между ними фактически нет.

Date: 2009-10-08 02:33 pm (UTC)
From: [identity profile] dlinyj.livejournal.com
Ну понятное дело что принтэфом :). Ща поставил дабл. :). Сразу всё стало на свои места!

Date: 2009-10-08 08:27 pm (UTC)
From: [identity profile] 0x1392.livejournal.com
=D
Гм, я сначала сам даже не очень допетрил, просто интуиция/опыт подсказали что double надо. А счас вот вспомнил почему именно так.
Вобщем фишка в том, что у float мало разрядов и еще в том что число разрядов конечное. А если число разрядов конечное, то количество различных комбинаций которые можно составить ограничено. То есть получается что только ограниченное количество дробей можно представить.
И получается что когда ты делаешь что-то типа
fvar = 0.00001;
Там на самом деле записывается (утрированно конечно) 0.000010000001..
Ну и чем больше ты всяких операций проведешь с этой переменной, тем больше будет нарастать эта "погрешность".
У double просто количество разрядов большое, и он может довольно точно отображать дробные числа. И ошибка копится намного медленее.

Date: 2009-10-09 04:44 am (UTC)
From: [identity profile] dlinyj.livejournal.com
Мне вот честно непонятно, откуда берётся погрешность. Именно то что записывается не вот так как мы видим, а ещё мусор в супермладших разрядах...

Date: 2009-10-11 09:01 pm (UTC)
From: [identity profile] holybrake.livejournal.com
ну да, все через это непонятно проходят - попробуй повыводить флоат в цикле из твоей мегадроби домножая ее на 10 на каждой итерации, и константу кстати объяви как float,
то бишь букву f после числа ставь - сразу обнаружишь как быстро у этого обрезка теряется точность.
(deleted comment)

Date: 2009-10-08 02:50 pm (UTC)
From: [identity profile] dlinyj.livejournal.com
Это х86 проц (486), с аппаратной поддержкой плавающей точки. Собственна софтина предназначена для теста этой самой плавучки.

Date: 2009-10-08 07:47 pm (UTC)
From: [identity profile] muslenok.livejournal.com
Солнышко, научи меня понимать тебя в таких постах...После просмотра своей френдленты где еще тусуется ру психооджи и ру секс скул...на твоих постах душа радуется...

Date: 2009-10-09 05:12 am (UTC)
From: [identity profile] dlinyj.livejournal.com
Ну тут элементы программирования. На самом деле несколько дней назад я бы сам не понял этот пост :). Он как бы расчитан на людей знающих си.

Проще говоря, у меня возникла глупая проблема, я о ней рассказал, чтобы люди её не допускали. А потом задал вопрос о насущной проблеме (работа с дробными числами). Там какая-то хитрость которую я не понимаю (и такое ощущение что никто не понимает). Например, банально: в некоторую переменную "а" записываем число 0,000000001:
а=0.000000001;
Затем вычитаем из неё это же число
а=а-0.000000001;

Так вот удивительно, что после такой операции, по всем правилам математики "а" ДОЛЖНО быть равно нулю, но оно НЕ будет равно нулю! Т.к. там будет некий мусор в младших разрядах, которые мы не видим. Вот я и задаю вопрос: как же округлять.

Date: 2009-10-09 01:38 pm (UTC)
From: [identity profile] muslenok.livejournal.com
Муравейчик, а я всю жизнь вот такие заморочки люблю...ты меня сейчас к чему-нить подтолкнешь... мне и так хочется чего-нить взрывающего мозг...Я пока энциклопедию по математике перечитаю чтоль...а дальше? Я только в школе алгоритмы составляла, да малюсенькие писюльки делала...

Date: 2009-10-09 01:46 pm (UTC)
From: [identity profile] dlinyj.livejournal.com
Ну так зачем дело! Дерзай, можно изучить си. Я программирование изучил именно из-за того что мне нравилось мозгом похрустеть! :)

January 2026

S M T W T F S
    123
456 78910
11121314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 22nd, 2026 11:23 am
Powered by Dreamwidth Studios