Я пытаюсь реализовать функцию, которая будет использоваться для определения непрерывности выхода генератора. Метод, к которому я стремлюсь, - это итерация через генератор. Для каждого значения я выравниваю по правому краю биты значения (без учета 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.
Я искренне извиняюсь за хаотичное объяснение. Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.
Интересное наблюдение, @RoryDaulton. Я не знал, как обозначить эту идею. Спасибо.





Я скорректировал ваш оператор присваивания 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)
Большое спасибо! Как ты сделал это? Насколько глупой была моя ошибка? Что мне не хватало? Как ты нашел это так быстро?
@AidanCodeX Сначала я проверил крайние случаи - 0b1000 ... и 0b00 ... 1, и увидел, что первый был выключен на БОЛЬШОЙ размер, и обнаружил, что вам нужно умножить на 1/2 степень двойки, на которую вы делите, иначе вы теряете эту «группу». Я распечатал различия и увидел, что они теперь находятся в нижних сотнях, а не в верхних тысячах. Затем я решил, что мне нужно позаботиться о том, чтобы бит терялся во время деления, и сократил разницу до <10. Затем я методом проб и ошибок добился нулевой разницы (я забыл добавить +1 в конце max(...)).
Я не думаю, что это была глупая ошибка - мне потребовалось некоторое время, чтобы самому разобраться в ней. Он состоял из двух частей - вам нужно было умножить на 1/2 сумму, на которую вы делили (после покрытия пола), иначе вы потеряете все, кроме одной из этих единиц. Затем, после их учета, вам все равно придется учитывать единицы, превышающие наибольшую степень двойки, которую вы учитываете. Это то, что делает часть 'max (...)'.
Это странное определение непрерывности, которое обычно определяется чем-то вроде различия между небольшими последовательными значениями. Разница между
1.0и1-2**-50очень мала, но количество битов1очень велико. То же самое можно сказать и о2**50и2**50-1.