Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
ymniktm
4 / 4 / 1
Регистрация: 04.07.2014
Сообщений: 65
1

В поисках логики

22.10.2014, 14:40. Просмотров 1593. Ответов 41
Метки нет (Все метки)

Проблема известная но окончательного ответа я так и не нашел...

int a,b;
a=(0.1+0.7)*10;
b=(0.1+0.8)*10;
cout << a << ' ' <<b;
// 7 9
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.10.2014, 14:40
Ответы с готовыми решениями:

В поисках адреса переменной
Здравствуйте. Вот дали задачки к экзамену, третий день ищу решение никак найти...

Программа по теории нечеткой логики
Ребят, у кого нибудь есть что то ПОХОЖЕЕ на эту программку?Буду очень...

В поисках хэндла приложения по имени
Привет всем! Помогите разобраться. Почему такой вод код не помогает найти хэндл...

Создание логики игры и двойная буферизация консоли
У меня есть консольная игра (змейка). Хотелось бы усовершенствовать ее, а...

В поисках книги
Брюс Эккель философия с++ 4е издание.

41
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 17:25 2
C++
1
a=(float)(0.1+0.7)*10;
Привидение типа. Вы используете внутри вычислений не int переменные, а т.к. int возвращяемое значение - то считаются как int и внутренние (что то типа того).
0
Nick Alte
Эксперт С++
1647 / 1019 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
22.10.2014, 17:57 3
Проблема в точности. Идеально точно десятичные дроби в double не помещаются (ну кроме совсем удачных, вроде 0.5), поэтому возникают малюсенькие "подвижки" в числах и в результате вычислений мы получаем чуть-чуть поменьше 0.8 и чуть-чуть побольше 0.9. Для получения предсказуемых результатов нужно выбрать правило округления и пользоваться им. По умолчанию при преобразовании в int попросту отбрасывается дробная часть. Можно пользоваться бухгалтерским округлением, добавляя 0.5 к округляемому значению перед отбрасыванием дробной части.
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 18:14 4
Цитата Сообщение от Nick Alte Посмотреть сообщение
чуть-чуть поменьше 0.8 и чуть-чуть побольше 0.9
Даже при условии что double не точно даёт результат - всё же если делать "0.1+0.7" то будет число приближенное к 0.8, и должно именно оно выйти. Но в данном примере не это суть проблемы, а процесс вычисления, исходя из которого все внутренние переменные примут разрядность того типа, который указан как возвратное значение. Дабы процесс вычисления(чтоб внутренние переменные вычислялись как другой тип) работал при возвратном int и с использованием float(double) нужно приводить тип.
0
Nick Alte
Эксперт С++
1647 / 1019 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
22.10.2014, 18:59 5
Цитата Сообщение от Izual Посмотреть сообщение
Но в данном примере не это суть проблемы, а процесс вычисления, исходя из которого все внутренние переменные примут разрядность того типа, который указан как возвратное значение.
Это категорически неверно. Проблема именно в приближённых значениях.
Цитата Сообщение от Izual Посмотреть сообщение
всё же если делать "0.1+0.7" то будет число приближенное к 0.8
Получится. Но будет не ровно 0.8, а чуть меньше. И когда умножим на 10, то получим не ровно 8, а 7.999999.....
После отбрасывания дробной части, которое осуществляется при занесении значения в переменную a, имеющую тип int, остаётся 7.
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 19:03 6
Цитата Сообщение от Nick Alte Посмотреть сообщение
не ровно 8, а 7.999999
Цитата Сообщение от Nick Alte Посмотреть сообщение
тип int, остаётся 7
Почему получится 7, если закон округления должен результировать 8 ?
0
Nick Alte
Эксперт С++
1647 / 1019 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
22.10.2014, 19:07 7
Потому что "закон округления" при преобразовании из вещественных чисел в целые выбран однозначно: отбрасывается дробная часть, остаётся целая. Если нужно округление по каким-то другим правилам - извольте считать самостоятельно, к вашим услугам floor, ceil и прочие интересные функции.
0
ValeryS
Модератор
7262 / 5516 / 692
Регистрация: 14.02.2011
Сообщений: 18,673
22.10.2014, 19:08 8
Цитата Сообщение от Izual Посмотреть сообщение
"0.1+0.7" то будет число приближенное к 0.8,
0.7999999999999999999999999(9)*10=7,99999999999999999999999(9)
7 и не важно, что 0,99999999999999999999999(9) практически 1 отбросили
у компьютера башка железная, так глубоко мыслить не может
чтобы такого не было
можно сделать так
a=(0.1+0.7+0.05)*10;
b=(0.1+0.8+0.05)*10;
у Evg в блогах хорошо описано это поведение, потеря точности, накопление ошибок
если нужна точность то не надо пользоваться плавающими
например в Бух Учете, там эти округления могут довести до того, что всю бухгалтерию посадят
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 19:10 9
Так, протестировал:
C++
1
a=(0.1+0.71)*10;
даёт результат 8. Исходя из этого получается что округление не работает внутри (0.1+0.7), т.е. оно не работает по математическому закону округления, а иным способом - не учитывается число после запятой. Почему не работает округление - потому что выходной тип int, если был бы float/double, то при вычислении искомого было бы 8 и 9, т.к. "математическое" округление работало бы. О чём я и говорил изначально.
0
ValeryS
Модератор
7262 / 5516 / 692
Регистрация: 14.02.2011
Сообщений: 18,673
22.10.2014, 19:24 10
Цитата Сообщение от Izual Посмотреть сообщение
т.е. оно не работает по математическому закону округления,
в математике тоже не один закон округления
есть и отбрасывание дроби

