Алгоритм суммирования битов Python

Я пытаюсь реализовать функцию, которая будет использоваться для определения непрерывности выхода генератора. Метод, к которому я стремлюсь, - это итерация через генератор. Для каждого значения я выравниваю по правому краю биты значения (без учета 0b), подсчитываю количество единиц и сдвигаю количество единиц.

#!/usr/bin/python3
from typing import Tuple


def find_bit_sum(top: int, pad_length: int) -> int :
    """."""
    return pad_length * (top + 1)


def find_pad_length(top: int) -> int :
    """."""
    return len(bin(top)) - 2  # -"0b"


def guess_certain(top: int, pad_length: int) -> Tuple[int, int, int] :
    """."""
    _both: int = find_bit_sum(top, pad_length)
    _ones: int = sum(sum(int(_i_in) for _i_in in bin(_i_out)[2 :]) for _i_out in range(1, top + 1))
    return _both - _ones, _ones, _both  # zeros, ones, sum


def guess(top: int, pad_length: int) -> Tuple[int, int, int] :  # zeros then ones then sum
    """."""
    _bit_sum: int = find_bit_sum(top, pad_length)  # number of bits in total
    _zeros: int = _bit_sum  # ones are deducted
    _ones: int = 0  # _bit_sum - _zeros
    # detect ones
    for _indexed in range(pad_length) :
        _ones_found: int = int(top // (2 ** (_indexed + 1)))  # HELP!!!
        _zeros -= _ones_found
        _ones += _ones_found
    #
    return _zeros, _ones, _bit_sum


def test_the_guess(max_value: int) -> bool :  # the range is int [0, max_value + 1)
    pad: int = find_pad_length(max_value)
    _zeros0, _ones0, _total0 = guess_certain(max_value, pad)
    _zeros1, _ones1, _total1 = guess(max_value, pad)
    return all((
        _zeros0 == _zeros1,
        _ones0 == _ones1,
        _total0 == _total1
    ))


if __name__ == '__main__' :  # should produce a lot of True
    for x in range(3000) :
        print(test_the_guess(x))

Да хоть убей, я не могу заставить guess() согласиться с guess_certain(). Моя проблема - временная сложность guess_certain(): он работает для небольших диапазонов [0, top], но можно забыть о 256-битных числах (tops). Функция find_bit_sum() работает отлично. Функция find_pad_length() тоже работает.

top // (2 ** (_indexed + 1))

Я пробовал 40 или 50 вариантов функции guess(). Это меня полностью разочаровало. Функция guess() вероятностная. В завершенном состоянии: если он возвращает False, то Генератор определенно не производит все значения в range(top + 1); однако, если он возвращает True, то может быть генератор. Мы уже знаем, что генератор range(top + 1) работает непрерывно, потому что он действительно производит каждое число от 0 до top включительно; Итак, test_the_guess() должен возвращать True.

Я искренне извиняюсь за хаотичное объяснение. Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.

Это странное определение непрерывности, которое обычно определяется чем-то вроде различия между небольшими последовательными значениями. Разница между 1.0 и 1-2**-50 очень мала, но количество битов 1 очень велико. То же самое можно сказать и о 2**50 и 2**50-1.

Rory Daulton 30.07.2018 21:24

Интересное наблюдение, @RoryDaulton. Я не знал, как обозначить эту идею. Спасибо.

YoungCoder5 31.07.2018 00:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я скорректировал ваш оператор присваивания ones_found, чтобы учесть количество степеней двойки для каждого int(top // (2 ** (_indexed + 1))), а также дополнительные «опрокидывания», которые происходят перед следующей степенью двойки. Вот результат:

_ones_found: int = int(top // (2 ** (_indexed + 1))) * (2 ** (_indexed)) + max(0, (top % (2 ** (_indexed + 1))) - (2 ** _indexed) + 1)

Я также взял на себя смелость преобразовать оператор в побитовые операторы для ясности и скорости, как показано ниже:

_ones_found: int = ((top >> _indexed + 1) << _indexed) + max(0, (top & (1 << _indexed + 1) - 1) - (1 << _indexed) + 1)

Большое спасибо! Как ты сделал это? Насколько глупой была моя ошибка? Что мне не хватало? Как ты нашел это так быстро?

YoungCoder5 31.07.2018 00:18

@AidanCodeX Сначала я проверил крайние случаи - 0b1000 ... и 0b00 ... 1, и увидел, что первый был выключен на БОЛЬШОЙ размер, и обнаружил, что вам нужно умножить на 1/2 степень двойки, на которую вы делите, иначе вы теряете эту «группу». Я распечатал различия и увидел, что они теперь находятся в нижних сотнях, а не в верхних тысячах. Затем я решил, что мне нужно позаботиться о том, чтобы бит терялся во время деления, и сократил разницу до <10. Затем я методом проб и ошибок добился нулевой разницы (я забыл добавить +1 в конце max(...)).

Dillon Davis 31.07.2018 00:27

Я не думаю, что это была глупая ошибка - мне потребовалось некоторое время, чтобы самому разобраться в ней. Он состоял из двух частей - вам нужно было умножить на 1/2 сумму, на которую вы делили (после покрытия пола), иначе вы потеряете все, кроме одной из этих единиц. Затем, после их учета, вам все равно придется учитывать единицы, превышающие наибольшую степень двойки, которую вы учитываете. Это то, что делает часть 'max (...)'.

Dillon Davis 31.07.2018 00:29

Другие вопросы по теме