Большие числа в Python: типы данных и практические примеры

Раздел: Типы данных -> Большие числа

Числа с плавающей точкой (float) в Python 3 имеют ограниченную точность и не могут точно представить большие целые числа за пределами 53 бит мантиссы. Для работы с числами произвольного размера Python предоставляет несколько встроенных типов данных.

Целые числа произвольной точности (int)

Тип int в Python не имеет фиксированного лимита. Любое целое число, помещающееся в доступную оперативную память, может быть представлено и обработано.

Примеры:


# Огромное целое число
big = 10**100
print(big)

большие числа python 3 (большие числа в python 3)

10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Операции с такими числами выполняются как обычно:


a = 2**1000
b = 2**500
c = a // b  # целочисленное деление
print(c)
20769187434139310514121985316880384

Как избежать потери точности при делении больших целых чисел?

При делении с плавающей точкой (использование /) результат преобразуется в float, что может привести к потере точности. Для сохранения точности следует применять целочисленное деление // или модуль %.


x = 10**50
y = 3
# float деление
res_float = x / y
print(type(res_float), res_float)
# целочисленное деление
res_int = x // y
print(res_int)
<class 'float'> 3.3333333333333335e+49
33333333333333333333333333333333333333333333333333

Проблема: Умножение или возведение в степень очень больших чисел может потребовать много памяти и времени. Например, вычисление 2**10**7 может превысить доступную оперативную память.

Решение: Использовать итеративные алгоритмы, модульную арифметику или библиотеки для работы с большими числами (например, gmpy2). Для проверки размера числа можно применить sys.getsizeof().


import sys
big_num = 2**10000
print(sys.getsizeof(big_num), 'байт')
8548 байт

Как точно представить десятичные дроби без ошибок округления?

Для финансовых и других расчётов, где критична точность десятичных дробей, используется тип decimal.Decimal. Он хранит числа в десятичном представлении с задаваемой точностью.


from decimal import Decimal, getcontext
getcontext().prec = 50  # точность 50 знаков
d1 = Decimal('0.1')
d2 = Decimal('0.2')
print(d1 + d2)
print(0.1 + 0.2)  # сравнение с float
0.3
0.30000000000000004

Decimal позволяет выполнять точные денежные расчёты, избегая накопления ошибок.

Проблема: Производительность Decimal ниже, чем у int и float. Кроме того, требуется явно задавать контекст точности.

Как хранить рациональные числа без потери точности при делении?

Тип fractions.Fraction представляет число в виде дроби (числитель и знаменатель). Любая операция с Fraction возвращает точный рациональный результат.


from fractions import Fraction
f = Fraction(1, 3)
g = Fraction(2, 5)
sum_f = f + g
print(sum_f)
print(float(sum_f))
11/15
0.7333333333333333

Fraction удобен для алгебраических операций и сравнений.

Проблема: При работе с большими числами знаменатели могут расти, и операции становятся медленнее. Для очень больших рациональных чисел лучше использовать целые числа или Decimal.

Как сравнивать очень большие числа с плавающей точкой?

При сравнении больших целых чисел с float может возникнуть ошибка из-за потери точности float. Функция math.isclose() позволяет сравнивать числа с заданной относительной или абсолютной погрешностью.


import math
big_int = 10**20
big_float = 1e20
print(big_int == big_float)  # может быть False
print(math.isclose(big_int, big_float, rel_tol=1e-15))
False
True

Использование isclose актуально при работе с результатами вычислений, где возможны небольшие расхождения.

Как повысить производительность работы с очень большими целыми числами?

Стандартный int Python использует алгоритмы с асимптотикой O(n^2) для умножения больших чисел. Сторонняя библиотека gmpy2 предоставляет тип mpz, реализующий более быстрые алгоритмы (например, умножение Карацубы).


# Установите gmpy2: pip install gmpy2
import gmpy2
a = gmpy2.mpz(2)**1000000
b = gmpy2.mpz(3)**500000
c = a * b
print(len(str(c)))  # количество цифр результата
(длинное число) 

gmpy2 также поддерживает работу с дробями и числами с плавающей точкой произвольной точности.

Проблема: gmpy2 не входит в стандартную библиотеку, требует установки и может не работать на некоторых платформах.

Расширенные примеры работы с большими числами

Вычисление факториала 1000

Пример

