Suma lub różnica dwóch potęg dwóch

27

Wyzwanie, jeśli zdecydujesz się je zaakceptować, polega na K >= 1znalezieniu liczb całkowitych nieujemnych Ai B spełnieniu co najmniej jednego z dwóch następujących warunków:

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

Jeśli takiego nie ma, Aa BTwój program może zachowywać się w dowolny sposób. (Wyjaśnienie Ai Bmoże być równe.)

Przypadki testowe

Często istnieje wiele rozwiązań wielu, ale oto kilka:

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 

Ostatni przypadek testowy, 17179867136, należy uruchomić w niecałe 10 sekund na każdym stosunkowo nowoczesną maszynę. To jest golf golfowy, więc wygrywa najkrótszy program w bajtach. Możesz użyć pełnego programu lub funkcji.

Conor O'Brien
źródło
5
Czy A może być równe B ?
Dennis
2
@ Dennis Nie rozumiem, dlaczego nie.
Conor O'Brien,
... i dla 16zarówno 5,4i 3,3są ważne.
Tytus
Właściwie teraz, gdy o tym myślę, może A, Bbyć ujemne? (np. -1, -1dla 1)
Sp3000,
@ Sp3000 Nie, dobry punkt.
Conor O'Brien,

Odpowiedzi:

3

Galaretka , 11 10 bajtów

;0+N&$BL€’

Zastosowanie sztuczki polegającej na kręceniu bitów z odpowiedzi Pythona autorstwa @xnor

Przetestuj w TryItOnline
Wszystkie przypadki testowe znajdują się również w TryItOnline

W jaki sposób?

;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]
Jonathan Allan
źródło
15

Python 2, 43 bajty

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

Powiedz to n==2^a ± 2^bz a>b. Zatem największym współczynnikiem potęgi 2 njest 2^bi możemy go znaleźć za pomocą sztuczki bitowej 2^b = n&-n. To pozwala nam obliczyć 2^b + n, która jest równa albo 2^a + 2 * 2^balbo tylko 2^a. Każdy z nich ma tę samą długość bitów co a*. Tak więc, wyprowadzamy długości bitów n&-ni (n&-n)+nobliczone na podstawie długości ich reprezentacji binarnych. Python 3 jest o jeden bajt dłuższy dla parens w for k in(n,0)].

* Tyle że 2^a + 2^bz a==b+1ma jedną dłuższą długość bitów, ale to dobrze, ponieważ możemy to interpretować jako 2^(a+1)-2^b.

xnor
źródło
Cudownie - szukałem trochę skrzypiec, ale nie mogłem tego rozwiązać, po prostu przeniesiony do Jelly.
Jonathan Allan,
Spróbuj n=4lub 8lub 16przyjemność.
Tytus
@Titus f(2**n)zwrotów (n+1,n)i 2**(n+1)-2**n=2**ntak nie ma problemu.
Jonathan Allan,
ah ... Jaki jest format bin()Pythona?
Tytus
@Titus to ciąg z wiodącym 0b, stąd -3.
Jonathan Allan,
8

JavaScript (ES6), 73 bajty

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

W przypadku odejmowania pierwsza liczba to liczba cyfr w reprezentacji binarnej, a druga liczba to liczba zer końcowych. W przypadku dodawania odejmujemy 1 od pierwszej liczby. Jeśli reprezentacją binarną są wszystkie 1, po których następują 0, to zakłada się przypadek dodania, w przeciwnym razie przyjmuje się przypadek odejmowania. 36-bajtowy port wersji @ xnor, który działa tylko dla B≤30 w JavaScript:

n=>[(l=Math.log2)(n+(n&=-n))|0,l(n)]
Neil
źródło
2
@ETHproductions Jasne, ale grałem w golfa do 36.
Neil
Szkoda, myślałem, że 36-bajtowa wersja nie działa dla 17 miliardów przypadków testowych.
ETHprodukcje
@ETHproductions Nie robi tego, ale podobnie jak twój port, jak pamiętam (komentuj, ponieważ usunięto, westchnij), ponieważ używał operacji bitowych.
Neil
Przepraszam, oto znowu: n=>[n,0].map(k=>((n&-n)+k).toString(2).length-1)I obie wersje wracają [34,11]na ostatnim przypadku testowym (używam FF 48).
ETHproductions
@ETHproductions Aha, więc dokładniej działają, gdy drugi wynik to 30 lub mniej.
Neil
6

Perl, 52 49 32 bajty

Stare rozwiązanie (49 bajtów)

Obejmuje +1 dla -p

Podaj dane wejściowe STDIN:

pow2.pl <<< 17179867136

pow2.pl

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

Jednak użycie algorytmu xnor i dodanie skrętu daje 32 bajty:

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

Tylko kod:

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

Cierpi na tym poważny błąd zaokrąglania, ponieważ 13/9 = 1.444...jest nieco powyżej 1/log 2 = 1.44269...( logsam również ma błąd zaokrąglania, ale jest o tyle mniejszy, że możemy go zawrzeć w analizie 13/9). Ale ponieważ każdy 2**big - 2** smallzostanie poprawiony 2** bigprzed dziennikiem, nie ma to znaczenia, a obliczenia dla 2**big + 2 * 2**smallskrócenia zostają zmniejszone, więc jest również bezpieczny. A po drugiej stronie zakresu 2**n+2**(n-1)nie zwiększa się wystarczająco w zakresie [0,64](nie mogę poprawnie i tak obsługuje więcej niż zakres liczb całkowitych ze względu na użycie &), aby doprowadzić do błędnego wyniku (multiplikator 1.5byłby jednak zbyt daleki dla dużych liczb).

