Сумма или разница двух степеней двух


27

Ваша задача, если вы решите ее принять, состоит в том, чтобы, учитывая целое число K >= 1, найти неотрицательные целые числа Aи выполнить так, чтобы выполнялось B хотя бы одно из двух следующих условий:

  1. K = 2^A + 2^B
  2. K = 2^A - 2^B

Если не существует таких Aи Bваша программа может вести себя любым способом. (Чтобы уточнить, Aи Bможет быть равным.)

Контрольные примеры

Часто существует несколько решений для числа, но вот несколько:

K => A, B
1 => 1, 0
15 => 4, 0                      ; 16 - 1 = 15
16 => 5, 4                      ; 32 - 16 = 16; also 3, 3: 8 + 8 = 16
40 => 5, 3                      ; 2^5 + 2^3 = 40
264 => 8, 3
17179867136 => 34, 11           ; 17179869184 - 2048 = 17179867136 

Последний тест, 17179867136, должны работать менее чем за 10 секунд на любой относительно современной машины. Это код гольфа, поэтому выигрывает самая короткая программа в байтах. Вы можете использовать полную программу или функцию.


5
Может равна B ?
Деннис

2
@ Денис, я не понимаю, почему нет.
Конор О'Брайен

... и для 16, и так 5,4и 3,3в силе.
Тит,

На самом деле теперь, когда я думаю об этом, может A, Bбыть отрицательным? (например, -1, -1для 1)
Sp3000

@ Sp3000 Нет, хорошая мысль.
Конор О'Брайен

Ответы:


3

Желе , 11 10 байт

;0+N&$BL€’

Применение трюка с трюком из ответа Python от @xnor

Протестируйте его в TryItOnline
Все тестовые примеры также есть в TryItOnline

Как?

;0+N&$BL€’ - main link takes an argument, k, e.g 15
;0         - concatenate k with 0, e.g. [15, 0]
     $     - last two links as a monad
   N       - negate, e.g. -15
    &      - bitwise and, e.g. -15&15=1 since these two are called as a monad (one input)
  +        - add, vectorises, e.g. [16,1]
      B    - convert to binary, vectorises, e.g. [[1,0,0,0,0],[1]]
       L€  - length for each, e.g. [5,1]
         ’ - decrement, vectorises, e.g. [4,0]

15

Python 2, 43 байта

lambda n:[len(bin((n&-n)+k))-3for k in n,0]

Скажи это n==2^a ± 2^bс a>b. Тогда наибольший коэффициент степени 2 nравен 2^b, и мы можем найти его, используя хитрость 2^b = n&-n. Это позволяет нам вычислять 2^b + n, что равно 2^a + 2 * 2^bили просто 2^a. Любой из них имеет такую ​​же длину в битах, как и a*. Итак, мы выводим битовые длины n&-nи (n&-n)+n, вычисленные по длинам их двоичных представлений. Python 3 на один байт длиннее для паренов for k in(n,0)].

* Кроме того, что 2^a + 2^bс a==b+1имеет одну длинную битовую длину, но это нормально , потому что мы можем интерпретировать это , как 2^(a+1)-2^b.


Замечательно - я искал небольшую скрипку, но не смог разобраться, просто портировал на Jelly.
Джонатан Аллан

Попробуйте n=4или 8или 16пожалуйста.
Тит

@Titus f(2**n)возвращается (n+1,n)и 2**(n+1)-2**n=2**nпоэтому проблем нет.
Джонатан Аллан

ах ... какой формат bin()в Python?
Тит,

@Titus это строка с ведущей 0b, отсюда и -3.
Джонатан Аллан

8

JavaScript (ES6), 73 байта

(n,[s,f,z]=/^1+(.*1)?(0*)$/.exec(n.toString(2)))=>[s.length-!!f,z.length]

Для случая вычитания первое число - это количество цифр в двоичном представлении, а второе число - это число завершающих нулей. Для случая сложения вычитаем 1 из первого числа. Если двоичное представление - все 1 с, сопровождаемые некоторыми 0, тогда случай сложения принимается, в противном случае принимается случай вычитания. 36-байтовый порт версии @ xnor, которая работает только для B≤30 в JavaScript:

n=>[(l=Math.log2)(n+(n&=-n))|0,l(n)]

2
@ETHproductions Конечно, но я сыграл в гольф до 36.
Нил

Плохо, я думал, что 36-байтовая версия не работает для 17 миллиардов тестовых случаев.
ETHproductions

@ETHproductions Это не так, но, как я помню, ваш порт тоже не работал (комментарий с момента удаления, вздох), поскольку он использовал побитовые операции.
Нейл

Извините, здесь снова: n=>[n,0].map(k=>((n&-n)+k).toString(2).length-1)обе версии возвращаются [34,11]в последнем тестовом примере (я использую FF 48).
ETHproductions