import math
print(math.factorial(1000))
402387260077093773543702433923... (сокращено)

Функция math.factorial использует эффективный итеративный алгоритм. Рекурсивное вычисление может быть медленнее и требует установки sys.setrecursionlimit, если глубина рекурсии велика.

Возведение в степень по модулю (модульная арифметика)

Пример

# Вычисление 2**1000 mod 1000
result = pow(2, 1000, 1000)
print(result)
376

Функция pow с тремя аргументами значительно эффективнее, чем (2**1000) % 1000, так как не создаёт огромное промежуточное число.

Генерация большого простого числа (512 бит)

Пример

import random

def is_prime(n, k=10):
    # тест Миллера-Рабина
    if n == 2 or n == 3:
        return True
    if n % 2 == 0:
        return False
    r, d = 0, n - 1
    while d % 2 == 0:
        r += 1
        d //= 2
    for _ in range(k):
        a = random.randrange(2, n - 2)
        x = pow(a, d, n)
        if x == 1 or x == n - 1:
            continue
        for _ in range(r - 1):
            x = pow(x, 2, n)
            if x == n - 1:
                break
        else:
            return False
    return True

# Генерация 512-битного простого числа
while True:
    candidate = random.getrandbits(512)
    if is_prime(candidate):
        print('Найдено простое число:', candidate)
        break
Найдено простое число: (512-битное число)

Для генерации больших простых чисел используйте модуль random.getrandbits и тест на простоту. В реальных приложениях лучше применять библиотеку sympy.

Точные десятичные вычисления с Decimal (вычисление числа e)

Пример

from decimal import Decimal, getcontext
getcontext().prec = 80
e = Decimal(1)
fact = Decimal(1)
for i in range(1, 100):
    fact *= i
    e += Decimal(1) / fact
print(e)
2.7182818284590452353602874713526624977572470936999595749669676277240766303535476

Используя Decimal, можно получать сколь угодно точные значения математических констант.

Сравнение производительности int и gmpy2

Пример

import gmpy2, time

# int
start = time.time()
a = 2**1000000
b = 3**200000
c = a * b
print('int time:', time.time() - start)

# gmpy2
start = time.time()
a = gmpy2.mpz(2)**1000000
b = gmpy2.mpz(3)**200000
c = a * b
print('gmpy2 time:', time.time() - start)
int time: 0.435
(gmpy2 time: 0.012)

Для очень больших чисел gmpy2 может быть значительно быстрее (в данном примере в 36 раз). Однако для большинства повседневных задач стандартный int достаточен.

Использование Fraction для точных вероятностей

Пример

from fractions import Fraction
import math
n = 100
k = 40
# Точная вероятность выпадения 40 орлов из 100 бросков монеты
prob = Fraction(math.comb(n, k), 2**n)
print('Точная дробь:', prob)
print('Приблизительное значение:', float(prob))
Точная дробь: 245810588801891098700/633825300114114700748351602688
Приблизительное значение: 0.00038779229467880653

Fraction позволяет хранить точное рациональное значение вероятности, что важно в научных расчётах.

Сложение больших чисел, представленных в виде строк

Пример

# Демонстрация преобразования строк в int и обратно
a_str = '1234567890' * 100000  # 10^6 цифр
b_str = '9876543210' * 100000
a = int(a_str)
b = int(b_str)
result = a + b
print('Количество цифр в результате:', len(str(result)))
Количество цифр в результате: 1000000

Преобразование длинных строк в int может потребовать много памяти, но Python справляется с числами размером до нескольких миллионов цифр.

Работа с большими числами в комбинаторике: количество сочетаний

Пример

from math import comb
n = 10**6
k = 500000
c = comb(n, k)
print('Число сочетаний C(10^6, 500000) имеет', len(str(c)), 'цифр')
(вывод количества цифр, около 300000)

math.comb для больших n, k также использует произвольную точность int.

Быстрое возведение в степень для больших чисел (бинарное возведение)

Пример

def fast_pow(base, exp):
    result = 1
    while exp:
        if exp & 1:
            result *= base
        base *= base
        exp >>= 1
    return result

print(len(str(fast_pow(2, 10000))))  # количество цифр 2^10000
3011

Алгоритм бинарного возведения в степень (быстрое возведение) позволяет вычислить огромные степени за O(log exp) умножений.

Большие числа в Python 3 - comments

En
большие числа python 3 (python)