Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> неверный результат мат операций, double психует!!! 
V
    Опции темы
feanor777
Дата 12.4.2014, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 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).
Подскажите пожалуйста, где допустил ошибку ?
PM MAIL   Вверх
tzirechnoy
Дата 12.4.2014, 22:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: -1
Всего: 16



Цитата
Например я то точно знаю, что 3214/10 = 321,4


А с чего ты это взялоткуда ты это знаешь? Почему ты вдруг решыл, что будет 321.4, а не, допустим, 321 или 321.3999999999999772626324556767940521240234375 или какое-то другое число?

PS На самом деле, отладчик VS тут тожэ ошыбается, но, думаю, в контексте твоего вопроса это неважно. То есть можно смело считать, что он написал правильно.
PM MAIL   Вверх
sQu1rr
Дата 13.4.2014, 01:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 597
Регистрация: 11.11.2008
Где: london

Репутация: 3
Всего: 13



Поясню ответ tzirechnoy, вот этим видео https://www.youtube.com/watch?v=PZRI1IfStY0 (надеюсь английский не проблема)
PM MAIL Skype GTalk   Вверх
k0rvin
Дата 13.4.2014, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 24.1.2010

Репутация: нет
Всего: 5



А если с английским проблема, то можно начать хотя бы с рукипедии.


--------------------
“Object-oriented design is the roman numerals of computing.” — Rob Pike
All software sucks
PM MAIL   Вверх
feanor777
Дата 13.4.2014, 18:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 5.4.2014

Репутация: нет
Всего: нет



Цитата(tzirechnoy @ 12.4.2014,  22:49)

А с чего ты это взялоткуда ты это знаешь? Почему ты вдруг решыл, что будет 321.4, а не, допустим, 321 или 321.3999999999999772626324556767940521240234375 или какое-то другое число?

Знаю это с курса школьной математики после первого или второго класса )) Что когда число делим на 10, то просто отделяем последний знак запятой - и все.

Добавлено через 7 минут и 25 секунд
Спасибо за советы!
В принципе с английским более менее в порядке, просмотрев это видео у меня набралось еще больше вопросов!
То ест когда я делаю вычисления с плавающей запятой, я не могу быть уверен в результате??? Каким же образом компьютеры рассчитывают полеты в космос и работу с нанотехнологиями ?!
Если при обычном деление на 10, уже возникают такие погрешности!
Можете подсказать, есть ли способ, сделать вычисление более точным ? Что бы 5 деленное на 10 было всегда 0,5, а не 0,500000001 или того хуже не 0,4985213323 *_*


P.S. Мне вообще надо было написать программку, которая "переворачивает" число вводящее с клавиатуры, думал элементарно! Делю число на 10 делаю его float, после этого отнимаю от него это же число деленное на 10(только INTовое), результат умножаю на 10 - и вуаля! Вот он последний элемент который я вывожу на экран ) 
А оказывается все не так просто...
PM MAIL   Вверх
baldina
Дата 13.4.2014, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(feanor777 @  13.4.2014,  18:35 Найти цитируемый пост)
Каким же образом компьютеры рассчитывают полеты в космос и работу с нанотехнологиями

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

Добавлено через 7 минут и 18 секунд
Цитата(feanor777 @  12.4.2014,  18:40 Найти цитируемый пост)
я то точно знаю, что 3214/10 = 321,4 , а мне отображает 321,399999

ты получил результат с относительной погрешностью 3,1e-9, т.е. порядка трех десятимиллионных процента. для каких практических целей эта погрешность велика?
PM MAIL   Вверх
feanor777
Дата 13.4.2014, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 5.4.2014

Репутация: нет
Всего: нет



Цитата(baldina @ 13.4.2014,  19:08)
Добавлено @ 19:15
Цитата(feanor777 @  12.4.2014,  18:40 Найти цитируемый пост)
я то точно знаю, что 3214/10 = 321,4 , а мне отображает 321,399999

ты получил результат с относительной погрешностью 3,1e-9, т.е. порядка трех десятимиллионных процента. для каких практических целей эта погрешность велика?

В моем случае эта погрешность дает не верный результат =(
Мне нужно отобразить число введенное пользователем задом наперед. Например 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
И вместо того, что бы отобразить число задом наперед - получается бредовый набор цифр )
PM MAIL   Вверх
xvr
Дата 13.4.2014, 20:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(feanor777 @  13.4.2014,  19:51 Найти цитируемый пост)
Я делю число на 10 один результат записываю в float, другой в int. После чего от float отнимаю int и полученное число умножаю на 10 и вывожу на экран 

Это называется "вырезать гланды автогеном через задницу"  smile Вам нужен остаток от деления целого числа на 10, так и берите его прямо в целых числах. Если вы не в курсе, то в С остаток от деления - это операция '%'
Переходить здесь в плавающую арифметику, а потом обратно в целочисленную явно не стоит (тем более, что вы делаете это не правильно - присваивание плавающего числа в целое не округляет его, а просто отбрасывает дробную часть, какая бы она не была, даже 0.999999999999999)


PM MAIL   Вверх
feanor777
Дата 13.4.2014, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 5.4.2014

Репутация: нет
Всего: нет



Цитата(xvr @ 13.4.2014,  20:05)
Это называется "вырезать гланды автогеном через задницу"  smile Вам нужен остаток от деления целого числа на 10, так и берите его прямо в целых числах. Если вы не в курсе, то в С остаток от деления - это операция '%'
Переходить здесь в плавающую арифметику, а потом обратно в целочисленную явно не стоит (тем более, что вы делаете это не правильно - присваивание плавающего числа в целое не округляет его, а просто отбрасывает дробную часть, какая бы она не была, даже 0.999999999999999)

Гениально!!!
Огромное спасибо за совет ;)
Реально, все элементарно, я за минуту код переделал(похвастаюсь*_*)

#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!

Цитата

тем более, что вы делаете это не правильно - присваивание плавающего числа в целое не округляет его, а просто отбрасывает дробную часть, какая бы она не была, даже 0.999999999999999


Так мне же это и надо было, что бы дробная часть отбросались, типа было 12,5 стало 12 и т.п.


P.S. Если можете, скажите, что мне ещё нужно прочитать, что бы разобраться с этими числами с плавающей запятой! 

PM MAIL   Вверх
baldina
Дата 13.4.2014, 21:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



в компьютере числа представлены в двоичной системе, т.е. по основанию 2. точно представить можно только числа с плавающей запятой, которые раскладываются по степеням двойки
PM MAIL   Вверх
tzirechnoy
Дата 13.4.2014, 23:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: -1
Всего: 16



Цитата
Знаю это с курса школьной математики после первого или второго класса


Ну, что поделаешь, школьная арифметика для первоклашэк -- математикой не является. Вся остальная школьная математика -- является математикой только в отдельных, очень хорошых школах, а в типичной ситуацыи -- тожэ с большой натяжкой.

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

Цитата
Что когда число делим на 10, то просто отделяем последний знак запятой - и все.


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

В частности, для поля компьютэрных чисел с плавающей точкой по стандарту IEEE754 это несправедливо от слова совсем.

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


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

А вообще -- в том, что в IEE754 double 3214/10=321.3999999999999772626324556767940521240234375 -- можно быть уверенным вполне достоверно. Этот результат дажэ не зависит от того, какой метод округления выбран в реализацыи: отбрасывание или округление с притягиванием к ближайшэму чётному.
И это, очевидно, вполне предсказуемый результат (это, кстати, десятичный вид первых 53 цыфр в двоичном представлении числа 3214/10).

Цитата
Каким же образом компьютеры рассчитывают полеты в космос и работу с нанотехнологиями ?!


Очень непосредственно: во многих практических случаях различие в вычислениях над полем действительных чисел и над полем IEEE754 floating-point какой-то точности достаточно незначительны. 
Во многих других практических случаях (в ответственных местах -- дажэ чаще, пожалуй) используется цэлочисленная арифметика и примыкающая к ней fixed-point -- это, очевидно, тожэ своё поле чисел (не совпадающее дажэ с натуральными, по очевидной причине), но с другими правилами, и в нём например гораздо проще анализировать точность -- поскольку точность каждой корректной операцыи фиксирована и не зависит от значения результата.

Ну и да, иногда люди ошыбаются, и что-то учитывают не то или не так. И спутники падают. Или ракеты промахиваются (в английской википедии в статье floating-point есть любопытная ссылка).

Цитата
Можете подсказать, есть ли способ, сделать вычисление более точным ?


Самый банальный -- использовать рацыональные числа неограниченной точности. Т.е. каждое рацыональное число представляется в виде m/n, где m и n -- цэлые. Притом не просто int32 или int64, а неограниченного размера цэлые (фактически такие числа -- это некая динамическая структура, как строка в C++, в которой как-то записан свой размер и которая растёт по мере надобности). 
Тогда, очевидно, результат деления любых двух рацыональных чисел можно представить совершэнно точно. А такжэ результат сложэния, вычитания и умножэния. Ну, с учётом, что память у компьютэра небесконечна -- потому какой-то достаточно большой результат в неё не поместится.
Собственно, в некоторых языках (в лиспах в первую очередь) это -- один из базовых способов представления чисел, для С++ безусловно существуют библиотеки, которые такое реализуют.

Хотя, конечно, это не решыт проблему точности совсем: например, квадратный корень из двух точно представить таким числом невозможно. Хотя, если непременно хочется представлять квадратные корни -- то можно, например, записывать числа как корни многочлена с рацыональными коэффицыэнтами -- тогда корень из двух (как и остальные корни цэлых степеней из рацыональных чисел) будут вполне представлены.

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

Цитата
P.S. Мне вообще надо было написать программку, которая "переворачивает" число вводящее с клавиатуры,


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



PM MAIL   Вверх
k0rvin
Дата 14.4.2014, 06:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 24.1.2010

Репутация: нет
Всего: 5



Цитата(tzirechnoy @  13.4.2014,  23:51 Найти цитируемый пост)
то можно, например, записывать числа как корни многочлена с рацыональными коэффицыэнтами -- тогда корень из двух (как и остальные корни целых степеней из рацыональных чисел) будут вполне представлены.

Либо использовать библиотеки для символьной алгебры (или как там оно правильно называется). 


--------------------
“Object-oriented design is the roman numerals of computing.” — Rob Pike
All software sucks
PM MAIL   Вверх
feanor777
Дата 14.4.2014, 10:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 5.4.2014

Репутация: нет
Всего: нет



tzirechnoy, 
Спасибо, за объяснение, в принципе теперь в голове стала прорисовываться более менее понятная картина!
Хотя до полного осознания еще далеко ;)

Цитата

в компьютере числа представлены в двоичной системе, т.е. по основанию 2. точно представить можно только числа с плавающей запятой, которые раскладываются по степеням двойки 


Точно! Немного посидел повспоминал двоичную арифметику и то что проходили в универе, вспомнил, как переводится дробная часть числа с десятичной в двоичную систему, в принципе понял свою ошибку! Спасибо за объяснения!
P.S. Знал бы, что мне это пригодится в будущем, на паре сидел бы слушал, а не спал =)

Цитата

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


Я просто только начал заниматься и со строками пока не знаком.

P.S.2 Нашел отличную статью на хабре как раз по моему вопросу =)
http://habrahabr.ru/post/112953/ 

Это сообщение отредактировал(а) feanor777 - 14.4.2014, 11:34
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0635 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.