Форум программистов, компьютерный форум CyberForum.ru

float переменная - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 15, средняя оценка - 4.87
korez
8 / 8 / 0
Регистрация: 22.02.2011
Сообщений: 179
12.06.2011, 08:06     float переменная #1
я инициализирую переменную float значением 0.15 а в действительности там 0.15000001.
потом прибавляю 0.01 получаю 0.16000001
потом прибавляю 0.01 еще раз, получаю 0.17000002.

откуда еще берется 0.00000001 и как от этого избавится?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
12.06.2011, 08:30     float переменная #2
http://democoder.ru/article/14
korez
8 / 8 / 0
Регистрация: 22.02.2011
Сообщений: 179
12.06.2011, 08:52  [ТС]     float переменная #3
pito211, что делать скажи
tylix
68 / 55 / 6
Регистрация: 10.06.2011
Сообщений: 149
12.06.2011, 08:57     float переменная #4
Цитата Сообщение от pito211 Посмотреть сообщение
Почитал. Интересно. Статья очень полезная.

Но ошибка мне кажется в компиляторе.
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
12.06.2011, 09:13     float переменная #5
Цитата Сообщение от korez Посмотреть сообщение
pito211, что делать скажи
Использовать double/GMP
Цитата Сообщение от tylix Посмотреть сообщение
Но ошибка мне кажется в компиляторе.
Тогда это ошибка всех компиляторов=)
Вот простенький код, демонстрирует точность float и double
C
1
2
3
4
5
6
7
#include <cstdio>
int main(){
    float f = 0.1;
    double d = 0.1;
    printf("%.20f \n%.20lf",f,d);
    return 0;
}
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
12.06.2011, 09:38     float переменная #6
Цитата Сообщение от tylix Посмотреть сообщение
Но ошибка мне кажется в компиляторе.
"ошибка" если её можно так назвать в системе исчисления. В двоичном виде 0.15 - бесконечная дробь.

Добавлено через 2 минуты
Цитата Сообщение от korez Посмотреть сообщение
pito211, что делать скажи
в статье которую я привёл есть решение. Округлять
tylix
68 / 55 / 6
Регистрация: 10.06.2011
Сообщений: 149
12.06.2011, 10:20     float переменная #7
Млин... не знал этого... буду учитывать в будущем
korez
8 / 8 / 0
Регистрация: 22.02.2011
Сообщений: 179
12.06.2011, 10:28  [ТС]     float переменная #8
как округлять
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
12.06.2011, 10:44     float переменная #9
а чё ты хочешь? При вычислениях от погрешности никуда не денешься, или итерациями пользоваться так точнее, но медленее. При сравнении надо ввести константу эпсилон и сравнивать с какой надо точностью. Но если операций с даблами не слишком много, можно забить на погрешность и при выводе воспользоваться precision, то есть просто обрезать мусор. Чё эта единичка так сильно влияет чтоли на твои мегавычисления?
ValeryLaptev
Эксперт C++
1005 / 784 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
12.06.2011, 10:53     float переменная #10
Цитата Сообщение от korez Посмотреть сообщение
как округлять
С точностью до эпсилон. А эпсилон - от задачи зависит.
C++
1
t = floor(t+0.5);   // -- до целых округление.
Mr.X
Эксперт С++
 Аватар для Mr.X
2802 / 1578 / 247
Регистрация: 03.05.2010
Сообщений: 3,666
12.06.2011, 11:53     float переменная #11
В статье http://democoder.ru/article/14, на которую ссылается pito211 в сообщении #2, ошибка в разделе о вычитании:
>>>>>>>>>>>>>>>>>>>>>>>начало цитаты>>>>>>>>>>>>>>>>>>>>>>
VII. Осторожнее с вычитанием!

Это наименее точная операции из всех алгебраических в компьютере. Вы должны избегать её где только возможно, особенно остерегайтесь вычитания очень близких друг к другу чисел, потому что из-за ошибки округления они могут выродиться в 0, а если эта разность была в знаменателе, то нетрудно представить, к чему это приведёт.

Е. Волков приводит интересный пример в своей книге "Численные методы":

"Мы должны вычислить sqrt(543)-sqrt(540), где 543 и 540 даны точно. (то есть все их разряды значащие)

Имеем

sqrt(543) = 23.30....


sqrt(540) = 23.23....

Округлим их до трёх разрядов (потому что столько было в исходных данных, а точность может только уменьшаться)

sqrt(543) - sqrt(540) ~ 23.3 - 23.2 = 0.1

Имеем только один значащий разряд в результате.

Избавимся от вычитания искусственным преобразованием:

sqrt(543) - sqrt(540) = 3 / (sqrt(543)+sqrt(540))

(умножили на sqrt(543)-sqrt(540))

Это равняется 3/(23.3+23.2) = 3/46.5 = 0.0645, мы имеем три значащих разряда в результате."
>>>>>>>>>>>>>>>>>>>конец цитаты>>>>>>>>>>>>>>>>>>>>>>>>>>>

Здесь 3/46.5 = 0.0645 неверно, так как 3 получается вычитанием 543 – 540, где числа даны с точностью до единицы, следовательно тройка имеет только одну значащую цифру, и при делении 3/46.5 мы в полученном результате также имеем право оставить только одну, т.е. в частном 0.0645 все цифры недостоверные, а можно писать только 0.1.
Похоже, что и Е. Волков, на которого там ссылаются, также с математикой не в ладах.
Собственно, в том-то и опасность вычитания, что оно может резко уменьшить количество значащих цифр.
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
12.06.2011, 12:05     float переменная #12
Цитата Сообщение от Mr.X Посмотреть сообщение
так как 3 получается вычитанием 543 – 540, где числа даны с точностью до единицы, следовательно тройка имеет только одну значащую цифру
Непонятно, на чём основан данный вывод. По условию 543 и 540 — точные значения, а не округлённые. В результате вычитания тоже получаются точное. Вот если бы 543 и 540 вычислялись бы с точностью до 3 знаков, то данное замечание было бы справедливым. Но в общем согласен, небольшой элемент жульничества тут присутствует
korez
8 / 8 / 0
Регистрация: 22.02.2011
Сообщений: 179
12.06.2011, 12:12  [ТС]     float переменная #13
совершенно верно мне она не нужна эта еденица нужно только четыре знака после, точки как сделать?
Mr.X
Эксперт С++
 Аватар для Mr.X
2802 / 1578 / 247
Регистрация: 03.05.2010
Сообщений: 3,666
12.06.2011, 12:12     float переменная #14
В общем, автор статьи хотел продемонстрировать вред вычитания, но пример выбрал неудачный, так как вычитание используется в обоих случаях.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.06.2011, 12:39     float переменная
Еще ссылки по теме:

опять ошибка.на этот раз cannot convert `float (*)(float)' to `float' in argument passing C++
cannot convert `float' to `float*. Почему так происходит? C++
C++ Чем отличаются float преобразования (float)var от float(var)

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
tylix
68 / 55 / 6
Регистрация: 10.06.2011
Сообщений: 149
12.06.2011, 12:39     float переменная #15
Цитата Сообщение от korez Посмотреть сообщение
совершенно верно мне она не нужна эта еденица нужно только четыре знака после, точки как сделать?
В инете нашел это... хотя меня мучают смутные сомнения )

C++
1
2
3
inline double round( double val, double prec) {
    return ((long long)((val/prec) + ((val > 0) ? 0.5 : -0.5)))*prec;
}
Yandex
Объявления
12.06.2011, 12:39     float переменная
Ответ Создать тему
Опции темы

Текущее время: 10:50. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru