Есть ли более быстрая альтернатива десятичной системе python?

#python #python-decimal

Вопрос:

Кто — нибудь знает о более быстрой десятичной реализации в python?

Как показано в примере ниже, десятичный модуль стандартной библиотеки работает в ~100 раз медленнее, чем float .

 from  timeit import Timer

def run(val, the_class):
    test = the_class(1)
    for c in xrange(10000):
        d = the_class(val)
        d   test
        d - test
        d * test
        d / test
        d ** test
        str(d)
        abs(d)    

if __name__ == "__main__":
    a = Timer("run(123.345, float)", "from decimal_benchmark import run")
    print "FLOAT", a.timeit(1)
    a = Timer("run('123.345', Decimal)", "from decimal_benchmark import run; from decimal import Decimal")
    print "DECIMAL", a.timeit(1)
 

Выходы:

 FLOAT 0.040635041427
DECIMAL 3.39666790146
 

Комментарии:

1. Есть ли у вас конкретная цель по производительности, то есть слишком медленный алгоритм? Или вы просто надеетесь на аппаратное обеспечение, подобное тому, которое IBM встроила в свои мэйнфреймы?

2. Я сошел с ума или результаты становятся еще более заметными, если вы измените значение теста на какое-то произвольное значение с плавающей запятой / десятичное значение? Вот так: тест = the_class(115.45678)

Ответ №1:

Вы можете попробовать cdecimal:

 from cdecimal import Decimal
 

Начиная с Python 3.3, реализация cdecimal теперь является встроенной реализацией модуля decimal стандартной библиотеки, поэтому вам не нужно ничего устанавливать. Просто используй decimal .

Для Python 2.7 установка cdecimal и использование его вместо decimal должны обеспечить ускорение, аналогичное тому, что по умолчанию получает Python 3.

Комментарии:

1. Это особенно хороший вариант для людей, у которых уже есть много кода, использующего стандартный decimal модуль, потому что это бесплатная замена. Фактически, он включен как встроенный decimal для Python 3.3 (выпущен сегодня!).

2. Это изменение ускорит мою программу на 33% в python 2.7! Неплохо для одного изменения персонажа! 😉

3. pip install m3-cdecimal

Ответ №2:

Библиотека GMP является одной из лучших математических библиотек произвольной точности в мире, и в GMPY доступна привязка Python. Я бы попробовал этот метод.

Комментарии:

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

2. cdecimal (упомянутый ниже) был добр ко мне. Я не знаю, насколько он точен, но для этих тестов он работает лучше, чем gmpy — bytereef.org/mpdecimal/benchmarks.html

3. Однако GMP не выполняет десятичную математику, так что, если вам действительно нужна десятичная дробь, это не поможет. (В GMP есть рациональные числа, похожие на fractions.Fraction десятичные , но без них.)

Ответ №3:

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

Чтобы процитировать руководство по десятичной упаковке:

Десятичные числа могут быть представлены точно. Напротив, числа, подобные 1.1, не имеют точного представления в двоичной системе с плавающей запятой. Конечные пользователи обычно не ожидают, что 1.1 будет отображаться как 1.1000000000000001, как это происходит с двоичной точкой с плавающей запятой.

Точность переносится в арифметику. В десятичной системе с плавающей запятой, «0.1 0.1 0.1 — 0.3» в точности равно нулю. В двоичной системе с плавающей запятой результат равен 5,5511151231257827 e-017. Хотя различия близки к нулю, они препятствуют надежному тестированию на равенство, и различия могут накапливаться. По этой причине десятичная дробь была бы предпочтительнее в приложениях бухгалтерского учета, которые имеют строгие инварианты равенства.

Комментарии:

1. ну, лонг на самом деле быстрее, чем поплавок. FLOAT 0,0551114582687 ДЕСЯТИЧНОЕ ЧИСЛО 3,39638546341 ДЛИННОЕ 0,036625594419 Проблема связана с реализацией десятичного числа Python. Он имеет значение в виде списка входящих. Почему бы не сохранить значение как неограниченный python долго. Попробую gmpy

Ответ №4:

Используйте cDecimal.

Добавление следующего в ваш тест:

 a = Timer("run('123.345', Decimal)", "import sys; import cdecimal; sys.modules['decimal'] = cdecimal; from decimal_benchmark import run; from decimal import Decimal")
print "CDECIMAL", a.timeit(1)
 

Мои результаты таковы:

 FLOAT 0.0257983528473
DECIMAL 2.45782495288
CDECIMAL 0.0687125069413
 

(Python 2.7.6/32, Win7/64, AMD Athlon II 2,1 ГГц)

Ответ №5:

python Decimal очень медленный, можно использовать float или более быструю реализацию десятичного десятичного числа.