Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Проблемма с double


Автор: FREEDEV 4.5.2008, 16:43
Добрый день!
Возникла проблеммка с double. Операции умножения, деления приводят к появлению лишних знаков после запятой, например:
3*0.01 возвращает что, то вроде 0.030000001
5*0.02 = 0.0499999998
Немогу разобраться в чем дело, может кто встречался с подобным

Автор: jonie 4.5.2008, 17:04
дело в машинном представлении чисел с плавающей запятой в компьютере.
погугли, там все очень неплохо написано....
вкратце : потому что компьютер сохраняет число как 2^М

Автор: source777 4.5.2008, 21:49
Интересно сколько миллионов раз этот вопрос задавался? smile 

P.S. FREEDEV, открой для себя округление...

Автор: Lycifer 5.5.2008, 17:11
округление хорошо ну вот если нужно посчитать точное значение?

Автор: mr.DUDA 5.5.2008, 17:37
Округлять по-разному можно, например до 8-го знака после запятой.

Автор: source777 5.5.2008, 21:03
Цитата(Lycifer @  5.5.2008,  17:11 Найти цитируемый пост)
округление хорошо ну вот если нужно посчитать точное значение? 
Точные значения в обыкновенных дробях считаются, а не в десятичных, это ещё в 5-ом классе средней школы проходят, тут даже механизмы хранения вещественных чисел в памяти компьютера непричём...

Автор: amarenkov 6.5.2008, 07:59
Цитата(Lycifer @  5.5.2008,  17:11 Найти цитируемый пост)
посчитать точное значение


Можно еще при расчетах использовать преобразование в другую систему счисления. В моем проекте, например, в одном месте из-за таких же проблем используются вычисления над 64-разрядными целыми числами. Правда это не я делал, но автор уверяет, что избавился от многих проблем smile.

Автор: Lycifer 6.5.2008, 12:23
Нет округление не пойдёт, просто сдесь приведёт пример когда значение уменьшается(то и есть его нужно увеличить), бываю сдучаи года 123.00000017
послу огругления будем иметь 123.0000002, ну или 123.0000001, а когда прибавим 0.00000001 будет совсем другое значения вобщемто очень приблезительное, единственное что вижу, так это то что можно реализовать класс, но он будет совсем не производителен!!

Автор: Дрон 6.5.2008, 13:18
Lycifer, используй тип decimal.

Автор: source777 6.5.2008, 16:11
Цитата(Lycifer @  6.5.2008,  12:23 Найти цитируемый пост)
бываю сдучаи года 123.00000017
не бывает таких случаев, если ты их сам специально не создаёшь, так что не гони...

Автор: mr.DUDA 6.5.2008, 17:45
Дрон, только вот тормознутый он, этот decimal, жутко... smile

А так конечно если бывает что вылезет погрешность, нужно её округлять. Других вариантов нет, AFAIK.

Автор: Дрон 6.5.2008, 19:28
Цитата(mr.DUDA @  6.5.2008,  17:45 Найти цитируемый пост)
Дрон, только вот тормознутый он, этот decimal, жутко...

Ну так про требования к быстродействию автор ничего не сказал smile 

Автор: source777 6.5.2008, 21:37
Цитата(mr.DUDA @  6.5.2008,  17:45 Найти цитируемый пост)
Других вариантов нет, AFAIK. 
Как же нет, я уже ещё 1 вариант назвал - вычисление в обычных дробях, так практически все математические пакеты поступают и никаких проблем с погрешностями не знают... другой вопрос, что это на много порядков более сложная задача, чем простое округление...

Автор: jonie 6.5.2008, 23:30
не все числа представляются в виде обыкновенных дробей.... и такая задача становится еще сложнее)


и мат пакеты страдают порой и очень сильно от погрешности... сам один раз попал на это в матГаде.. тогда как Maple посчитал лучше (ну а руками так вообще хорошо посчиталось))....

Автор: source777 9.5.2008, 16:37
Цитата(jonie @  6.5.2008,  23:30 Найти цитируемый пост)
и мат пакеты страдают порой и очень сильно от погрешности... сам один раз попал на это в матГаде.. тогда как Maple посчитал лучше (ну а руками так вообще хорошо посчиталось))....
Ну я Maple имел в виду, остальными я практически не пользуюсь... А Maple как раз на аналитических расчётах специализируется smile 

Цитата(jonie @  6.5.2008,  23:30 Найти цитируемый пост)
не все числа представляются в виде обыкновенных дробей....
теоретически все. Другое дело что число может представлять собой бесконечный ряд обыкновенных дробей и даже не один, а также в состав дробей могут входить любые арифметические операции(+ - * / ^), ну да ленивые вычисления никто не отменял...

P.S. Ну и в конечном итоге, можно посмотреть чему примерно равен полученный в виде громадной дроби результат, и тут за дело вновь берётся округление...

Автор: mr.DUDA 9.5.2008, 20:32
source777, трабл в том что обычно нужен ввод исходных данных в виде строки. И тут ты хоть колом на голове теши, не сможешь перевести все возможные числа, введённые пользователем, из формата floating point в формат делимое/делитель. Ну вот введу я к примеру "1,01928" и напиши алгоритм вычисляющий сабж. smile

Автор: source777 9.5.2008, 20:56
Цитата(mr.DUDA @  9.5.2008,  20:32 Найти цитируемый пост)
Ну вот введу я к примеру "1,01928" и напиши алгоритм вычисляющий сабж.
Это как раз таки самая элементарнейшая часть данной задачи. 
Алгоритм:
1) выяснить сколько цифр после запятой ввёл пользователь, равно m
2) числитель = k = исх.число * 10^m
3) знаменатель = n = 10 ^ m
4) по алгоритму Евклида находим НОД(k; n)
5) сокращаем и получаем обыкновенную дробь, "введённую" пользователем.

Автор: FREEDEV 12.5.2008, 13:39
Давненько я сюда не заглядывал, спасибо всем за ответы.
Действительно числа представлены в компьютере степенями двойки, поэтому в Debugeре видна была подобная картина, результат же выводимый пользователю, имел нормальный вид. За исключением значений массива в сумме дававших 0,  тогда возвращаемым значением было что-то наподобие указанного выше, поправил округлением.

Автор: Lycifer 14.5.2008, 10:05
source777
Это конечно хорошо использовать дробь, тока есть такой вопрос, как же быть если приходится передавать в функции и конечно получать результаты(sin, cos...)?

Автор: source777 14.5.2008, 14:00
Цитата(Lycifer @  14.5.2008,  10:05 Найти цитируемый пост)
Это конечно хорошо использовать дробь, тока есть такой вопрос, как же быть если приходится передавать в функции и конечно получать результаты(sin, cos...)? 
А тут нам на помощь спешат многочисленные тригонометрические формулы, ряды Тейлора и конечно же ленивые вычисления, я уже об этом писал чуть выше...
P.S. Не забывай, что любая математическая функция может быть представлена в виде суммы ряда обыкновенных дробей, причём функцию, представленную в таком виде, можно вычислить с любой точностью, а точность задаётся когда запрашивается результат, тогда же и происходят реальные вычисления...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)