@ETHproductions Ага, так точнее они работают, когда второй результат 30 или меньше.
Нил

6

Perl, 52 49 32 байта

Старое решение (49 байт)

Включает +1 для -p

Внесите свой вклад в STDIN:

pow2.pl <<< 17179867136

pow2.pl

#!/usr/bin/perl -p
$_=reverse sprintf"%b",$_;/()1(?:1+|0*)/;$_="@+"

Однако использование алгоритма xnor и добавление кручения дает 32 байта:

perl -nE 'say 13/9*log|0for$;=$_&-$_,$_+$'

Просто код:

say 13/9*log|0for$;=$_&-$_,$_+$

Это страдает от серьезной ошибки округления, потому что 13/9 = 1.444...она немного выше 1/log 2 = 1.44269...( logсама по себе также имеет ошибку округления, но она настолько меньше, что мы можем ее обернуть при анализе 13/9). Но так как любое 2**big - 2** smallисправляется 2** bigдо журнала, это не имеет значения, и вычисление для 2**big + 2 * 2**smallсокращается, поэтому также безопасно. И на другой стороне диапазона 2**n+2**(n-1)не увеличивается достаточно в диапазоне [0,64](я не могу должным образом в любом случае поддерживать больше, чем целочисленный диапазон из-за использования &), чтобы привести к неверному результату ( 1.5однако, для большого числа множитель будет слишком далеко).


5

Брахилог , 23 байта

,A:B#+.:2rz:^a{+|-}?,.=

Попробуйте онлайн!

Это намного быстрее, чем требуется, например, это все еще меньше 10 секунд на TIO .

объяснение

Это в основном прямая транскрипция формулы без оптимизации:

,A:B     The list [A, B]
#+       Both A and B are greater than or equal to 0
.        Output = [A, B]
:2rz     The list [[2, A], [2, B]]
:^a      The list [2^A, 2^B]
{+|-}?   2^A + 2^B = Input OR 2^A - 2^B = Input
,.=      Assign a value to A and B which satisfy those constraints

2
Похоже, что этот вызов был сделан для языка: D
Конор О'Брайен

4

Python, 69 байт

def f(k):b=bin(k)[::-1];return len(b)-2-(b.count('1')==2),b.find('1')

Тесты на Ideone

Поскольку недопустимый ввод может делать все что угодно, мы знаем, что если для входа задано ровно 2 бита, то это сумма этих двух степеней 2, а в противном случае (если они действительны) это будет цикл с некоторым количеством битов (включая возможность только 1 бит) и будет разница между следующей наивысшей мощностью 2, чем MSB и набор LSB.


4

JAVA 7,142 ,140134 БАЙТА

Это мой первый пост на PPCG! Я был бы очень признателен за отзывы на гольф Подсказок
Благодаря замороженный для сохранения 2 байта

void f(long n){for(int i=-1,j;i++<31;)for(j=0;j++<34;){long a=1,x=a<<i,y=a<<j;if(x+y==n|y-x==n){System.out.println(j+" "+i);return;}}}

UNGOLF

void f(long n){
    for(int i=-1,j;i++<31;)
         for(j=0;j++<34;){
          long a=1,x=a<<i,y=a<<j;
            if(x+y==n|y-x==n){
            System.out.println(j+" "+i);
        return;
        }
            }
    }

ideone


1
Привет номер узел! Еще один странник от недоумения вижу. Это, кажется, не работает 40=2**3+2**5, например. Глядя на это, я не понимаю, почему нет, может быть, я допустил ошибку транскрипции ...
Джонатан Аллан

1
@JonathanAllan Теперь все работает нормально. На самом деле скобки в этой строке отсутствовали, если ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) и спасибо.
Numberknot

Разве вы не можете использовать литерал 1вместо объявления переменной для него?
Титус

1
@TTus, если я использую литерал 1, тогда этот тестовый сценарий (17179867136) будет невозможен, потому что если вы используете литерал 1, тогда java автоматически назначит ему пространство памяти INT.
Numberknot

