LINUX.ORG.RU

GCC странно считает float


0

2

Сейчас хелловордил олимпиадные задачки, столкнулся с такой штукой.

Пример:

#include <stdio.h>

int main (void)
{
	float a = 1;

	while (a < 2.00)
		a += 0.005;

	printf ("%f\n", a);

	return 0;
}
Эта код выдаёт 2.004999 вместо положенных 2.000000. В чём проблема? Может я чего не так делаю? Версия gcc 4.3.4


>В чём проблема?

В том, что ты используешь float, не зная об особенностях работы с данным типом данных на уровне процессора.

Попробуй double поюзать, чисто по приколу.

anonymous
()
Ответ на: комментарий от anonymous

Выдаёт 2.00500. Примечательно, что если в цикле знак с < изменить на <= то нарезультат это не повлияет

PamidoR
() автор топика

Тогда, когда число должно быть равно 2.00, оно на самом деле чуточку меньше. Поэтому условие выполняется лишний раз.

pathfinder ★★★★
()

Есть такой стандарт - IEEE 754. Рекомендую ознакомиться.

AptGet ★★★
()
Ответ на: комментарий от PamidoR

>А почему оно меньше? Как добиться более точных вычислений?

Никогда не делай строгих сравнений с числами с плавающей запятой если для тебя чувствительно отклонение даже на бесконечно малую величину.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

ты ошибаешься. КО намекает: двоичная система тут не причем, выше пруф есть от чего оно так (способ хранения в памяти).

и да, мне интересно как ты собрался делить 101 на 1111101000 (на самом деле интересно, я двоичную арифметику давно изучал, может забыл что).

dpt-ru
()
Ответ на: комментарий от PamidoR

тебе выше AptGet ответил

Есть такой стандарт - IEEE 754. Рекомендую ознакомиться.

dpt-ru
()
Ответ на: комментарий от dpt-ru

>ты ошибаешься. КО намекает: двоичная система тут не причем, выше пруф есть от чего оно так (способ хранения в памяти).

Я с капитаном не дружу. Давай развернутый ответ почему я не прав.

pathfinder ★★★★
()
Ответ на: комментарий от dpt-ru

ты ошибаешься. КО намекает: двоичная система тут не причем, выше пруф есть от чего оно так (способ хранения в памяти).

Ты ошибаешься. Двоичная система тут тоже причём. Любую конечную двоичную дробь можно записать конечной десятичной дробью, но не всякую конечную десятичную дробь можно записать конечной двоичной дробью.

Deleted
()

Кстати про IEEE 754. Если кому-нибудь нужно, могу отправить pdf'ку с IEEE 754-2008. Сам около месяца назад безуспешно искал на торрентах и рапидшарах, но нашёл только на каком-то китайском форуме в виде вложения, доступного только после регистрации =).

Deleted
()
Ответ на: комментарий от Deleted

ок. поехали.

объясни мне что такое двоичная дробь. и как она храниться в памяти (таки на всех типах архитектур одинаково?).

насколько я понимаю - все зависит от конкретной реализации. что мешает тебе хранить конечную десятичную дробь в виде числа с фиксированной точкой (самописной реализацией к примеру). в чем я неправ?

возможно я и ошибаюсь, так ты просвети. возможно я чего-то не знаю.

dpt-ru
()
Ответ на: комментарий от pathfinder

ну я же спросил

и да, мне интересно как ты собрался делить 101 на 1111101000 (на самом деле интересно, я двоичную арифметику давно изучал, может забыл что).[/qoute]

dpt-ru
()
Ответ на: комментарий от dpt-ru

у 101 ведущие нули добавляются? блин, я что-то забыл просто, вот и вопрос задал. хотел попробовать поделить, в столбик )

dpt-ru
()
Ответ на: комментарий от dpt-ru

>и да, мне интересно как ты собрался делить 101 на 1111101000 (на самом деле интересно, я двоичную арифметику давно изучал, может забыл что).

Арифметические действия во всех системах счисления выполняются одинаково. Делить столбиком, как в начальной школе учили.

linuxfan
()
Ответ на: комментарий от linuxfan

я поэтому и сказал что столбиком собираюсь делить, знаю я что такое двоичное деление. я про двоичные дроби то ли не знал, то ли забыл (не помню, может забыл просто).

dpt-ru
()
Ответ на: комментарий от dpt-ru

*мое упущение (в какой-то момент хотел написать мои упущения похоже, что-то плохо соображаю сегодня)

