Сума або різниця двох потужностей двох


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
@Dennis Я не бачу, чому ні.
Conor O'Brien

... і для 16обох, 5,4і 3,3для дійсних.
Тит

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

@ Sp3000 Ні, хороший момент.
Conor O'Brien

Відповіді:


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.


Чудово - я шукав трохи загадки, але не зміг її розробити, просто переніс до Джелі.
Джонатан Аллан

Спробуйте 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 від першого числа. Якщо бінарне подання - це всі 1s, а потім - 0s, тоді припускається випадок додавання, інакше передбачається випадок віднімання. 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{+|-}?,.=

Спробуйте в Інтернеті!

Це набагато швидше, ніж потрібно, наприклад, на TIO це все ще менше 10 секунд .

Пояснення

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

,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
Conor O'Brien

4

Пітон, 69 байт

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

Тести на ideone

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


4

JAVA 7,142 ,140, 134 БЮТ

Це моє перше повідомлення про 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;
        }
            }
    }

ідеоне


1
Привіт, номер! Ще одного мандрівника від спантеличених я бачу. Це, здається, не працює 40=2**3+2**5, наприклад. Дивлячись на це, я не бачу, чому ні, можливо, я допустив помилку транскрипції ...
Джонатан Аллан

1
@JonathanAllan Тепер він працює нормально. Фактично дужки відсутні в цьому рядку, якщо ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) і спасибі.
Numberknot

Чи не можете ви використовувати літерал 1замість оголошення змінної?
Тит

1
@TItus, якщо я використовую літерал 1, то цей тестовий зразок (17179867136) був би неможливим, оскільки якщо ви використовуєте літерал 1, то Java автоматично призначила йому простір пам’яті INT.
Numberknot

1
Ви можете оголосити j разом із i:for(int i=-1,j;[...]
Frozn

4

Математика, 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яка, можливо, може з’явитися при поданні вводу #(щільна верхня межа - Журнал [2 #] / Журнал [2] = 1,44 ... Журнал [#] + 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 ( $ n), 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.