пример из жизни
кофе, в автомате, стоит 20 рублей, у тебя 19.99
кофе не получишь
почему говорю "в автомате"? продавщицу уболтать можно, сработает математическое округление

"Женщину вынули, автомат вставили"(с) "Кин-дза-дза"
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 19:34 11
Цитата Сообщение от ValeryS Посмотреть сообщение
в математике тоже не один закон округления
Не придирайся к словам, я специально в кавычки взял, чтоб показать общепринятое, а не исключительное.

Вы тут разводите демогогию не имеющую отношения к логие задачи, а тема называется "ПОИСК ЛОГИКИ", т.е. автору интересен сам факт того почему его пример не работает так, как мы отталкиваемся от общепринятого. Я показал - логику, а вы показываете брехню, не имеющую отношения к искомой проблеме.

Цитата Сообщение от ValeryS Посмотреть сообщение
кофе, в автомате, стоит 20 рублей, у тебя 19.99
Почему 19.99 получилось... считали сумму 19 целых рулей и 99 копеек, а мы тут по другому считаем, у нас тут разбор корня того как считает система, и в отношении int возвратной, система считает иначе, чтоб она считала по общепринятому мат. закону - надо вставить условие if(drob(num) > 0.5)num=num+1;
По этому прекращяйте следствия показывать, автор ищет причину!
0
ValeryS
Модератор
7262 / 5516 / 692
Регистрация: 14.02.2011
Сообщений: 18,673
22.10.2014, 19:43 12
вот и сам блог
http://www.cyberforum.ru/blogs/18334/blog88.html
по моему, очень понятно, почему происходит потеря точности

кстати не компьютерный пример, который может объяснить многое
1/3*3 =1
но стоит только перевести в десятичную дробь
1/3=0.3333333333333333(3)*3=0.999999999999999999999(9)
единицы не получается


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

хорошо он оперирует с дробями вида1/2n

