Suma o diferencia de dos poderes de dos

27

Su desafío, si elige aceptarlo, es, dado un número entero K >= 1, encontrar números enteros no negativos Ay B tal que al menos una de las dos condiciones siguientes se cumpla:

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

Si no existe tal Ay B, su programa puede comportarse de cualquier manera. (Para aclarar, Ay Bpuede ser igual).

Casos de prueba

A menudo hay múltiples soluciones para un número, pero aquí hay algunas:

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 

El último caso de prueba 17179867136, debe ejecutarse en menos de 10 segundos en cualquier máquina relativamente moderna. Este es un código de golf, por lo que gana el programa más corto en bytes. Puede usar un programa completo o una función.

Conor O'Brien
fuente
55
¿Puede A ser igual a B ?
Dennis
2
@ Dennis No veo por qué no.
Conor O'Brien
... y para 16, ambos 5,4y 3,3son válidos.
Tito
En realidad, ahora que lo pienso, puede A, Bser negativo? (por ejemplo, -1, -1para 1)
Sp3000
@ Sp3000 No, buen punto.
Conor O'Brien

Respuestas:

3

Jalea , 11 10 bytes

;0+N&$BL€’

Aplicando el truco de bit twiddling de twiddling la respuesta de Python de @xnor

Pruébelo en TryItOnline
Todos los casos de prueba también están en TryItOnline

¿Cómo?

;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
fuente
15

Python 2, 43 bytes

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

Di eso n==2^a ± 2^bcon a>b. Entonces, el mayor factor de potencia de 2 nes 2^b, y podemos encontrarlo usando el truco de bits 2^b = n&-n. Eso nos permite calcular 2^b + n, que es igual 2^a + 2 * 2^bo igual 2^a. Cualquiera de los dos tiene la misma longitud de bits que a*. Entonces, sacamos las longitudes de bits de n&-ny (n&-n)+n, calculadas a partir de las longitudes de sus representaciones binarias. Python 3 es un byte más largo para los padres en for k in(n,0)].

* Excepto que 2^a + 2^bwith a==b+1tiene una longitud de bit más larga, pero está bien porque podemos interpretar eso como 2^(a+1)-2^b.

xnor
fuente
Maravilloso: busqué un poco de violín, pero no pude resolverlo, solo lo porté a Jelly.
Jonathan Allan
Prueba n=4o 8o 16por favor.
Tito
@Titus f(2**n)regresa (n+1,n)y 2**(n+1)-2**n=2**nno hay problema.
Jonathan Allan
ah ... ¿Cuál es el formato de bin()en Python?
Tito
@Titus es una cadena con un encabezado 0b, de ahí el -3.
Jonathan Allan
8

JavaScript (ES6), 73 bytes

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

Para el caso de resta, el primer número es el número de dígitos en la representación binaria y el segundo número es el número de ceros finales. Para el caso de la suma, restamos 1 del primer número. Si la representación binaria es todos los 1 seguidos de algunos 0, entonces se supone el caso de suma, de lo contrario se supone el caso de resta. Puerto de 36 bytes de la versión de @ xnor que solo funciona para B≤30 en JavaScript:

n=>[(l=Math.log2)(n+(n&=-n))|0,l(n)]
Neil
fuente
2
@ETHproductions Claro, pero lo bajé a 36.
Neil
Mi mal, pensé que la versión de 36 bytes no funcionaba para el caso de prueba de 17 mil millones.
ETHproductions
@ETHproductions No lo hace, pero tampoco lo hizo su puerto, como recuerdo (comentario desde eliminado, suspiro), ya que utilizaba operaciones bit a bit.
Neil
Lo siento, aquí está de nuevo: n=>[n,0].map(k=>((n&-n)+k).toString(2).length-1)y ambas versiones regresan [34,11]en el último caso de prueba (estoy usando FF 48).
ETHproductions
@ETHproductions Aha, por lo que funcionan con mayor precisión cuando el segundo resultado es 30 o menos.
Neil
6

Perl, 52 49 32 bytes

Solución anterior (49 bytes)

Incluye +1 para -p

Dar entrada en STDIN:

pow2.pl <<< 17179867136

pow2.pl

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

Sin embargo, usar el algoritmo de xnor y agregar un giro da 32 bytes:

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

Solo el código:

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

Esto sufre un grave error de redondeo porque 13/9 = 1.444...está bastante por encima 1/log 2 = 1.44269...( logtambién tiene un error de redondeo, pero es mucho más pequeño que podemos resumirlo en el análisis de 13/9). Pero dado que cualquiera 2**big - 2** smallse corrige 2** bigantes del registro, esto no importa y el cálculo para 2**big + 2 * 2**smallse trunca, por lo que también es seguro ... Y en el otro lado del rango 2**n+2**(n-1)no aumenta lo suficiente en el rango [0,64](no puedo admite más que el rango entero de todos modos debido al uso de &) para conducir a un resultado incorrecto (el multiplicador, 1.5sin embargo, estaría demasiado lejos para números grandes).

