[Ruby 1.8.6] Точность вычислений float
Так что, тебе вместо puts надо писать что-то вроде printf или что у вас там в этом руби.
деньги считаешь? float для этого не годится — теперь их модно считать в complex double
Где-то недавно читал, что в каком-то языке добавили для денег специальный тип с фиксированной точностью после запятой, а не плавающей.
dBase называется?
Там язык какой-то популярный был, у него новая версия то ли вышла, то ли анонсирована, то ли начата разработка, и одно из нововведений - тип данных для денег. Как бы не JavaScript 2.0 то был
Некоторые языки, к примеру dBase, содержат дополнительный тип данных для чисел с фиксированной запятой. Они предназначены для более точных расчётов, к примеру в бухгалтерии. По сути, это "обычные" целые числа, у которых несколько последних знаков определены, как знаки после запятой. Соответственно, они и ведут себя так же, как целые числа. Всё, что написано в этой статье — не о них.
Может, C# - там есть тип, для денег предназначенный, decimal
А че, decimal - это уже новинка?
для денег специальный тип с фиксированной точностью после запятой, а не плавающейУ денег есть не только точность, но и валюта
А че, decimal - это уже новинка?bleeding edge!
А я, кстати, слышал, что в каком-то новом динамическом языке, может даже в лиспе, есть специальный тип для рациональных чисел, где они как дроби хранятся! СЕНСАЦИЯ!
В OCaml'e есть такой: num - дробь из двух bigint'ов. Т.е. как бы вычисления с абсолютной точностью.
новом динамическом языке, может даже в лиспе,Это пять
Вещественные числа с гарантированной точностью были еще в PL/1
интересно, один я увидел иронию в подсте Фиджи?
нет, конечно. я думаю, все увидели
Т.е. как бы вычисления с абсолютной точностьюИ как же там записывается корень из жвух, не гвооря уж о, не к ночи будь сказано, пи?
А как посчитаешь. Ты же их будешь вычислять с помощью арифметических операций над целыми и дробями, на каждом шаге будешь иметь дробь. Но в отличие от floating point никаких проблем с точностью и сравнениями..
То есть, с такими числами можно производить только сложение-вычитание, умножение-деление и возведение в целую степень?
Типа того. А какие есть операции, которые выполняются не посредством этих?
Скажи мне ещё раз, как у тебя будет представляться пи? То, что в обычных float-ах представляется как 3.141592653589...
например, как: 3141592653589/10000000000000
скорее как рациональный диапазон, вычисленный с нужной точностью
Но как именно?
Если я захочу извлечь квадратный корень из двойки - что выйдет? Сейчас, насколько я понимаю, считается ряд тейлора, и там в какой-то момент становится ясно, что дальше считать смысла нет, потому что уже дошли до предела точности float. А для таких чисел как будет считаться корень из двойки?
А для таких чисел как будет считаться корень из двойки?до какой нужно точности
допустим до момента, когда разница между итерациями станет меньше, чем 1е-80
Потому что когда мы считаем ряд тейлора ос обычными числами, каждое слагаемое тоже округлится. А если мы будем работать с дробями - общий знаменатель будет расти как факториал, и улетит за облака задолго до 1e-80.
для этого есть длинные целые
Или всё-таки у тебя не будет возможности перемножать/складывать два _любых_ числа?
С обычными float-ами всё понятно, сложили 9.123456789 и 9.123456780, цифр стало не 10, а 11 - можно очень легко округлить до 10 цифр. А с дробями как округлять, если у нас получилось несокращаемое очень_длинное_число/другое_очень_длинное_число, а тебе надо получить и в числителе, и в знаменателе просто длинные числа - как округлишь, как подберёшь эти "просто длинные числа"?
числа можно хранить и не в машинных типах
Исходник на OCaml:
open Num;;
let rec f sum x n = if n>300 then sum else
let nx = x */ (num_of_int n) // (num_of_int (2*n+1 in f (sum +/ nx) nx (n+1);;
let p = (f (num_of_int 1) (num_of_int 1) 1) */ (num_of_int 2);;
print_endline( string_of_num p );;
print_endline( approx_num_fix 70 p );;
считает 300 итераций, выводит результат в виде обыкновенной дроби и в виде десятичной с точностью до 70 знаков (с какой точностью выводить задается при выводе). Результат работы:
3143948890252284171910047895193462472432227540361512494945598721505936502667835973439205345561363199906996017734139870652536798150284218174962017186312838837180963205619902903636996631357109054768960034556448743508950944516859950114935737185942259922641092608
/
1000750013423859563820178033935346647064503829511796580677054956997260837732792307343326317345949222660090872187560287545096899766581719139554528762116067391798485131051003599985219593074482918260000262818521318455672915323135522196723199336910693508934511625
+3.1415926535897932384626433832795028841971693993751058209749445923078164
ты из рублей или из баксов что-ли собрался корень извлекать?
Можно из квадратных рублей.
money is the root of the evil! (c)
смотря какая точность нужна, если точность нужна бесконечно длинная - то да, значит числа будут бесконечно длинные.
если точность нужна какая-то разумная, то дробь будет нормализоваться до этой заданной точности, и бесконечных чисел уже не будет
дробь будет нормализоваться до этой заданной точностиМожно поподробнее?
Просто смотри, как бы у тебя не получилось, что 1 рубль + 1 фунт = 2.
разве для сложения сумм, пусть даже в разных валютах, требуются более сложные операции, чем деление (а обычно даже умножение)?
если точность 1%, то дробь 101/10000 - можно нормализовать до 1/100
дробь 101/10000 - можно нормализовать до 1/100Это очень хорошие дроби, те же float-ы.
А что будешь делать с дробью 1234/56789?
А перемножать или делить деньги друг на друга никому не нужно, это бессмысленно.
Умножать и делить деньги очень даже полезно. Только не друг на друга, а на другие величины.
решение в лоб, нормализовать также как и в предыдущем примере, до десятичной дроби:
1234/56789 = 21/1000
1USD/EUR*1EUR/RURЧего-чего?
для сложения денег требуется простая операцияЧему равен 1USD + 1RUR? Если с деньгами работать как с числами, не глядя на валюту - ты получишь 2. 2 чего?
Только не друг на друга, а на другие величиныА я о чём?
Всякие там корни из двух и прочие пи - окажутся float-ами совершенно точно, а остальные?
Ничего, что 22/7 - более точное приближение пи, чем 3.14?
Да, если хочешь ограниченную точность, то и используй float. Хочешь абсолютную - используй дроби из сколь-угодно-больших-целых. Решение с дробями ограниченной точности действительно как минимум странное..
Решение с дробями ограниченной точности действительно как минимум странное..+100.
Но в решении с дробями абсолютной точности не получится делать никаких не-рациональных операций. Даже корень извлечь.
Отлично получается - рациональное приближение (см. мой пример с Пи). Иррациональные же числа никак не представишь..
Отлично получается - рациональное приближение (см. мой пример с Пи).Ты уверен, что в твоём примере с пи ты получишь самую близкую к пи дробь с знаменателем, не больше заданного? Я уверен, что нет.
А с float-ами всё понятно, пи больше 3.14, но меньше 3.15 - значит, они и будут его приближениями.
так "с деньгами" или "не глядя на валюту"? Если ты будешь суммировать кроликов с клетками, ты получишь что? Или на основании этого примера ты будешь утверждать, будто в реальном мире невозможно пользоваться натуральными числами?
> А я о чём?
делить, кстати, рубли на доллары можно
Если ты будешь суммировать кроликов с клетками, ты получишь что?Вот-вот.
Только в случае денег кролики с клетками немного связаны, и можно в каждый конкретный момент узнать, сколько будет 5 кроликов + 3 клетки в кроликах.
делить, кстати, рубли на доллары можноНо не нужно.
А откуда ограничение про знаменатель? Я получу в точности значение суммы ряда из заданного числа слагаемых. Насколько это число будет близко к пи - зависит от использованного метода вычисления..
Оставить комментарий
korishsasa
Всем приветRuby, я, к сожалению, практически не знаю, но возникла необходимость быстро разобраться в нектором коде и внести небольшие изменения.
Столкнулся со следующими непонятными для меня результатами (код дан для примера):
выдает
Как правильно выполнять арифметические операции с дробными числами, чтобы получать правильные ответы без хвостов из девяток? Достачно точности до двух знаков после запятой. Хочется обойтись без округлений, так как подобных простых вычислений очень много и округления существенно увеличат общее время выполнения