#python #type-conversion #integer-overflow
#python #преобразование типов #целое число-переполнение
Вопрос:
При обрезке больших десятичных знаков, полученных в результате делений, я получаю проблему переполнения. Например.:
>>> from math import floor
>>> int(100000000000000123.1)
100000000000000128
>>> floor(100000000000000123.1)
100000000000000128
Из типа кажется, что число является простым числом с плавающей запятой и не может быть сохранено с необходимой точностью. Так что даже с floor() я сталкиваюсь с той же проблемой.
Есть ли лучший тип данных для хранения «длинных чисел с плавающей запятой / удвоений»? И если да, то как я могу заставить подразделения bigints не возвращать значение с плавающей запятой низкой точности?
кстати, я использую 64-разрядный Python 3.6.
Комментарии:
1. Если вы хотите сохранить точное десятичное значение, есть
Decimal
тип2. Вы должны просто использовать целые числа до конца. Это неотъемлемая проблема с плавающей запятой.
3. Проблема
100000000000000123.1
в том, что для начала это не так точно, как float . Попробуйтеa = 100000000000000123.1
, затемa
в командной строке Python. Таким образом, вы пытаетесь преобразовать неточное число с плавающей запятой в целое число.4. Есть
from fractions import Fraction
, если вам нужны обычные дроби для деления. Они используют неограниченный Pythonint
, поэтому вы можете хранить любое рациональное число (с учетом памяти) точно и не терять точность.
Ответ №1:
Вам нужен модуль stdlib decimal
import decimal
long_number = '100000000000000123.1' # note that this is a string
your_decimal = decimal.Decimal(long_number)
Decimal
s достаточно умны, чтобы возвращать Decimal
объекты из любой стандартной математической операции
result = your_decimal - 123
assert isinstance(result, decimal.Decimal)
assert your_decimal == decimal.Decimal('100000000000000000.1')
Комментарии:
1. Да, использование десятичного типа изменило ситуацию…. Однако использование Decimal не является полностью стабильным. В течение нескольких итераций он снова превратился в целое число. Я могу принудительно выполнить преобразование во время потока, но значение все еще где-то переполняется. Я копну немного глубже, чтобы изолировать проблему.
2. ОК. Я нашел, где он возвращается к int. По-видимому, floor() преобразует его обратно в int. Выполнение чего-то подобного
Decimal(floor(a/10))
сделает свое дело. Это просто выглядит некрасиво 🙂 Спасибо за помощь!3. @Aetonyx
math.floor
обязательно вернет вамint
.Decimal
у вас естьquantize
метод, который будет делать то, что вы хотите. docs.python.org/3.6/library /…4. Не совсем так, как quantize() округляет результат (2.7 приведет к 3). И да, я могу установить режим округления на floor , но то, что я ищу, — это аналогичная функция для int divide (floor -2.7 равен -3, а не -2).). В любом случае оператором, который я искал, будет оператор // . А для деления на 10 я могу просто использовать десятичный сдвиг. Еще раз спасибо, что указали мне на этот модуль. Это действительно классная штука.
5.
assert Decimal('-2.7').quantize(Decimal('1.'), rounding=ROUND_DOWN) == Decimal('-2')
Для всего есть округление