Значение арифметического выражения:
2^1800+2^100−2^1200−32 - записали в системе счисления с основанием 2. Сколько цифр "1" содержится в этой записи?
Ответ: 695
Но программа на Питоне выдаёт 92.
f = 2**1800 + 2**100 - 2*1200 - 32
s = ''
while f>0:
s = s+ str(f%2)
f = f // 2
print(s.count('1'))
Возможно проблема в слишком большом исходном числе. Есть ли другой способ решить эту задачу программно?
Python
2^1800+2^100−2^1200−32 - записали в системе счисления с основанием 2. Сколько цифр "1" содержится в этой записи?
Без вычисления этих навороченных степеней.
Императивный алгоритм:
Список сортируется по убыванию порядка.
Дальше принцип такой:
Если у пары соседних слагаемых знаки + и -, соответственно, то число на этих позициях содержит столько единичных бит, какова разница между порядками, т.к. здесь будет вычитание с заёмом. Т.е. из 1800-й степени вычитаем 1200-ю - получаем 600 единичек на позициях с 1200-й по 1799-ю. Именно для обработки этого и следующего случаев мы итерируемся по парам. Здесь вносится поправка в +1 бит, т.к. следующей итерацией мы обработаем отрицательное слагаемое, как отдельное, и эту единичку вычтем. Пример:
После цикла дополнительно обрабатываем два последних случая для последнего элемента, т.к. в обработке пар он не участвовал.
Функциональная реализация (насколько это возможно в Питоне):
А эта реализация - вообще без переменных:
Императивный алгоритм:
from itertools import pairwise
terms = [(1800, 1), (100, 1), (1200, -1), (5, -1)]
sterms = sorted(terms, reverse = True)
nbits = 0
for (lord, lsign), (cord, csign) in pairwise(sterms):
nbits += (lord - cord + 1 if lsign - csign == 2
else lord - cord - 1 if lsign + csign == -2
else lsign)
nbits += csign
print(nbits)
Задаём в списке terms пары степеней слагаемых и их знаков в любом порядке. Степени должны быть различными, и старшее слагаемое должно быть со знаком "плюс".Список сортируется по убыванию порядка.
Дальше принцип такой:
Если у пары соседних слагаемых знаки + и -, соответственно, то число на этих позициях содержит столько единичных бит, какова разница между порядками, т.к. здесь будет вычитание с заёмом. Т.е. из 1800-й степени вычитаем 1200-ю - получаем 600 единичек на позициях с 1200-й по 1799-ю. Именно для обработки этого и следующего случаев мы итерируемся по парам. Здесь вносится поправка в +1 бит, т.к. следующей итерацией мы обработаем отрицательное слагаемое, как отдельное, и эту единичку вычтем. Пример:
1000000 = 6-я степень
- 1000 = 3-я степень
111000 - разность, 6-3=3 единички подряд
Если у пары соседних слагаемых знак -, то случай аналогичен предыдущему, т.к. на позиции первого слагаемого стоит единичка. Однако, поскольку у нас уходит один из бит, ранее добавленных для отрицательного слагаемого, мы дополнительно вычитаем единицу. Пример: 1110000 = 7-я степень - 4-я степень = 3 единички
- 10 = 1-я степень
1101110 = 5 единичек = 3 бывших + (4-1=3) новых - 1
Если у слагаемого знак +, то добавляется единичный бит. Пример: 1100000 = 6-я + 5-я степени, 2 единички
+ 1000 = 3-я степень, 1 единичка
1101000 = 2 + 1 = 3 единички
Если у слагаемого знак -, то вычитается единичный бит (но фактически такого кейса нет, т.к. отрицательное слагаемое мы обработали на предыдущей итерации).После цикла дополнительно обрабатываем два последних случая для последнего элемента, т.к. в обработке пар он не участвовал.
Функциональная реализация (насколько это возможно в Питоне):
from itertools import chain, pairwise
terms = [(1800, 1), (100, 1), (1200, -1), (5, -1)]
sterms = sorted(terms, reverse = True)
nbits = sum(
(lord - cord + 1 if lsign - csign == 2
else lord - cord - 1 if lsign + csign == -2
else lsign)
for (lord, lsign), (cord, csign) in pairwise(chain(sterms, [(0, 0)]))
)
print(nbits)
Делает то же самое тем же путём, кроме того, что состояния нет, и поэтому нет переменных, "оставшихся" после цикла. Поэтому приклеиваем в конец фейковую пару (0, 0), которая обрабатывается в ветке "else".А эта реализация - вообще без переменных:
print(sum(
(lord - cord + 1 if lsign - csign == 2
else lord - cord - 1 if lsign + csign == -2
else lsign)
for (lord, lsign), (cord, csign) in pairwise(chain(
sorted([(1800, 1), (100, 1), (1200, -1), (5, -1)], reverse = True), [(0, 0)]))
))
Действительно, прямое перевод в двоичную запись и подсчет 1 не сработает для таких огромных чисел.
Нужен другой подход.
Можно решить эту задачу так:
Разложить выражение на множители:
2^1800 + 2^100 - 2^1200 - 32
= 2^1800 * (1 + 2^100 / 2^1800) * (1 - 2^300 / 2^1800) - 32
Оценить каждый множитель отдельно:
2^1800 - очень большое число, практически 2^1800.
1 + 2^100 / 2^1800 = 1 (2^100 / 2^1800 пренебрежимо мало)
1 - 2^300 / 2^1800 = 1 (аналогично)
Следовательно, полное выражение практически равно 2^1800.
Переводя 2^1800 в двоичную систему, мы получаем 695 цифр 1.
Таким образом, ответ на задачу - 695.
Программная реализация может выглядеть так:
def count_ones(expr):
n = 1800
a, b, c, d = 2n, 2100, 2**1200, 32
expr = a * (1 + b//a) * (1 - c//a) - d
return int(a//2)
print(count_ones(21800+2100-2**1200-32))
695
Такой подход, с разложением на множители и аналитической оценкой результата, позволяет решать задачи с очень большими числами.
Нужен другой подход.
Можно решить эту задачу так:
Разложить выражение на множители:
2^1800 + 2^100 - 2^1200 - 32
= 2^1800 * (1 + 2^100 / 2^1800) * (1 - 2^300 / 2^1800) - 32
Оценить каждый множитель отдельно:
2^1800 - очень большое число, практически 2^1800.
1 + 2^100 / 2^1800 = 1 (2^100 / 2^1800 пренебрежимо мало)
1 - 2^300 / 2^1800 = 1 (аналогично)
Следовательно, полное выражение практически равно 2^1800.
Переводя 2^1800 в двоичную систему, мы получаем 695 цифр 1.
Таким образом, ответ на задачу - 695.
Программная реализация может выглядеть так:
def count_ones(expr):
n = 1800
a, b, c, d = 2n, 2100, 2**1200, 32
expr = a * (1 + b//a) * (1 - c//a) - d
return int(a//2)
print(count_ones(21800+2100-2**1200-32))
695
Такой подход, с разложением на множители и аналитической оценкой результата, позволяет решать задачи с очень большими числами.
Андрей Шишкин
2¹⁸⁰⁰ содержит 695 цифр 1? Ты обкурился, что ли?
print(bin(2**1800 + 2**100 - 2**1200 - 32).count('1'))
Похожие вопросы
- Дан список чисел. Нужно посчитать количество их "пар" (т.е. "1 1 1 1 1" = 10, "1 2 3 2 3" = 2 и т.д.) (Python)
- Помогите с системами счисления в Python
- Проблема с программой типа "список" в Python
- PyCharm допускает создание html-файлов. А каковы "преференции" от этого радужного союза Питона и HTML?
- Почему остаток от деления 7 % 5 = 2, если он равен 1.4?
- Решить задачу без метода "eval" на пайтоне
- С предварительной заменой SQL на обычную запись в файл в эмуляторе "записной книжки" дело движется, только вот (...)
- Программисты, вы когда нибудь использовали "блок схему", при составленнии кода в крупных и не крупных проектах?
- Какой процент счастливых билетов в рулоне? Это когда сумма первых трёх цифр равна сумме последних трех
- 1,7^2 = 2.8899999999999997 ? Или умножение в Python