Количество знаков после запятой при делении числа 2**128-1 на 2
Как разделить, в python, число 2*128-1 или ему подобное на 2, несколько раз до получения ответа типа 1.ххххххххх Необходимо максимально точно отобразить все знаки после запятой Пробовал разные варианты float и to fixed decimal
Внесу небольшую правку если число будет представлять из себя разность степеней двойки , 2 ** 128 - 2 ** 11 - 2 ** 6-1
Ответы (2 шт):
Это не так уж сложно с использованием длинной арифметики, имеющейся в Python для целых чисел.
Пусть степень n=4. Тогда 2^4-1 = 1111
в бинарном представлении, а нужный результат 1.111
- опять же в бинарном. В десятичном виде дробная часть выглядит как 0.5 + 0.25 + 0.125 = 0.875
, а если часть до точки пока убрать, то 500+250+125
Получается, что вам нужно взять число t=10**(n-1)
, начальное значение s=0
, и в цикле делить t
пополам и прибавлять к s
,а в конце вывести s
в виде f'1.{s}'
def ppp(n, minus_set):
t = 10**(n-1)
s = 0
for i in reversed(range(n-1)):
t //= 2
if not i in minus_set:
s += t
return f'1.{s}'
print(ppp(6,{2,4}))
>>> 1.34375
Проверяем: (64-16-4-1)/32 = 1.34375
decimal
Простая постановка задачи
Для точного представления дроби (2p - 1) / 2p-1 нужно ровно p десятичных разрядов. Выставляем нужную точность и получаем результат:
import decimal
p = int(input())
with decimal.localcontext() as c:
c.prec = p
print(decimal.Decimal(2 ** p - 1) / 2 ** (p - 1))
$ echo 10 | python dec.py 1.998046875 $ echo 128 | python dec.py 1.9999999999999999999999999999999999999941225282458885624601563173138887716109066722161395623924562414686079137027263641357421875
p разрядов точности достаточно, потому что (2p - 1)·5p-1 < 2p·5p-1 < 2p·5p = 10p. А для него как раз и нужно p разрядов.
Усложним немного
Решим задачу для произвольного числа n. int.bit_length
вычисляет для целого положительного числа его длину в битах. Обозначим её за p. Тогда нам нужно вывести n / 2p-1, а требуемая точность равна p.
import decimal
def print_fraction(n):
p = n.bit_length()
with decimal.localcontext() as c:
c.prec = p
print(decimal.Decimal(n) / 2 ** (p - 1))
def parse_exp(w):
return (-1 if w.startswith('-') else 1), abs(int(w))
print_fraction(sum(s * 2 ** p for s, p in map(parse_exp, input().split())))
$ echo 10 -0 | python dec.py 1.998046875 $ echo 10 -5 -0 | python dec.py 1.935546875 $ echo 10 -8 | python dec.py 1.5 $ echo 128 -0 | python dec.py 1.9999999999999999999999999999999999999941225282458885624601563173138887716109066722161395623924562414686079137027263641357421875 $ echo 128 -11 -6 -0 | python dec.py 1.9999999999999999999999999999999999875809021835625324783102984842469744138457983927028953352600382231685216538608074188232421875
Целые
Простая постановка задачи
Вместо деления 2p - 1 на 2p-1 умножим его на 5p-1. Получится целое число, которое ровно в 10p-1 раз больше нужного ответа. Целое превратим в строку, вставим точку после первого знака и готово:
p = int(input())
s = str((2 ** p - 1) * (5 ** (p - 1)))
print(f'{s[0]}.{s[1:]}')
$ echo 10 | python int.py 1.998046875 $ echo 128 | python int.py 1.9999999999999999999999999999999999999941225282458885624601563173138887716109066722161395623924562414686079137027263641357421875
Усложним немного
Требуемая точность p вычисляется так же как и в случае c decimal
. Затем делается умножение на 5p-1, дальше всё аналогично:
def print_fraction(n):
p = n.bit_length()
s = str(n * (5 ** (p - 1)))
print(f'{s[0]}.{s[1:]}')
def parse_exp(w):
return (-1 if w.startswith('-') else 1), abs(int(w))
print_fraction(sum(s * 2 ** p for s, p in map(parse_exp, input().split())))
$ echo 10 -0 | python int.py 1.998046875 $ echo 10 -5 -0 | python int.py 1.935546875 $ echo 10 -8 | python int.py 1.500000000 $ echo 128 -0 | python int.py 1.9999999999999999999999999999999999999941225282458885624601563173138887716109066722161395623924562414686079137027263641357421875 $ echo 128 -11 -6 -0 | python int.py 1.9999999999999999999999999999999999875809021835625324783102984842469744138457983927028953352600382231685216538608074188232421875
P.S. Оба способа опираются на знание какой будет результат. В первом способе надо определить нужную точность. Во втором способе деление на степень двойки заменяется умножением на степень пятёрки. Эти приемчики не сработают, например, для (3p - 1) / 3p-1. А даже для таких дробей есть способ решить задачу без трюков, полностью автоматически. Но поля книги слишком узки.