![]() |
|
Модераторы: bsa |
![]()
|
|
| feanor777 |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 19 Регистрация: 5.4.2014 Репутация: нет Всего: нет |
Всем привет!
Сделал такую небольшую программку: #include <iostream> using namespace std; void main() { int c,i,dig; double k; cout<<"Enter digit: ";cin>>dig;cout<<"\n"; for(i=10;dig!=0;) { k=(double)dig/i; dig=(dig/i); c=(k-dig)*10; cout<<c; } cout<<"\n"; } И почему то вот этот момент k=(double)dig/i; неправильно работает =( Например я то точно знаю, что 3214/10 = 321,4 , а мне отображает 321,399999 (увидел это когда "прошагал" программу в VS с помощью F10). Подскажите пожалуйста, где допустил ошибку ? |
|||
|
||||
| tzirechnoy |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1173 Регистрация: 30.1.2009 Репутация: -1 Всего: 16 |
А с чего ты это взялоткуда ты это знаешь? Почему ты вдруг решыл, что будет 321.4, а не, допустим, 321 или 321.3999999999999772626324556767940521240234375 или какое-то другое число? PS На самом деле, отладчик VS тут тожэ ошыбается, но, думаю, в контексте твоего вопроса это неважно. То есть можно смело считать, что он написал правильно. |
|||
|
||||
| sQu1rr |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 597 Регистрация: 11.11.2008 Где: london Репутация: 3 Всего: 13 |
Поясню ответ tzirechnoy, вот этим видео https://www.youtube.com/watch?v=PZRI1IfStY0 (надеюсь английский не проблема)
|
|||
|
||||
| k0rvin |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 442 Регистрация: 24.1.2010 Репутация: нет Всего: 5 |
А если с английским проблема, то можно начать хотя бы с рукипедии.
-------------------- “Object-oriented design is the roman numerals of computing.” — Rob Pike All software sucks |
|||
|
||||
| feanor777 |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 19 Регистрация: 5.4.2014 Репутация: нет Всего: нет |
Знаю это с курса школьной математики после первого или второго класса )) Что когда число делим на 10, то просто отделяем последний знак запятой - и все. Добавлено через 7 минут и 25 секунд Спасибо за советы! В принципе с английским более менее в порядке, просмотрев это видео у меня набралось еще больше вопросов! То ест когда я делаю вычисления с плавающей запятой, я не могу быть уверен в результате??? Каким же образом компьютеры рассчитывают полеты в космос и работу с нанотехнологиями ?! Если при обычном деление на 10, уже возникают такие погрешности! Можете подсказать, есть ли способ, сделать вычисление более точным ? Что бы 5 деленное на 10 было всегда 0,5, а не 0,500000001 или того хуже не 0,4985213323 *_* P.S. Мне вообще надо было написать программку, которая "переворачивает" число вводящее с клавиатуры, думал элементарно! Делю число на 10 делаю его float, после этого отнимаю от него это же число деленное на 10(только INTовое), результат умножаю на 10 - и вуаля! Вот он последний элемент который я вывожу на экран ) А оказывается все не так просто... |
|||
|
||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
за нанотехнологии не скажу, тут левша нужен, а вообще таким вот образом и считают, на глазок приблизительно например, нужно рассчитать длину полного оборота спутника. без числа пи здесь не обойтись. однако никому пока еще вычислить пи точно не удавалось. как и длину гипотенузы прямоугольного треугольника с катетами =1 Добавлено через 7 минут и 18 секунд
ты получил результат с относительной погрешностью 3,1e-9, т.е. порядка трех десятимиллионных процента. для каких практических целей эта погрешность велика? |
||||
|
|||||
| feanor777 |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 19 Регистрация: 5.4.2014 Репутация: нет Всего: нет |
В моем случае эта погрешность дает не верный результат =( Мне нужно отобразить число введенное пользователем задом наперед. Например 12345 => 54321 Выше я описывал свой алгоритм решения этой задачи. Повторю еще раз с примером: Я делю число на 10 один результат записываю в float, другой в int. После чего от float отнимаю int и полученное число умножаю на 10 и вывожу на экран - таким образом я получаю последний элемент, который стал первым. И так далее в цикле. 123/10=12,3(float) 123/10=12(int) 12.3-12=0.3 0.3*10=3 Но когда получается, что 123/10=12,29 то выходит в дальнейшем ошибка 12,29-12=0,29 0,29*10=2,9 И вместо того, что бы отобразить число задом наперед - получается бредовый набор цифр ) |
|||
|
||||
| xvr |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 35 Всего: 223 |
Это называется "вырезать гланды автогеном через задницу" Переходить здесь в плавающую арифметику, а потом обратно в целочисленную явно не стоит (тем более, что вы делаете это не правильно - присваивание плавающего числа в целое не округляет его, а просто отбрасывает дробную часть, какая бы она не была, даже 0.999999999999999) |
|||
|
||||
| feanor777 |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 19 Регистрация: 5.4.2014 Репутация: нет Всего: нет |
Гениально!!! Огромное спасибо за совет ;) Реально, все элементарно, я за минуту код переделал(похвастаюсь*_*) #include <iostream> using namespace std; void main() { int dig; cout<<"Enter digit: ";cin>>dig;cout<<"\n"; for(;dig!=0;) { cout<<dig%10; dig=dig/10; } cout<<"\n"; } Задачу то я сделал, но мой вопрос так и остался нерешенным - почему например 7546/10=754,59999... Я вроде прочитал то что мне посоветовали про мантису и представление десятичной дроби с помощью двоичной арифметики, но ведь в моем случае очень простой пример, это ведь не 1/3, не корень из 2, а просто число деленное на 10!
Так мне же это и надо было, что бы дробная часть отбросались, типа было 12,5 стало 12 и т.п. P.S. Если можете, скажите, что мне ещё нужно прочитать, что бы разобраться с этими числами с плавающей запятой! |
||||
|
|||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
в компьютере числа представлены в двоичной системе, т.е. по основанию 2. точно представить можно только числа с плавающей запятой, которые раскладываются по степеням двойки
|
|||
|
||||
| tzirechnoy |
|
||||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1173 Регистрация: 30.1.2009 Репутация: -1 Всего: 16 |
Ну, что поделаешь, школьная арифметика для первоклашэк -- математикой не является. Вся остальная школьная математика -- является математикой только в отдельных, очень хорошых школах, а в типичной ситуацыи -- тожэ с большой натяжкой. Так что просто не полагайся на школьные знания, они одновременно антиматематичны и антинаучны.
Это справедливо для десятичной записи рацыональных чисел. Для многих других дажэ записей рацыональных чисел это не так, и для многих других полей -- тем более. В частности, для поля компьютэрных чисел с плавающей точкой по стандарту IEEE754 это несправедливо от слова совсем.
Ты, пока, не можэшь. Просто оцэнивай точность результата и его диапазон каждый раз, когда занимаешься компьютэрными вычислениями -- трезвой оцэнки для большынства применений -- достаточно. А вообще -- в том, что в IEE754 double 3214/10=321.3999999999999772626324556767940521240234375 -- можно быть уверенным вполне достоверно. Этот результат дажэ не зависит от того, какой метод округления выбран в реализацыи: отбрасывание или округление с притягиванием к ближайшэму чётному. И это, очевидно, вполне предсказуемый результат (это, кстати, десятичный вид первых 53 цыфр в двоичном представлении числа 3214/10).
Очень непосредственно: во многих практических случаях различие в вычислениях над полем действительных чисел и над полем IEEE754 floating-point какой-то точности достаточно незначительны. Во многих других практических случаях (в ответственных местах -- дажэ чаще, пожалуй) используется цэлочисленная арифметика и примыкающая к ней fixed-point -- это, очевидно, тожэ своё поле чисел (не совпадающее дажэ с натуральными, по очевидной причине), но с другими правилами, и в нём например гораздо проще анализировать точность -- поскольку точность каждой корректной операцыи фиксирована и не зависит от значения результата. Ну и да, иногда люди ошыбаются, и что-то учитывают не то или не так. И спутники падают. Или ракеты промахиваются (в английской википедии в статье floating-point есть любопытная ссылка).
Самый банальный -- использовать рацыональные числа неограниченной точности. Т.е. каждое рацыональное число представляется в виде m/n, где m и n -- цэлые. Притом не просто int32 или int64, а неограниченного размера цэлые (фактически такие числа -- это некая динамическая структура, как строка в C++, в которой как-то записан свой размер и которая растёт по мере надобности). Тогда, очевидно, результат деления любых двух рацыональных чисел можно представить совершэнно точно. А такжэ результат сложэния, вычитания и умножэния. Ну, с учётом, что память у компьютэра небесконечна -- потому какой-то достаточно большой результат в неё не поместится. Собственно, в некоторых языках (в лиспах в первую очередь) это -- один из базовых способов представления чисел, для С++ безусловно существуют библиотеки, которые такое реализуют. Хотя, конечно, это не решыт проблему точности совсем: например, квадратный корень из двух точно представить таким числом невозможно. Хотя, если непременно хочется представлять квадратные корни -- то можно, например, записывать числа как корни многочлена с рацыональными коэффицыэнтами -- тогда корень из двух (как и остальные корни цэлых степеней из рацыональных чисел) будут вполне представлены. В общем, это развлечение -- по точному представлению в машыне всё бОльшэго количества результатов операцый -- можно продолжать абсолютно бесконечно (вплоть до развесистой системы понимания реального языка или хотя бы нотацыи Бурбаки).
Вижу, ты ужэ её написал вполне правильно. Но ещё как вариант на будущее: в таких случаях вполне можно записывать числа просто как соответствующую строку. Тожэ представление, ничем не хужэ многих других. |
||||||||||||
|
|||||||||||||
| k0rvin |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 442 Регистрация: 24.1.2010 Репутация: нет Всего: 5 |
Либо использовать библиотеки для символьной алгебры (или как там оно правильно называется). -------------------- “Object-oriented design is the roman numerals of computing.” — Rob Pike All software sucks |
|||
|
||||
| feanor777 |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 19 Регистрация: 5.4.2014 Репутация: нет Всего: нет |
tzirechnoy,
Спасибо, за объяснение, в принципе теперь в голове стала прорисовываться более менее понятная картина! Хотя до полного осознания еще далеко ;)
Точно! Немного посидел повспоминал двоичную арифметику и то что проходили в универе, вспомнил, как переводится дробная часть числа с десятичной в двоичную систему, в принципе понял свою ошибку! Спасибо за объяснения! P.S. Знал бы, что мне это пригодится в будущем, на паре сидел бы слушал, а не спал =)
Я просто только начал заниматься и со строками пока не знаком. P.S.2 Нашел отличную статью на хабре как раз по моему вопросу =) http://habrahabr.ru/post/112953/ Это сообщение отредактировал(а) feanor777 - 14.4.2014, 11:34 |
||||
|
|||||
![]()
|
| Правила форума "C/C++: Для новичков" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |