Somme ou différence de deux puissances de deux

27

Votre défi, si vous choisissez de l'accepter, est, étant donné un entier K >= 1, de trouver des entiers non négatifs Aet B tels qu'au moins une des deux conditions suivantes soit vérifiée:

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

S'il n'existe pas tel Aet B, votre programme peut se comporter de n'importe quelle façon. (Pour clarifier, Aet Bpeut être égal.)

Cas de test

Il existe souvent plusieurs solutions à un certain nombre, mais en voici quelques-unes:

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 

Le dernier cas de test, 17179867136, doit être exécuté en moins de 10 secondes sur une machine relativement moderne. C'est un golf de code, donc le programme le plus court en octets gagne. Vous pouvez utiliser un programme complet ou une fonction.

Conor O'Brien
la source
5
A peut -il égaler B ?
Dennis
2
@Dennis Je ne vois pas pourquoi.
Conor O'Brien
... et pour 16, les deux 5,4et 3,3sont valides.
Titus
En fait, maintenant que j'y pense, peut A-il Bêtre négatif? (par exemple -1, -1pour 1)
Sp3000
@ Sp3000 Non, bon point.
Conor O'Brien

Réponses:

3

Gelée , 11 10 octets

;0+N&$BL€’

Appliquer l'astuce de twiddling de bits de la réponse Python par @xnor

Testez-le sur TryItOnline
Tous les cas de test sont également sur TryItOnline

Comment?

;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
la source
15

Python 2, 43 octets

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

Dites ça n==2^a ± 2^bavec a>b. Ensuite, le plus grand facteur de puissance de 2 nest 2^b, et nous pouvons le trouver en utilisant le bit-trick 2^b = n&-n. Cela nous permet de calculer 2^b + n, ce qui est égal 2^a + 2 * 2^bou juste 2^a. L'un ou l'autre a la même longueur de bits que a*. Ainsi, nous émettons les longueurs de bits de n&-net (n&-n)+n, calculées à partir des longueurs de leurs représentations binaires. Python 3 est un octet de plus pour les parens dans for k in(n,0)].

* Sauf 2^a + 2^bqu'avec a==b+1a une longueur de bit plus longue, mais c'est très bien car nous pouvons interpréter cela comme 2^(a+1)-2^b.

xnor
la source
Merveilleux - je cherchais un peu de violon, mais je ne pouvais pas le résoudre, juste porté sur Jelly.
Jonathan Allan
Essayez n=4ou 8ou 16s'il vous plaît.
Titus
@Titus f(2**n)revient (n+1,n)et 2**(n+1)-2**n=2**nil n'y a donc aucun problème.
Jonathan Allan
ah ... Quel est le format de bin()Python?
Titus
@Titus c'est une chaîne avec un début 0b, d'où le -3.
Jonathan Allan
8

JavaScript (ES6), 73 octets

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

Pour le cas de soustraction, le premier nombre est le nombre de chiffres dans la représentation binaire et le deuxième nombre est le nombre de zéros à droite. Pour le cas d'addition, on soustrait 1 du premier nombre. Si la représentation binaire est tous les 1 suivis de quelques 0 alors le cas d'addition est supposé sinon le cas de soustraction est supposé. Port de 36 octets de la version @ xnor qui ne fonctionne que pour B≤30 en JavaScript:

n=>[(l=Math.log2)(n+(n&=-n))|0,l(n)]
Neil
la source
2
@ETHproductions Bien sûr, mais je l'ai minimisé à 36.
Neil
Mon mauvais, je pensais que la version 36 octets ne fonctionnait pas pour le cas de test de 17 milliards.
ETHproductions
@ETHproductions Ce n'est pas le cas, mais votre port non plus, si je me souviens bien (commentaire depuis supprimé, soupir), car il a utilisé des opérations au niveau du bit.
Neil
Désolé, le voici à nouveau: n=>[n,0].map(k=>((n&-n)+k).toString(2).length-1)Et les deux versions reviennent [34,11]sur le dernier cas de test (j'utilise FF 48).
ETHproductions
@ETHproductions Aha, donc plus précisément ils fonctionnent lorsque le deuxième résultat est 30 ou moins.
Neil
6

Perl, 52 49 32 octets

Ancienne solution (49 octets)

Comprend +1 pour -p

Donnez votre avis sur STDIN:

pow2.pl <<< 17179867136

pow2.pl

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

Cependant, l'utilisation de l'algorithme de xnor et l'ajout d'une torsion donne 32 octets:

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

Juste le code:

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

Cela souffre d'une grave erreur d'arrondi car il 13/9 = 1.444...est un peu au-dessus 1/log 2 = 1.44269...( loglui-même a également une erreur d'arrondi mais qui est tellement plus petit que nous pouvons le conclure dans l'analyse du 13/9). Mais comme tout 2**big - 2** smallest corrigé 2** bigavant le journal, cela n'a pas d'importance et le calcul de 2**big + 2 * 2**smallest tronqué, il est donc également sûr. Et de l'autre côté de la plage, il 2**n+2**(n-1)n'est pas suffisamment augmenté dans la plage [0,64](je ne peux pas correctement prendre en charge plus que la plage entière de toute façon en raison de l'utilisation de &) pour conduire à un mauvais résultat (le multiplicateur 1.5serait cependant trop éloigné pour les grands nombres).

Ton Hospel
la source
5

Brachylog , 23 octets

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

Essayez-le en ligne!

Ceci est beaucoup plus rapide que nécessaire, par exemple, il reste moins de 10 secondes sur TIO .

Explication

Il s'agit essentiellement d'une transcription directe de la formule sans optimisation:

,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
Fatalize
la source
2
Il semble que ce défi ait été fait pour la langue: D
Conor O'Brien
4

Python, 69 octets

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

Les tests sont sur idéone

Étant donné qu'une entrée non valide peut faire n'importe quoi, nous savons que si l'entrée a exactement 2 bits définis, c'est la somme de ces 2 puissances de 2, et sinon (si elle est valide), ce sera une série d'un certain nombre de bits (y compris la possibilité de seulement 1 bit) et sera la différence entre la prochaine puissance la plus élevée de 2 que le MSB et l'ensemble LSB.

Jonathan Allan
la source
4

JAVA 7,142 ,140, 134 octets

Ceci est mon premier article sur PPCG! J'apprécierais vraiment les commentaires sur les astuces de golf
Merci à gelé pour avoir économisé 2 octets

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

idéone

Numberknot
la source
1
Salut numberknot! Un autre vagabond de perplexe que je vois. Cela ne semble pas fonctionner 40=2**3+2**5, par exemple. En le regardant, je ne vois pas pourquoi, peut-être que j'ai fait une erreur de transcription ...
Jonathan Allan
1
@JonathanAllan Maintenant, cela fonctionne très bien. En fait, les crochets manquaient dans cette ligne si ((a << i) + (a << j) == n | (a << j) - (a << i) == n ) et merci.
Numberknot
Ne pouvez-vous pas utiliser un littéral 1au lieu de lui déclarer une variable?
Titus
1
@TItus si j'utilise le littéral 1, ce testcase (17179867136) ne serait pas possible car si vous utilisez le littéral 1, java lui attribue automatiquement un espace mémoire INT.
Numberknot
1
Vous pouvez déclarer j avec i:for(int i=-1,j;[...]
Frozn
4

Mathematica, 57 54 octets

Enregistré 3 octets grâce à LegionMammal978!

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

Imprime en fait toutes les 1 paires appropriées {a, b}. 2Log@#+1est une limite supérieure pour la plus grande aqui peut éventuellement apparaître lors de la représentation de l'entrée #(la limite supérieure étroite est Log [2 #] / Log [2] = 1,44 ... Log [#] + 1). Fonctionne presque instantanément sur l'entrée de test, et en moins d'un quart de seconde (sur mon nouvel ordinateur standard) sur des entrées à 100 chiffres.

1 Laisser adémarrer à la valeur par défaut de 1 au lieu de 0 économise deux octets; il provoque la sortie {0,0} à manquer lorsque l'entrée est 2, mais trouve la sortie {2,1} dans ce cas, ce qui est assez bon.

Greg Martin
la source
Toutes les paires appropriées? (En outre, If[Abs[2^a-#]==2^b,Print@{a,b}]peut être remplacé par Abs[2^a-#]==2^b&&Print@{a,b}pour économiser 3 octets.)
LegionMammal978
Belle observation, je comprends! "All *" était une note de bas de page, mais c'est plus clair maintenant.
Greg Martin
3

MATL , 23 22 octets

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

Essayez-le en ligne! Ou vérifiez tous les cas de test .

Explication

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
la source
3

Perl 6 , 41 octets

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

(Algorithme copié sans vergogne à partir de la réponse Perl 5 )

Explication:

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

Usage:

# 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
la source
1

PHP, 73 octets

J'aurais pu copier la solution Pyhton 2 de Jonathan pour 54 octets (+13 de surcharge),
mais je voulais trouver quelque chose de différent.

enregistrer dans un fichier, puis exécuter avec phpou php-cgi.

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

imprimés aet bséparés par un trait de soulignement, rien pour aucune solution.

solution distinctive, 96 octets

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

imprimés aet bséparés par un trait de soulignement; un seul soulignement pour aucune solution.

Il vous indique même l'opération pour 11 octets supplémentaires: il
suffit de remplacer le premier trait de soulignement du code par '-+'[!$m[2]].

Titus
la source
Si j'essaie 67 dans echo strlen ($ n = decbin ($ argv [1])) - !! strpos ($ n, '01 ') .'- +' [! $ N [2]]. Strpos (strrev ( n), 49); cela me rend 6 + 0 qui est 65
Jörg Hülsermann
@ JörgHülsermann: 67 n'a pas de solution; le comportement pour aucune solution n'est pas défini; donc peu importe ce qu'il imprime pour 67.
Titus
0

PHP, 117 octets

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

Etuis version 4 étendue

$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 version courte réunit les cas 1 et 3 et fait une différence avec le cas 3 et dans les deux versions, le cas 4 ne donne aucune sortie.

Jörg Hülsermann
la source