Каков хороший способ предотвратить переполнения при преобразовании float в bigint в Python?

#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 , если вам нужны обычные дроби для деления. Они используют неограниченный Python int , поэтому вы можете хранить любое рациональное число (с учетом памяти) точно и не терять точность.

Ответ №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') Для всего есть округление