Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Архив форумов ЦИТФорума
Море(!) вопросов - Море(!) ответов
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 
Как правильно задавать вопросы

Проблема при вычислении нуля

 
Перейти:  
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование
Предыдущая тема :: Следующая тема  
Автор Сообщение
Airex



Зарегистрирован: 20.11.2006
Сообщения: 5
Откуда: Уфа

СообщениеДобавлено: Пн Ноя 20 2006 19:31    Заголовок сообщения: Проблема при вычислении нуля Ответить с цитатой

Код:
while (x<=2.0)
   {
      cout<<"x="<<x<<"\t"<<"y="<<f(x)<<endl;
      x=x+0.2;
   }

есть такой кусок кода. Так вот, при вычислении x=-0.2+0.2 дает не 0 как это должно быть,а 1,47044845e-005. Как это можно исправить?

PS проверял также и в экселе - та же фигня выходит!
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Airex



Зарегистрирован: 20.11.2006
Сообщения: 5
Откуда: Уфа

СообщениеДобавлено: Пн Ноя 20 2006 19:53    Заголовок сообщения: Ответить с цитатой

Странно, конечно, но проблема решилась, когда я вывод переделал
Код:
while (x<=2.0)
   {
      printf("x=%2.1f\ty=%2.2f\n",x,f(x));
      x=x+0.2;
   }   

теперь всё нормально.

Странно однако....

Кто нить сможет объяснить мне в чём была проблема?

PS типы данных в обоих случаях double
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
next



Зарегистрирован: 20.11.2006
Сообщения: 28

СообщениеДобавлено: Пн Ноя 20 2006 19:57    Заголовок сообщения: Ответить с цитатой

числа с плавающей точкой не дают гарантированного нуля - лишь 0+/-погрешность_вычислений
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Airex



Зарегистрирован: 20.11.2006
Сообщения: 5
Откуда: Уфа

СообщениеДобавлено: Пн Ноя 20 2006 20:16    Заголовок сообщения: Ответить с цитатой

А как нибудь можно гарантированно ноль получить?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
next



Зарегистрирован: 20.11.2006
Сообщения: 28

СообщениеДобавлено: Пн Ноя 20 2006 21:56    Заголовок сообщения: Ответить с цитатой

Airex писал(а):
А как нибудь можно гарантированно ноль получить?

сделай так
Код:

#include <limits>

double zerofp(double x) {
   if(numeric_limits<double>::epsilon() < x && x < numeric_limits<double>::epsilon()) return 0.0;
   else return x;
}

/* ... */

while (x<=2.0)
   {
      cout<<"x="<<zerofp(x)<<"\t"<<"y="<<zerofp(f(x))<<endl;
      x=x+0.2;
   }


теперь он должен писать 0, когда значение 'x' от него не отличимо.

по той-же причине запись "x <= 2.0" эквивалентна "x<2.0", а посему явная ошибка.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Mytilus Galloprovincialis



Зарегистрирован: 30.08.2005
Сообщения: 358
Откуда: откуда все люди родятся

СообщениеДобавлено: Вт Ноя 21 2006 03:17    Заголовок сообщения: Ответить с цитатой

Действительно, процессор округляет числа с плавающей запятой, так как не может работать с числами, где разряды дробной части превышают некоторое количество. Скорее всего, твоя переменная х двойной точности (double), что может привести к округлению ее значения. Исправь ее на float, и все проблемы должны решиться.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
next



Зарегистрирован: 20.11.2006
Сообщения: 28

СообщениеДобавлено: Вт Ноя 21 2006 03:39    Заголовок сообщения: Ответить с цитатой

Mytilus Galloprovincialis писал(а):
Исправь ее на float, и все проблемы должны решиться.

Вы уверены, что 'float' процессор гарантированно посчитает без погрешностей?

http://en.wikipedia.org/wiki/Floating-point

Цитата:
The facts that floating-point numbers cannot faithfully mimic the real numbers, and that floating-point operations cannot faithfully mimic true arithmetic operations, lead to many surprising situations.

For example, the non-representability of 0.1 and 0.01 means that the result of attempting to square 0.1 is neither 0.01 nor the representable number closest to it. In 24-bit (single precision) representation, 0.1 (decimal) was given previously as e=-4; s=110011001100110011001101, which is

.100000001490116119384765625 exactly.

Squaring this number gives

.010000000298023226097399174250313080847263336181640625 exactly.

Squaring it with single-precision floating-point hardware (with rounding) gives

.010000000707805156707763671875 exactly.

But the representable number closest to 0.01 is

.009999999776482582092285156250 exactly.

Also, the non-representability of π (and π/2) means that an attempted computation of tan(π/2) will not yield a result of infinity, nor will it even overflow. It is simply not possible for standard floating-point hardware to attempt to compute tan(π/2), because π/2 cannot be represented exactly. This computation in C:

// Enough digits to be sure we get the correct approximation.
double pi = 3.1415926535897932384626433832795;
double z = tan(pi/2.0);

