чтобы немного расширить ответ Алоиса, мы можем расширить предложенный y = (x * 205) >> 11
еще на несколько кратных / сдвигов:
y = (ms * 1) >> 3 // first error 8
y = (ms * 2) >> 4 // 8
y = (ms * 4) >> 5 // 8
y = (ms * 7) >> 6 // 19
y = (ms * 13) >> 7 // 69
y = (ms * 26) >> 8 // 69
y = (ms * 52) >> 9 // 69
y = (ms * 103) >> 10 // 179
y = (ms * 205) >> 11 // 1029
y = (ms * 410) >> 12 // 1029
y = (ms * 820) >> 13 // 1029
y = (ms * 1639) >> 14 // 2739
y = (ms * 3277) >> 15 // 16389
y = (ms * 6554) >> 16 // 16389
y = (ms * 13108) >> 17 // 16389
y = (ms * 26215) >> 18 // 43699
y = (ms * 52429) >> 19 // 262149
y = (ms * 104858) >> 20 // 262149
y = (ms * 209716) >> 21 // 262149
y = (ms * 419431) >> 22 // 699059
y = (ms * 838861) >> 23 // 4194309
y = (ms * 1677722) >> 24 // 4194309
y = (ms * 3355444) >> 25 // 4194309
y = (ms * 6710887) >> 26 // 11184819
y = (ms * 13421773) >> 27 // 67108869
каждая строка представляет собой отдельный независимый расчет, и вы увидите свою первую «ошибку» / неверный результат при значении, указанном в комментарии. как правило, лучше брать наименьшее смещение для данного значения ошибки, поскольку это сведет к минимуму дополнительные биты, необходимые для сохранения промежуточного значения в расчете, например, (x * 13) >> 7
"лучше", чем (x * 52) >> 9
, так как для него требуется на два бита меньше, а оба начинают давать неправильные ответы выше 68.
если вы хотите рассчитать больше из них, можно использовать следующий (Python) код:
def mul_from_shift(shift):
mid = 2**shift + 5.
return int(round(mid / 10.))
и я сделал очевидную вещь для вычисления, когда это приближение начинает ошибаться с:
def first_err(mul, shift):
i = 1
while True:
y = (i * mul) >> shift
if y != i // 10:
return i
i += 1
(обратите внимание, что //
используется для "целочисленного" деления, то есть оно усекается / округляется до нуля)
причина ошибки "3/1" (то есть, 8 повторов, 3 раза, а затем 9), по-видимому, связана с изменением основ, т.е. если мы отобразим ошибки, мы получим следующее:
, где относительная погрешность определяется как: mul_from_shift(shift) / (1<<shift) - 0.1