Ton Hospel
fuente
5

Brachylog , 23 bytes

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

Pruébalo en línea!

Esto es mucho más rápido de lo requerido, por ejemplo, esto todavía es inferior a 10 segundos en TIO .

Explicación

Esto es básicamente una transcripción directa de la fórmula sin optimización:

,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
Fatalizar
fuente
2
Parece que este desafío fue hecho para el idioma: D
Conor O'Brien
4

Python, 69 bytes

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

Las pruebas están en ideone

Como la entrada no válida puede hacer cualquier cosa, sabemos que si la entrada tiene exactamente 2 bits configurados, es la suma de esas 2 potencias de 2, y de lo contrario (si es válida) se ejecutará una cierta cantidad de bits (incluyendo la posibilidad de solo 1 bit) y será la diferencia entre la siguiente potencia más alta de 2 que el conjunto MSB y LSB.

Jonathan Allan
fuente
4

JAVA 7,142 ,140134 BYTES

¡Esta es mi primera publicación en PPCG! Realmente agradecería sus comentarios sobre consejos de golf
Gracias a frozen por guardar 2 bytes

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

ideona

Nudo numérico
fuente
1
Hola numberknot! Otro vagabundo de desconcierto que veo. No parece funcionar para 40=2**3+2**5, por ejemplo. En cuanto a ella, no veo por qué no, tal vez cometió un error de transcripción ...
Jonathan Allan
1
@JonathanAllan Ahora funciona bien. En realidad, faltaban los corchetes en esta línea si ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) y gracias.
Numberknot
¿No puedes usar un literal en 1lugar de declarar una variable para él?
Titus
1
@TItus si uso el literal 1, entonces este caso de prueba (17179867136) no sería posible porque si usa el literal 1, entonces Java le asignará automáticamente un espacio de memoria INT.
Numberknot
1
Puede declarar j junto con i:for(int i=-1,j;[...]
Frozn
4

Mathematica, 57 54 bytes

¡Guardado 3 bytes gracias a LegionMammal978!

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

Realmente imprime los 1 pares apropiados {a, b}. 2Log@#+1es un límite superior para el más grande aque puede aparecer al representar la entrada #(el límite superior ajustado es Log [2 #] / Log [2] = 1.44 ... Log [#] + 1). Se ejecuta casi instantáneamente en la entrada de prueba, y en menos de un cuarto de segundo (en mi computadora nueva pero lista para usar) en entradas de 100 dígitos.

1 Dejar que acomience con el valor predeterminado de 1 en lugar de 0 ahorra dos bytes; hace que la salida {0,0} se pierda cuando la entrada es 2, pero encuentra la salida {2,1} en ese caso, lo cual es lo suficientemente bueno.

Greg Martin
fuente
Todos * pares apropiados? (Además, If[Abs[2^a-#]==2^b,Print@{a,b}]se puede reemplazar con Abs[2^a-#]==2^b&&Print@{a,b}para guardar 3 bytes.)
LegionMammal978
Buena observación, lo entiendo! "Todos *" fue una nota al pie, pero ahora está más claro.
Greg Martin
3

MATL , 23 22 bytes

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

Pruébalo en línea! O verificar todos los casos de prueba .

Explicación

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
fuente
3

Perl 6 , 41 bytes

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

(Algoritmo copiado descaradamente de la respuesta de Perl 5 )

Explicación:

# 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)
Brad Gilbert b2gills
fuente
1

PHP, 73 bytes

Podría haber copiado la solución Python de Jonathan 2 para 54 bytes (+13 sobrecarga),
pero quería encontrar algo diferente.

guardar en el archivo, luego ejecutar con phpo php-cgi.

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

impresiones ayb separadas por un guión bajo, cualquier cosa sin solución.

solución distintiva, 96 bytes

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

huellas dactilares a y bseparadas por un guión bajo; Un único guión bajo para ninguna solución.

Incluso le indica la operación para 11 bytes más:
simplemente reemplace el primer guión bajo en el código con '-+'[!$m[2]].

Titus
fuente
Si intento 67 en echo strlen ($ n = decbin ($ argv [1])) - !! strpos ($ n, '01 ') .'- +' [! $ N [2]]. Strpos (strrev ( $ n), 49); me devuelve 6 + 0, que es 65
Jörg Hülsermann
@ JörgHülsermann: 67 no tiene solución; el comportamiento para ninguna solución es indefinido; así que no importa para qué imprime 67.
Tito
0

PHP, 117 bytes

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

Versión extendida 4 Casos

$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 versión corta une los casos 1 y 3 y marca la diferencia con el caso 3 y en ambas versiones el caso 4 no da salida.

Jörg Hülsermann
fuente