Will give a result of 16331239353195370.0. In single precision (using the tanf function), the result will be -22877332.0.

By the same token, an attempted computation of sin(π) will not yield zero. The result will be (approximately) .1225 × 10-15 in double precision, or -.8742 × 10-7 in single precision. [3]

In fact, while addition and multiplication are both commutative (a+b = b+a and a×b = b×a), they are not associative (a + b) + c = a + (b + c). Using 7-digit decimal arithmetic:

1234.567 + 45.67844 = 1280.245
1280.245 + 0.0004 = 1280.245
but
45.67844 + 0.0004 = 45.67884
45.67884 + 1234.567 = 1280.246

They are also not distributive (a + b)×c = a×c + b×c :

1234.567 × 3.333333 = 4115.223
1.234567 × 3.333333 = 4.115223
4115.223 + 4.115223 = 4119.338
but
1234.567 + 1.234567 = 1235.802
1235.802 × 3.333333 = 4119.340

In addition to loss of significance, inability to represent numbers such as π and 0.1 exactly, and other slight inaccuracies, the following phenomena may occur:

* Cancellation: subtraction of nearly equal operands may cause extreme loss of accuracy. This is perhaps the most common and serious accuracy problem.
* Conversions to integer are unforgiving: converting (63.0/9.0) to integer yields 7, but converting (0.63/0.09) may yield 6. This is because conversions generally truncate rather than rounding.
* Limited exponent range: results might overflow yielding infinity, or underflow yielding a denormal value or zero. If a denormal number results, precision will be lost.
* Testing for safe division is problematical: Checking that the divisor is not zero does not guarantee that a division will not overflow and yield infinity.
* Equality is problematical! Two computational sequences that are mathematically equal may well produce different floating-point values. Programmers often perform comparisons within some tolerance (often a decimal constant, itself not accurately represented), but that doesn't necessarily make the problem go away.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Kefir



Зарегистрирован: 16.04.2005
Сообщения: 443
Откуда: Пермь

СообщениеДобавлено: Вт Ноя 21 2006 07:15    Заголовок сообщения: Ответить с цитатой

1. никогда не используйте float, толку от него никакого. А погрешность, почти всегда, неприемлема.

2. Каким был вывод до, каким после?

3. Ноль можно получить, если использовать арифметику неограниченной точности. Например, в Java это класс java.math.BigDecimal
_________________
Самоловских Виталий aka Kefir
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
Airex



Зарегистрирован: 20.11.2006
Сообщения: 5
Откуда: Уфа

СообщениеДобавлено: Вт Ноя 21 2006 21:26    Заголовок сообщения: Ответить с цитатой

float пользовал, никакой разницы, а насчет
Цитата:
никогда не используйте float, толку от него никакого. А погрешность, почти всегда, неприемлема.

память жрет в два раза меньше

2. до был 1,4(что-то там)e-014
после 0

3. в Си аналогов не знаю, а с Джавой не знаком, собираюсь попробовать. Smile
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
next



Зарегистрирован: 20.11.2006
Сообщения: 28

СообщениеДобавлено: Ср Ноя 22 2006 01:32    Заголовок сообщения: Ответить с цитатой

Kefir писал(а):
1. никогда не используйте float, толку от него никакого. А погрешность, почти всегда, неприемлема.

1) float самый быстрый тип вычислений.
2) современные видео карты поддерживают только float. посему вся практические вычисления графики только с float, будь то OpenGL, DirectX или homemade рэйтрейсер.
3) погрешность имеет значение, только если требуются очень большие значения или очень маленькие.

Цитата:
3. Ноль можно получить, если использовать арифметику неограниченной точности. Например, в Java это класс java.math.BigDecimal

на практике он слишком медленный.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Kefir



Зарегистрирован: 16.04.2005
Сообщения: 443
Откуда: Пермь

СообщениеДобавлено: Ср Ноя 22 2006 13:45    Заголовок сообщения: Ответить с цитатой

1. Про память. Ну ребята, вы что до сих пор на 8Мб сидите, что Вам памяти под double жалко?
2. Про скорость. Все вычисления FPU производятся в типе double, соответственно скорочть вычислений с типом float при помощи FPU может быть еще медленнее за счет преобразования типов. Конечно можно использовать SSE, но для этого Вы должны убедиться, что Ваш компилятор поддерживает SSE.
3. Графика - единственное место где можно использовать. Точнее так уж повелось.
4. Про погрешность. Возьмем стандартный квадратик картинки 8*8 произведем вейвлет-преобразование и обратное вейвлет-преобразование. Если будем использовать float получим картинку с артефактами. Если double получим чистую картинку.

Откуда такая любовь к этому убогому типу?
_________________
Самоловских Виталий aka Kefir
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
Kefir



Зарегистрирован: 16.04.2005
Сообщения: 443
Откуда: Пермь

СообщениеДобавлено: Ср Ноя 22 2006 13:51    Заголовок сообщения: Ответить с цитатой

