Somma o differenza di due poteri di due


27

La tua sfida, se scegli di accettarla, è, dato un numero intero K >= 1, di trovare numeri interi non negativi Ae B tale che valga almeno una delle due seguenti condizioni:

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

Se non esiste tale Ae B, il programma potrebbe comportarsi in qualsiasi modo. (Per chiarire, Ae Bpuò essere uguale.)

Casi test

Esistono spesso più soluzioni per un numero, ma eccone alcune:

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 

L'ultimo caso di test, 17179867136, deve essere eseguito in meno di 10 secondi su qualsiasi macchina relativamente moderna. Questo è un codice golf, quindi vince il programma più breve in byte. È possibile utilizzare un programma completo o una funzione.


5
Può A uguale B ?
Dennis,

2
@Dennis Non vedo perché no.
Conor O'Brien,

... e per 16, entrambi 5,4e 3,3sono validi.
Tito,

In realtà, ora che ci penso, può A, Bessere negativo? (ad es. -1, -1per 1)
Sp3000,

@ Sp3000 No, buon punto.
Conor O'Brien,

Risposte:


3

Gelatina , 11 10 byte

;0+N&$BL€’

Applicando il piccolo trucco della risposta Python di @xnor

Provalo su TryItOnline
Tutti i casi di test sono anche su TryItOnline

Come?

;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 byte

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

Dillo n==2^a ± 2^bcon a>b. Quindi, il più grande fattore power-of-2 di nè 2^b, e possiamo trovarlo usando il bit-trick 2^b = n&-n. Questo ci permette di calcolare 2^b + n, che è uguale 2^a + 2 * 2^bo solo o solo 2^a. Uno dei due ha la stessa lunghezza di bit di a*. Quindi, produciamo le lunghezze di bit di n&-ne (n&-n)+n, calcolate dalle lunghezze delle loro rappresentazioni binarie. Python 3 è più lungo di un byte per le parentesi for k in(n,0)].

* Tranne che 2^a + 2^bcon a==b+1ha una lunghezza di bit più lunga, ma va bene perché possiamo interpretarlo come 2^(a+1)-2^b.


Meraviglioso: ho cercato un po 'di violino, ma non sono riuscito a risolverlo, appena portato su Jelly.
Jonathan Allan,

Prova n=4o 8o per 16favore.
Tito,

@Titus f(2**n)ritorna (n+1,n)e 2**(n+1)-2**n=2**nquindi non ci sono problemi.
Jonathan Allan,

ah ... Qual è il formato di bin()in Python?
Tito,

@Titus è una stringa con un inizio 0b, quindi il -3.
Jonathan Allan,

8

JavaScript (ES6), 73 byte

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

Per il caso di sottrazione, il primo numero è il numero di cifre nella rappresentazione binaria e il secondo numero è il numero di zero finali. Per il caso di aggiunta, sottraggiamo 1 dal primo numero. Se la rappresentazione binaria è tutta 1 seguita da alcuni 0, si assume il caso di addizione, altrimenti si ipotizza il caso di sottrazione. Porta a 36 byte della versione di @ xnor che funziona solo per B≤30 in JavaScript:

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

2
@ETHproductions Certo, ma ho giocato a golf fino a 36.
Neil

Mio male, pensavo che la versione a 36 byte non funzionasse per il caso di test da 17 miliardi.
ETHproductions

@ETHproductions Non lo è, ma poi nemmeno la tua porta, come ricordo (commento cancellato, sospiro), poiché utilizzava operazioni bit per bit.
Neil,

Siamo spiacenti, eccolo di nuovo: n=>[n,0].map(k=>((n&-n)+k).toString(2).length-1)ed entrambe le versioni ritornano [34,11]sull'ultimo test case (sto usando FF 48).
ETHproductions

@ETHproductions Aha, quindi con maggiore precisione funzionano quando il secondo risultato è 30 o meno.
Neil,

6

Perl, 52 49 32 byte

Vecchia soluzione (49 byte)

Include +1 per -p

Dare input su STDIN:

pow2.pl <<< 17179867136

pow2.pl

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

Tuttavia, l'utilizzo dell'algoritmo di xnor e l'aggiunta di un twist danno 32 byte:

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

Solo il codice:

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

Questo soffre di un grave errore di arrotondamento perché 13/9 = 1.444...è un po 'più in alto 1/log 2 = 1.44269...(di per logsé ha anche un errore di arrotondamento ma è molto più piccolo che possiamo concludere nell'analisi del 13/9). Ma dal momento che qualcuno 2**big - 2** smallviene corretto 2** bigprima del registro, questo non ha importanza e il calcolo per 2**big + 2 * 2**smallviene troncato, quindi è anche sicuro .. E dall'altro lato dell'intervallo 2**n+2**(n-1)non viene aumentato abbastanza nell'intervallo [0,64](non riesco correttamente supportare comunque più dell'intervallo intero a causa dell'uso di &) per portare a un risultato sbagliato (il moltiplicatore 1.5sarebbe troppo lontano per numeri grandi).