1
Вы можете объявить j вместе с i:for(int i=-1,j;[...]
Frozn

4

Mathematica, 57 54 байта

Сохранено 3 байта благодаря LegionMammal978!

Do[Abs[2^a-#]==2^b&&Print@{a,b},{a,2Log@#+1},{b,0,a}]&

Фактически распечатывает все 1 соответствующие пары {a, b}. 2Log@#+1верхняя граница для наибольшего значения, aкоторое может появиться при представлении ввода #(жесткая верхняя граница - это Log [2 #] / Log [2] = 1,44 ... Log [#] + 1). Работает практически мгновенно на тестовом вводе и менее чем за четверть секунды (на моем новом, но стандартном компьютере) на 100-значных входах.

1 Разрешение aначать со значения по умолчанию 1 вместо 0 сохраняет два байта; он пропускает выход {0,0}, когда на входе 2, но находит выход {2,1} в этом случае, что достаточно хорошо.


Все * соответствующие пары? (Кроме того, If[Abs[2^a-#]==2^b,Print@{a,b}]может быть заменен на, Abs[2^a-#]==2^b&&Print@{a,b}чтобы сохранить 3 байта.)
LegionMammal978

Хорошее наблюдение, я понял! «Все *» было сноской, но теперь стало понятнее.
Грег Мартин

3

MATL , 23 22 байта

BnQ:qWtG-|ym)1)tG-|hZl

Попробуйте онлайн! Или проверьте все тестовые случаи .

объяснение

B      % Implicit input. Convert to binary. Gives n digits
nQ:q   % Range [1 ... n+1]
W      % 2 raised to that, element-wise: gives [1 2 4 ... 2^(n+1)] (*)
tG-|   % Duplicate. Absolute difference with input, element-wise (**)
y      % Push a copy of (*)
m      % True for elements of (**) that are members of (*)
)      % Use as logical index to select elements from (*)
1)     % Take the first element. Gives power of the first result
tG-|   % Duplicate. Absolute difference with input. Gives power of the second result
hZl    % Concatenate. Take binary logarithm. Implicit display

3

Perl 6 , 41 байт

{.base(2).flip~~/1[1+|0*]/;$/.to,$/.from}

(Алгоритм бесстыдно скопирован из ответа Perl 5 )

Объяснение:

# bare block lambda with implicit parameter 「$_」
{
  # turn into binary
  # ( implicit method call on 「$_」 )
  .base(2)

  # flip the binary representation
  .flip

  ~~ # smartmatch that against:

  /
    1      # a 「1」
    [
      | 1+ # at least one 「1」
      | 0* # or any number of 「0」
    ]
  /;

  # returns a list comprised of

  # the position of the end of the match (larger of the two)
  $/.to,
  # the position of the beginning of the match
  $/.from
}

Использование:

# give it a lexical name for clarity
my &bin-sum-diff = {.base(2).flip~~/1[1+|0*]/;$/.to,$/.from}

say bin-sum-diff 15; # (4 0)
say bin-sum-diff 16; # (5 4)

say bin-sum-diff 20; # (4 2)
# 2**4==16, 2**2==4; 16+4 == 20

say bin-sum-diff 40; # (5 3)
say bin-sum-diff 264; # (8 3)
say bin-sum-diff 17179867136; # (34 11)

1

PHP, 73 байта

Я мог бы скопировать решение Джонатана Pyhton 2 для 54 байтов (+13 служебных данных),
но хотел придумать что-то другое.

сохранить в файл, затем выполнить с помощью phpили php-cgi.

<?=strlen($n=decbin($argv[1]))-!!strpos($n,'01')._.strpos(strrev($n),49);

печатает aи bразделяется подчеркиванием, что-либо без решения.

отличительное решение, 96 байт

<?=preg_match('#^(10*1|(1+))(0*)$#',decbin($argv[1]),$m)?strlen($m[0])-!$m[2]._.strlen($m[3]):_;

печатает aи bразделяется подчеркиванием; единственное подчеркивание без решения.

Он даже сообщает об операции для еще 11 байтов:
просто замените первое подчеркивание в коде на '-+'[!$m[2]].


Если я попробую 67 в echo strlen ($ n = decbin ($ argv [1])) - !! strpos ($ n, '01 ') .'- +' [! $ N [2]]. Strpos (strrev ( $ п), 49); это возвращает мне 6 + 0, то есть 65
Йорг Хюльсерманн

@ JörgHülsermann: 67 не имеет решения; поведение без решения не определено; так что не имеет значения, что он печатает для 67.
Тит

0

PHP, 117 байт

if(preg_match("#^(1+|(10*1))0*$#",$b=decbin($k=$argv[1]),$t))echo($l=strlen($b))-($t[2]?1:0).",",$l+~strrpos($b,"1");

Расширенная версия 4 случая

$l=strlen($b=decbin($k=$argv[1]));
// Case 1: n=2(n-1)=n+n or n=n*(2-1)=2n-n 
if(preg_match('#^100*$#',$b))echo($l-2).'a+'.($l-2).':'.$l.'a-'.($l-1);
// Case 2: n-m
elseif(preg_match('#^1+0*$#',$b)){echo $l.'b-',strpos($b,"0")?$l-strpos($b,"0"):0;}
// Case 3: n+m 
elseif(preg_match('#^10*10*$#',$b))echo ($l-1).'c+',$l-strrpos($b,"1")-1;
else echo "Nothing";

укороченная версия объединяет Варианты 1 и 3 и имеет значение для Варианта 3, и в обеих версиях Вариант 4 не дает выходных данных.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.