next писал(а):

Цитата:
3. Ноль можно получить, если использовать арифметику неограниченной точности. Например, в Java это класс java.math.BigDecimal

на практике он слишком медленный.

Не замечал... Smile
У меня, например, основная статься расходов - взаимодействие с БД, а все остальное я даже не пытаюсь оптимизировать.

В любом случае при моделировании бизнес-процессов альтернативы нет, ну или почти нет. Некоторые додумались использовать long, но с ним получаем дополнительный гемор при умножении и делении. Ограничение сверху опять же.
_________________
Самоловских Виталий aka Kefir
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
next



Зарегистрирован: 20.11.2006
Сообщения: 28

СообщениеДобавлено: Ср Ноя 22 2006 15:33    Заголовок сообщения: Ответить с цитатой

Kefir писал(а):
next писал(а):

Цитата:
3. Ноль можно получить, если использовать арифметику неограниченной точности. Например, в Java это класс java.math.BigDecimal

на практике он слишком медленный.

Не замечал... Smile

Пока у вас пара использований BigDecimal на миллион инструкций все - ок. Но, что вы будете делать, когда надо прогнать миллион BigDecimal через пару инструкций, как при комерссии mpeg?

если важны сразу точность и скорость, попробуйте обычные int, как fixed-point.

Цитата:
1. Про память. Ну ребята, вы что до сих пор на 8Мб сидите, что Вам памяти под double жалко?

Допустим, у меня сцена с 10-ю миллионами вершин. Каждая вершина определяется минимум 5-ю значениями: x,y,z,u,v. Отсюда, имеем вес всей сцены в 190 Мб при float, и 380 Mb при double. На моей машине 256Mb RAM. Помимо того, что 380 даст в два! раза брольше cache misses, оно создаст кучу швоппинга - скорость обработки упадет более чем в два раза.

больших аргументов в сторону float лично мне не нужно.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Kefir



Зарегистрирован: 16.04.2005
Сообщения: 443
Откуда: Пермь

СообщениеДобавлено: Ср Ноя 22 2006 16:31    Заголовок сообщения: Ответить с цитатой

Естественно, при конверсии mpeg BigDecimal использовать не нужно. Человек спросил, что сделать, чтоб получался точно 0. Ответ использовать типы с неограниченной точностью.

У меня не пара инструкций на миллион. У меня вся система на BigDecimal построена. И производительность BigDecimal меня абсолютно не волнует. Кстати, если Вы имели дело с BigDecimal в ранних версиях Java, то спешу Вас обрадовать, кажется, с версии 1.4 производительность операций с BigDecimal значительно повысилась.

int имеет ограничение в 2 млрд, делим на 100, а точнее на 10000,т.к. курсы цен хранят, обычно с точностью до 4го знака и получаем примерно 200 000. Ну знаете. У меня некоторые препараты больше стоят. Пусть делим на 100, получаем 20 000 000, ну статистику по одним торгам подвести можно, а если считать сумму по всем - переполнение. так что нужно использовать long как минимум. Но, опять же, куча всяких мелочей, которые увеличат время разработки раза в полтора, а это уже, блин, очень много денег, лучше купить сервак помощнее.

Не понял что за сцена...

Что я хочу донести, так это то, что точности float недостаточно даже для графики. см. выше. Конечно, иногда приходится жертвовать ради производительности.

Иногда студенты начинают решать СЛАУ в float'ах, и получают совсем неправдоподобные решения, а потом удивляются. Ведь алгоритм то правильный!!! А почему они используют float, а потому что их приучили к этому в школе!
_________________
Самоловских Виталий aka Kefir
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
next



Зарегистрирован: 20.11.2006
Сообщения: 28

СообщениеДобавлено: Ср Ноя 22 2006 16:54    Заголовок сообщения: Ответить с цитатой

Kefir писал(а):
Не понял что за сцена...

хорошие модельки из 3ds max, или CAD прекрасно дадут по 1 миллиону и больше вертексов. и попробуйте с ними поработать в рилтайме.

Цитата:
Что я хочу донести, так это то, что точности float недостаточно даже для графики. см. выше. Конечно, иногда приходится жертвовать ради производительности.

Вы невнимательно прочитали артикль с вики. Там ясно написанно, что в узких местах следует перейти к double, или любому другому типу. Все же у нас не чистая математика, а грязный инженерный хакинг Smile

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

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

Цитата:
Иногда студенты начинают решать СЛАУ в float'ах, и получают совсем неправдоподобные решения, а потом удивляются. Ведь алгоритм то правильный!!! А почему они используют float, а потому что их приучили к этому в школе!

Ну кто их в школе такому учил? Там учат идеалистичности реальных чисел.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Показать сообщения:   
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB © 2001, 2002 phpBB Group
Русская поддержка phpBB

 

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 6608306, ICQ 232284597
Пресс-релизы — pr@citforum.ru
Послать комментарий
Информация для авторов
This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2006 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...