5

Brachylog , 23 byte

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

Provalo online!

Questo è molto più veloce del necessario, ad es. Questo è ancora meno di 10 secondi su TIO .

Spiegazione

Questa è fondamentalmente una trascrizione diretta della formula senza ottimizzazione:

,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
Sembra che questa sfida sia stata fatta per la lingua: D
Conor O'Brien,

4

Python, 69 byte

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

I test sono su ideone

Poiché un input non valido può fare qualsiasi cosa, sappiamo che se l'ingresso ha esattamente 2 bit impostati, è la somma di quei 2 poteri di 2, e altrimenti (se valido) sarà una serie di un certo numero di bit (incluso la possibilità di solo 1 bit) e sarà la differenza tra la successiva potenza massima di 2 rispetto al set MSB e LSB.


4

JAVA 7,142 ,140, 134 BYTES

Questo è il mio primo post su PPCG! Apprezzerei molto per il feedback sui suggerimenti sul golf
Grazie a frozen per aver salvato 2 byte

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
Ciao numero! Vedo un altro vagabondo perplesso. Non sembra funzionare 40=2**3+2**5, per esempio. Guardandolo, non riesco a capire perché no, forse ho fatto un errore di trascrizione ...
Jonathan Allan,

1
@JonathanAllan Ora funziona bene. In realtà le parentesi mancavano in questa riga se ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) e grazie.
Numberknot,

Non puoi usare un valore letterale 1invece di dichiararne una variabile?
Tito,

1
@TItus se uso letterale 1 allora questo testcase (17179867136) non sarebbe possibile perché se usi letterale 1 java gli ha assegnato automaticamente uno spazio di memoria INT.
Numberknot,

1
Puoi dichiarare j insieme a i:for(int i=-1,j;[...]
Frozn,

4

Mathematica, 57 54 byte

Salvato 3 byte grazie a LegionMammal978!

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

In realtà stampa tutte le 1 coppie appropriate {a, b}. 2Log@#+1è un limite superiore per il più grande ache può eventualmente apparire quando rappresenta l'ingresso #(il limite superiore stretto è Log [2 #] / Log [2] = 1.44 ... Log [#] + 1). Funziona quasi istantaneamente sull'ingresso di prova e in meno di un quarto di secondo (sul mio computer nuovo ma standardizzato) su ingressi di 100 cifre.

1 Lasciar apartire al valore predefinito 1 invece di 0 consente di risparmiare due byte; fa sì che l'output {0,0} venga perso quando l'input è 2, ma trova l'output {2,1} in quel caso, il che è abbastanza buono.


Tutte * le coppie appropriate? (Inoltre, If[Abs[2^a-#]==2^b,Print@{a,b}]può essere sostituito con Abs[2^a-#]==2^b&&Print@{a,b}per salvare 3 byte.)
LegionMammal978

Bella osservazione, ho capito! "All *" era una nota a piè di pagina, ma ora è più chiaro.
Greg Martin,

3

MATL , 23 22 byte

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

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

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 byte

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

(Algoritmo copiato spudoratamente dalla risposta Perl 5 )

Spiegazione:

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

Uso:

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

Avrei potuto copiare la soluzione Pyhton 2 di Jonathan per 54 byte (+13 overhead),
ma volevo trovare qualcosa di diverso.

salva su file, quindi esegui con phpo php-cgi.

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

stampe aeb separato da un trattino basso, tutto per nessuna soluzione.

soluzione distintiva, 96 byte

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

stampe a e bseparato da un trattino basso; un carattere di sottolineatura unico per nessuna soluzione.

Ti dice anche l'operazione per altri 11 byte:
basta sostituire il primo trattino di sottolineatura nel codice con '-+'[!$m[2]].


Se provo 67 in echo strlen ($ n = decbin ($ argv [1])) - !! strpos ($ n, '01 ') .'- +' [! $ N [2]]. Strpos (strrev ( $ n), 49); mi restituisce 6 + 0 che è 65
Jörg Hülsermann

@ JörgHülsermann: 67 non ha soluzione; il comportamento per nessuna soluzione non è definito; quindi non importa cosa stampa per 67.
Tito

0

PHP, 117 byte

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

Versione estesa 4 casi

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

la versione corta unisce Case 1 e 3 e fa la differenza con Case 3 e in entrambe le versioni Case 4 non produce output.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.