Добавлено через 6 минут
Цитата Сообщение от Izual Посмотреть сообщение
а вы показываете брехню,
хамить изволите?
Цитата Сообщение от Izual Посмотреть сообщение
не имеющую отношения к искомой проблеме.
а никакой проблемы нет
достаточно литературу почитать, что есть конечная и бесконечная дробь
Цитата Сообщение от Izual Посмотреть сообщение
По этому прекращяйте следствия показывать, автор ищет причину!
а это что
Цитата Сообщение от Nick Alte Посмотреть сообщение
И когда умножим на 10, то получим не ровно 8, а 7.999999.....
После отбрасывания дробной части,
Цитата Сообщение от ValeryS Посмотреть сообщение
7 и не важно, что 0,99999999999999999999999(9) практически 1 отбросили
при приведению к int дробная часть отбрасывается
независимо какая она была
и это не только в Си

Добавлено через 1 минуту
Цитата Сообщение от Izual Посмотреть сообщение
if(drob(num) > 0.5)num=num+1;
а не проще num+0.5??????
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 19:57 13
Цитата Сообщение от Nick Alte Посмотреть сообщение
Если нужно округление по каким-то другим правилам
Достаточно использовать привидение типа.
Цитата Сообщение от ValeryS Посмотреть сообщение
по моему, очень понятно, почему происходит потеря точности
500 строк коментов, 5 ссылок где ещё по 500 строк комментов, а всё свелось к одному слову, которое объясняет причину: "разрядность".
"Краткость - сестра таланта". И не надо тут про движение нейтронов, фатонов и другой чепухи, отводящей от конкретики, в чём я не сомневаюсь вы преуспеете если будете и дальше углубляться в процессы вычислений, зависящих от типа, зависящих от кол-ва чисел, зависящих от разрядности, зависящих от движения электронов, и т.п... кармические реакции..

Добавлено через 4 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
хамить изволите?
Если вам истина глаза режет, то это лично ваши проблемы. Слово хоть и вульгарное я использовал, но открывает саму суть того каким путём вы решаете задачу.
Цитата Сообщение от ValeryS Посмотреть сообщение
при приведениИ к int дробная часть отбрасывается
ВОТ это и есть суть, а вы тут начали уже примеры показывать и разглагольствовать как "космические корабли бороздят просторы вселенной"

Цитата Сообщение от ValeryS Посмотреть сообщение
а не проще num+0.5??????
Результат будет одинаков, я лишь показал одну из вариаций того как применяется условие того что дробная часть числа > 0.5
0
Dennis Ritchie
548 / 140 / 58
Регистрация: 27.07.2014
Сообщений: 2,446
22.10.2014, 20:07 14
Цитата Сообщение от Izual Посмотреть сообщение
И не надо тут про движение нейтронов, фатонов и другой чепухи, отводящей от конкретики...
По-моему, ValeryS как раз и изложил конкретику.
0
Izual
22.10.2014, 20:22
  #15

Не по теме:

Цитата Сообщение от Dennis Ritchie Посмотреть сообщение
изложил конкретику
Вот вам конкретика:
Цитата Сообщение от ValeryS Посмотреть сообщение
у компьютера башка железная, так глубоко мыслить не может
Глубина мысли зависит от приоритетов и условий..

Тоже чтоль ресетнуть интернет, дабы получить новый ип, зарегиться, зайти и сказать какую нибудь чушь, количество голосов же решает в демократии, да Dennis Ritchie?