Ton Hospel
źródło
5

Brachylog , 23 bajty

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

Wypróbuj online!

Jest to znacznie szybsze niż wymagane, np . W TIO jest to nadal poniżej 10 sekund .

Wyjaśnienie

Jest to w zasadzie bezpośrednia transkrypcja formuły bez optymalizacji:

,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
Fatalizować
źródło
2
Wygląda na to, że wyzwanie zostało wykonane dla języka: D
Conor O'Brien
4

Python, 69 bajtów

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

Testy są na ideone

Ponieważ nieprawidłowe dane wejściowe mogą zrobić wszystko, wiemy, że jeśli dane wejściowe mają ustawione dokładnie 2 bity, jest to suma tych 2 mocy 2, a w przeciwnym razie (jeśli jest poprawna) będzie to ciąg pewnej liczby bitów (w tym możliwość tylko 1 bit) i będzie różnicą między następną najwyższą mocą 2 niż zestaw MSB i zestaw LSB.

Jonathan Allan
źródło
4

JAVA 7,142 ,140, 134 BYTES

To jest mój pierwszy post na PPCG! Naprawdę byłbym wdzięczny za opinie na temat wskazówek golfowych
Dzięki zamrożeniu za oszczędność 2 bajtów

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

Numberknot
źródło
1
Cześć numerknot! Widzę kolejnego wędrowca z zagadek. Na przykład wydaje się, że nie działa 40=2**3+2**5. Patrząc na to, nie rozumiem, dlaczego nie, może popełniłem błąd transkrypcji ...
Jonathan Allan
1
@JonathanAllan Teraz działa dobrze. Właściwie brakowało nawiasów w tym wierszu, jeśli ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) i dzięki.
Numberknot
Czy nie możesz użyć literału 1zamiast deklarować dla niego zmienną?
Tytus
1
@TItus, jeśli użyję literału 1, to ta walizka testowa (17179867136) nie byłaby możliwa, ponieważ jeśli użyjesz literału 1, java automatycznie przypisze mu pamięć INT.
Numberknot 10.09.16
1
Możesz zadeklarować j razem z i:for(int i=-1,j;[...]
Frozn 10.09.16
4

Mathematica, 57 54 bajtów

Zaoszczędzono 3 bajty dzięki LegionMammal978!

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

Właściwie drukuje wszystkie 1 odpowiednie pary {a, b}. 2Log@#+1jest górną granicą największej, aktóra może pojawić się podczas reprezentowania danych wejściowych #(ścisła górna granica to Log [2 #] / Log [2] = 1,44 ... Log [#] + 1). Działa niemal natychmiast na wejściu testowym, aw mniej niż kwadrans (na moim nowym, ale gotowym komputerze) na wejściach 100-cyfrowych.

1 Letting apoczątek w domyślnej wartości 1 zamiast 0 zapisuje dwa bajty; powoduje, że wyjście {0,0} jest pomijane, gdy wejście ma wartość 2, ale w takim przypadku znajduje wyjście {2,1}, co jest wystarczająco dobre.

Greg Martin
źródło
Wszystkie * odpowiednie pary? ( If[Abs[2^a-#]==2^b,Print@{a,b}]Można go również zastąpić, Abs[2^a-#]==2^b&&Print@{a,b}aby zaoszczędzić 3 bajty.)
LegionMammal978 10.09.16
Niezła obserwacja, rozumiem! „Wszystko *” było przypisem, ale teraz jest jaśniejsze.
Greg Martin
3

MATL , 23 22 bajtów

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

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie

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
Luis Mendo
źródło
3

Perl 6 , 41 bajtów

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

(Algorytm bezwstydnie skopiowany z odpowiedzi Perla 5 )

Wyjaśnienie:

# 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
}

Stosowanie:

# 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)
Brad Gilbert b2gills
źródło
1

PHP, 73 bajty

Mogłem skopiować rozwiązanie Pyhton 2 Jonathana dla 54 bajtów (+13 narzutu),
ale chciałem wymyślić coś innego.

zapisz do pliku, a następnie uruchom za pomocą phplub php-cgi.

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

drukuje ai boddzielone znakiem podkreślenia, wszystko bez rozwiązania.

charakterystyczne rozwiązanie, 96 bajtów

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

odbitki ai boddzielone znakiem podkreślenia; jedyny znak podkreślający brak rozwiązania.

Mówi nawet o operacji dla 11 kolejnych bajtów:
wystarczy wymienić pierwszy znak podkreślenia w kodzie na '-+'[!$m[2]].

Tytus
źródło
Jeśli spróbuję 67 w echu strlen ($ n = decbin ($ argv [1])) - !! strpos ($ n, '01 ') .'- +' [! $ N [2]]. Strpos (strrev ( n), 49); oddaje mi 6 + 0, czyli 65
Jörg Hülsermann
@ JörgHülsermann: 67 nie ma rozwiązania; zachowanie dla żadnego rozwiązania nie jest zdefiniowane; więc nie ma znaczenia, co drukuje dla 67.
Tytus
0

PHP, 117 bajtów

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");

Rozszerzona wersja 4 walizki

$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";

krótka wersja połączenia Case 1 i 3 i robi różnicę w stosunku do Case 3, aw obu wersjach Case 4 nie daje wyników.

Jörg Hülsermann
źródło