dpt-ru
()
Ответ на: комментарий от dpt-ru

объясни мне что такое двоичная дробь.

То же, что и десятичная, например 1001100,010010011101001101.

и как она храниться в памяти (таки на всех типах архитектур одинаково?).

Архитектура и компьютеры вообще тут не причём, мы говорим про представление числа в разных системах счисления.

что мешает тебе хранить конечную десятичную дробь в виде числа с фиксированной точкой (самописной реализацией к примеру).

Потеря точности, причём при любой фиксированной длине дробной части.

В качестве эксперимента попробуй перевести число 0,3 в двоичную систему счисления.

Deleted
()
Ответ на: комментарий от PolarFox

слушай, а ты тут причем вообще? я вроде бы людям вопрос задавал, с которыми разговаривал. спасибо конечно, но мне ответили. к чему этот пост? *налетели коршуны мля*

dpt-ru
()
Ответ на: комментарий от Deleted

>Кстати про IEEE 754. Если кому-нибудь нужно, могу отправить pdf'ку с IEEE 754-2008

М.б. вы выложите ее в открытый доступ, на slil.ru, например?

Dimanc ★★
()
Ответ на: комментарий от dpt-ru

> я вроде бы людям вопрос задавал, с которыми разговаривал

Это форум, да ещё и древовидный, да к тому же с показом комментариев в плоском виде сортированном по времени. Привыкай.

PolarFox ★★★★★
()
Ответ на: комментарий от Deleted

>Потеря точности, причём при любой фиксированной длине дробной части.

В качестве эксперимента попробуй перевести число 0,3 в двоичную систему счисления.


Что мешает хранить число в виде обыкновенной дроби? :)

Dimanc ★★
()
Ответ на: комментарий от Dimanc

Что мешает хранить число в виде обыкновенной дроби? :)

Это уже другой вопрос. =)

Deleted
()
Ответ на: комментарий от PolarFox

да, наверное это особенность данного форума. и на самом деле непривычно просто. на будущее учту.

dpt-ru
()
Ответ на: комментарий от PamidoR

А почему оно меньше? Как добиться более точных вычислений?

Использовать рациональные вместо вещественных, например.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Или нужно сказать самому себе в первую очередь, что хотим получить таким алгоритмом и потом уже компилятору: [code=c] #include<stdio.h> #include<math.h> int main() { float a = 1; float h = 0.005; while ((fabs(a - 2.0) > fabs(a + h - 2.0))) a = a + h; printf(«%f\n», a); return 0; } [\code] Таким алгоритмом получают не 2, а наибольшее число X, которое ближе к 2, чем X+0.005.

anonymous
()
Ответ на: комментарий от anonymous

[code=c] #include<stdio.h> #include<math.h> int main() { float a = 1; float h = 0.005; while ((fabs(a - 2.0) > fabs(a + h - 2.0))) a = a + h; printf(«%f\n», a); return 0; } [/code] Топикстартер предложил алгоритм, которым получают не 2, а наибольшее число X, которое ближе к 2, чем X+0.005. Если это то, что он хотел, то вот улучшенный вариант его алгоритма.

anonymous
()
Ответ на: комментарий от anonymous

Сорри, [code] что-то заглючил. Но идея думаю понятна. В таком цикле лишний раз прибавление не произойдет. Мы с минимальной ошибкой вычислений окажемся около 2: ответом будет 1.9999999 или 2.0000001 - тут уже могут спорить знатоки двоичных представлений и архитектур.

anonymous
()
Ответ на: комментарий от pozitiffcat

Ну не в этом же трабла у топикстартера.

На самом деле, предлагаемые варианты типа:

а) использовать точное представление конечных десятичных дробей б) использовать точное представление рациональных чисел

правильные, но излишне масштабно решают проблему топикстартера, которая заключалась собственно в следующем:

В предложенном алгоритме какое условие остановки цикла использовать, чтоб полученное a было наибольшим числом, ближайшим к числу 2?

Условие остановки, предложенное топикстартером просто нужно заменить на предложенное анонимусом

fabs(a - 2) > fabs(a + 0.005 - 2)

что словами можно описать как:

«увеличивать a по 0.005 до тех пор, пока текущее значение не окажется ближе к 2, чем следующее».

При таком подходе a будет максимально близко после окончания вычислений к 2, и лишнего шага не произойдет.

Это вообще-то проходят на самых первых уроках курса численных методов или типа того.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.