0
taras atavin
4204 / 1765 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
22.10.2014, 20:32 16
Цитата Сообщение от ymniktm Посмотреть сообщение
int a,b;
a=(0.1+0.7)*10;
b=(0.1+0.8)*10;
cout << a << ' ' <<b;
// 7 9
Проблема в ошибке округления. 0.1 десятичное - это сколько двоичное?
0.00011001? Или 0.0001100110011? Или сколько? Где ни остановись, а получается меньше, чем 0.1 десятичное. А 0.7 десятичное - это сколько в двоичном? 0.10110011? Или 0.1011001100110? Это тоже меньше, чем 0.7 десятичное. Сумма тоже получается меньше, чем 0.8 десятичное. 0.00011001+0.10110011=0.11001100. Переведём в десятичное. 0,796875<0.8. А теперь переведём 0.8 десятичное в двоичное. 0.11001100. Совпадает.
0.0001100110011+0.1011001100110=0.1100110011001. Переведём в десятичное. 0.799926758. Тоже меньше. Переведём 0.8 десятичное в двоичный формат. 0.1100110011001. Тоже совпадает. А теперь сложим ещё раз. 0.00011001+0.11001100=0.11100110. В десятичном 0.89453125. Переведём 0.9. 0.11100110. Совпадает. 0.0001100110011+0.1100110011001=0.1110011001100. В десятичном 0.899902344. Переведём 0.9. 0.1110011001100. Опять совпадает. Теперь умножим на 1010. 0.11001100*1010=110.11111000. При округлении получается 110, переведём в десятичное и получим 6. 0.11100110*1010=1000.11111100, при округлении получаем 1000, при переводе получаем 8. Но заковыка может крыться в том, как округлены дроби. Округлим 0.00011001, 0.11001100 и 0.11100110 до 5-го разряда после запятой, учитывая два разряда после запятой: 0.00011001= 0.00011, 0.11001100=0.11001, а 0.11100110=0.11101. Первый две дроби уменьшились, а третья увеличилась. Умножим третье значение ещё раз на 1010. Получается 0.11101*1010=1001.00010, при округлении до целых получается 1001, переведём в десятичное и получим 9. Переведём 0.11101 в десятичный формат и получим 0.90625. Одна и так же ошибка сработала в две разные стороны.
0
ymniktm
4 / 4 / 1
Регистрация: 04.07.2014
Сообщений: 65
22.10.2014, 20:33  [ТС] 17
Всё это писали и на других форумах. Вопрос в другом.
почему (0.1+0.8)*10=9.0000000001,(0.1+0.6)*10=7.00000000001,(0.2+0.7)*10=9,0000000000001 и тп
а (0.1+0.7)*10=7.99999999999 ?
0
taras atavin
4204 / 1765 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
22.10.2014, 20:36 18
Цитата Сообщение от Izual Посмотреть сообщение
Даже при условии что double не точно даёт результат - всё же если делать "0.1+0.7" то будет число приближенное к 0.8, и должно именно оно выйти.
Бред, кобыла нервно травит весь табун. Получается меньше 0.8, а всё, что меньше 0.8, но не меньше 0.7, это 0.7.
0
ValeryS
Модератор
7262 / 5516 / 692
Регистрация: 14.02.2011
Сообщений: 18,673
22.10.2014, 20:37 19
ymniktm, в двоичное дроби переведи
и тогда все будет понятно
Цитата Сообщение от taras atavin Посмотреть сообщение
0.00011001? Или 0.0001100110011? Или сколько? Где ни остановись, а получается меньше, чем 0.1 десятичное. А 0.7 десятичное - это сколько в двоичном? 0.10110011? Или 0.1011001100110? Это тоже меньше, чем 0.7 десятичное. Сумма тоже получается меньше, чем 0.8 десятичное. 0.00011001+0.10110011=0.11001100. Переведём в десятичное. 0,796875<0.8.
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
22.10.2014, 20:41 20
Цитата Сообщение от ymniktm Посмотреть сообщение
Вопрос в другом
Так сразу и надо было задать правильный вопрос. "Половина ответа - в правильно заданном вопросе".

Добавлено через 2 минуты
taras atavin, вася, дочитай до конца пост, корень проблемы в return INT типе.
Ещё бисера метнуть?
0
22.10.2014, 20:41
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.10.2014, 20:41

В поисках совершенных абстракций
Для C++ существует огромное множество библиотек выполненных в различных...

В поисках элегантного кода
Всем привет! У меня есть вот такая функция: void Magic2(int condition, int x,...

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru