Trouver le nombre de zéros non significatifs dans un entier 64 bits

18

Problème:

Trouver le nombre de zéros non significatifs dans un entier signé 64 bits

Règles:

  • L'entrée ne peut pas être traitée comme une chaîne; cela peut être n'importe quoi où les opérations mathématiques et au niveau des bits conduisent l'algorithme
  • La sortie doit être validée par rapport à la représentation entière signée 64 bits du nombre, quelle que soit la langue
  • Les règles de golf par défaut s'appliquent
  • Le code le plus court en octets gagne

Cas de test:

Ces tests supposent deux entiers signés complémentaires. Si votre langue / solution manque ou utilise une représentation différente des entiers signés, veuillez l'indiquer et fournir des cas de test supplémentaires qui peuvent être pertinents. J'ai inclus quelques cas de test qui traitent de la double précision, mais n'hésitez pas à en suggérer d'autres qui devraient être répertoriés.

input                output   64-bit binary representation of input (2's complement)
-1                   0        1111111111111111111111111111111111111111111111111111111111111111
-9223372036854775808 0        1000000000000000000000000000000000000000000000000000000000000000
9223372036854775807  1        0111111111111111111111111111111111111111111111111111111111111111
4611686018427387903  2        0011111111111111111111111111111111111111111111111111111111111111
1224979098644774911  3        0001000011111111111111111111111111111111111111111111111111111111
9007199254740992     10       0000000000100000000000000000000000000000000000000000000000000000
4503599627370496     11       0000000000010000000000000000000000000000000000000000000000000000
4503599627370495     12       0000000000001111111111111111111111111111111111111111111111111111
2147483648           32       0000000000000000000000000000000010000000000000000000000000000000
2147483647           33       0000000000000000000000000000000001111111111111111111111111111111
2                    62       0000000000000000000000000000000000000000000000000000000000000010
1                    63       0000000000000000000000000000000000000000000000000000000000000001
0                    64       0000000000000000000000000000000000000000000000000000000000000000
Dave
la source
13
Bienvenue chez PPCG! Quelle est la raison derrière "l'entrée ne peut pas être traitée comme une chaîne" ? Cela disqualifie toutes les langues qui ne peuvent pas gérer les entiers 64 bits et est peu susceptible de conduire à plus de réponses qui prennent un entier, car c'est de toute façon la méthode la plus simple lorsqu'elle est disponible.
Arnauld
1
Pouvons-nous revenir Falseau lieu de 0?
Jo King
4
@Arnauld Il y a déjà des questions similaires ici et sur d'autres sites qui appellent spécifiquement à des solutions basées sur des chaînes, mais rien qui ouvre la question aux opérations mathématiques et logiques. Mon espoir est de voir un tas d'approches différentes à ce problème qui ne sont pas déjà répondu ailleurs. Cela devrait-il être également ouvert aux solutions de chaînes pour être tout compris?
Dave
4
Plusieurs processeurs, y compris x86 et ARM, ont des instructions spécifiques à ce sujet (x86 en a plusieurs). Je me suis toujours demandé pourquoi les langages de programmation n'exposent pas cette fonctionnalité, car dans la plupart des langages de programmation aujourd'hui, vous ne pouvez pas invoquer les instructions d'assemblage.
slebetman
1
@ user202729 Je pense que j'ai mal formulé ceci: 'La sortie doit être validée par rapport à la représentation entière signée 64 bits du nombre, quelle que soit la langue' Ce que je veux dire par là, c'est que cette question définit le nombre de zéros comme le nombre de zéros dans un entier signé 64 bits. Je suppose que j'ai fait cette contrainte pour éliminer les entiers signés et non signés.
Dave

Réponses:

41

Langage machine x86_64 sous Linux, 6 octets

0:       f3 48 0f bd c7          lzcnt  %rdi,%rax
5:       c3                      ret

Nécessite un processeur Haswell ou K10 ou supérieur avec lzcntinstruction.

Essayez-le en ligne!

plafond
la source
20
Les bâtons frappent à nouveau / s
Logern
1
Je recommande de spécifier la convention d'appel utilisée (bien que vous l'ayez dit sur Linux)
qwr
@qwr Il ressemble à la convention d'appel SysV car le paramètre est passé dans% rdi et il est renvoyé dans% rax.
Logern
24

Hexagonie , 78 70 octets

2"1"\.}/{}A=<\?>(<$\*}[_(A\".{}."&.'\&=/.."!=\2'%<..(@.>._.\=\{}:"<><$

Essayez-le en ligne!

Ce défi n'est-il pas trop banal pour un langage pratique? ;)

longueur de côté 6. Je ne peux pas l'adapter dans un hexagone de longueur de côté 5.

Explication

user202729
la source
3
J'ai ri très fort de "l'explication". : D
Eric Duminil
1
Je pense que vous avez peut-être trop compliqué à gérer des nombres négatifs / zéro. J'ai réussi à adapter un programme similaire à la longueur de côté 5 en ne faisant pas ce calcul lourd de 2 ^ 64. Ce n'est clairement pas encore bien joué, cependant!
FryAmTheEggman
@fry Ah à droite, les nombres négatifs ont toujours 0 zéros en tête ... ce qui conduit définitivement à un programme plus court car génère 2 ^ 64 est long.
user202729
12

Python , 31 octets

lambda n:67-len(bin(-n))&~n>>64

Essayez-le en ligne!

L'expresson est le bit à bit &de deux parties:

67-len(bin(-n)) & ~n>>64

Le 67-len(bin(-n))donne la bonne réponse pour les entrées non négatives. Il prend la longueur en bits et soustrait 67, ce qui est 3 de plus que 64 pour compenser le -0bpréfixe. La négation est une astuce à régler pour n==0utiliser cette négation qui ne produit pas de -signe devant.

Le & ~n>>64fait que la réponse soit plutôt 0négative n. Quand n<0, ~n>>64est égal à 0 (sur des entiers 64 bits), donc -ing avec cela0 . Quand n>=0, l' ~n>>64évalue -1et l'action &-1n'a aucun effet.


Python 2 , 36 octets

f=lambda n:n>0and~-f(n/2)or(n==0)*64

Essayez-le en ligne!

Alternative arithmétique.

xnor
la source
9

Java 8, 32 26 octets.

Long::numberOfLeadingZeros

Builtins FTW.

-6 octets grâce à Kevin Cruijssen

Essayez-le en ligne!

lukeg
la source
Ah, complètement oublié numberOfLeadingZeros.. Vous pouvez n->n.numberOfLeadingZeros(n)
jouer au
2
En fait, Long::numberOfLeadingZerosest encore plus court (26 octets).
Kevin Cruijssen
6
Wow, il n'arrive pas très souvent que Java bat Python. Félicitations!
Eric Duminil
9

C (gcc) , 14 octets

__builtin_clzl

Fonctionne bien sur tio

C (gcc) , 35 29 octets

f(long n){n=n<0?0:f(n-~n)+1;}

Essayez-le en ligne!

Que Dennis pour 6 octets

Indicateurs du compilateur C (gcc) , 29 octets par David Foerster

-Df(n)=n?__builtin_clzl(n):64

Essayez-le en ligne!

l4m2
la source
3
A noter que ce n'est que pour les machines 64 bits (ou toutes autres avec LP64 / ILP64 / etc. ABI)
Ruslan
1
Décidément, c'est encore plus court que toute utilisation du GCC intégré__builtin_clzl avec laquelle je peux arriver .
David Foerster
@Ruslan: bon point, sur les systèmes où longest 32 bits (y compris Windows x64), vous avez besoin __builtin_clzll(non signé long long). godbolt.org/z/MACCKf . (Contrairement à Intel intrinsèques, les builds GNU C sont pris en charge quelle que soit l'opération réalisable avec une instruction machine. Sur x86 32 bits, clzll se compile en une branche ou cmov pour faire lzcnt(low half)+32ou lzcnt(high half). Ou bsrsilzcnt n'est pas disponible.
Peter Cordes
Les cas de test incluent "0" mais __builtin_clz(l)(l) comportement n'est pas défini pour zéro: "Si x est 0, le résultat n'est pas défini."
MCCCS
1
@MCCCS Si ça marche, ça compte. C'est aussi pourquoi je garde la dernière réponse
l4m2
6

Perl 6 , 35 28 26 octets

-2 octets grâce à nwellnhof

{to .fmt("%064b")~~/^0*/:}

Essayez-le en ligne!

Bloc de code anonyme qui prend un nombre et renvoie un nombre. Cela convertit le nombre en une chaîne binaire et compte les zéros non significatifs. Cela fonctionne pour les nombres négatifs car le premier caractère est un -exemple -00000101, donc il n'y a pas de zéros de tête.

Explication:

{                        }  # Anonymous code block
    .fmt("%064b")           # Format as a binary string with 64 digits
                 ~~         # Smartmatch against
                   /^0*/    # A regex counting leading zeroes
 to                     :   # Return the index of the end of the match
Jo King
la source
6

JavaScript (Node.js) , 25 octets

Prend l'entrée comme un littéral BigInt.

f=x=>x<0?0:x?f(x/2n)-1:64

Essayez-le en ligne!

0

Arnauld
la source
n=>n<1?0:n.toString(2)-64N'exécuterait pas la même chose?
Ismael Miguel
@IsmaelMiguel Je suppose que vous vouliez dire n=>n<1?0:n.toString(2).length-64, mais cela ne fonctionnerait pas de toute façon. Ce serait , je pense.
Arnauld
1
@IsmaelMiguel Pas de soucis. :) Il est en effet possible que l' .toString()approche fonctionne, mais nous avons toujours besoin d'un littéral BigInt en entrée. Sinon, nous n'avons que 52 bits de mantisse, ce qui conduit à des résultats invalides lorsque la précision est perdue .
Arnauld
1
Le fait que le suffixe BigInt ait le même caractère que votre paramètre est très déroutant ...
Neil
1
@Neil Code illisible sur PPCG ?? Ça ne peut pas être! Fixé! : p
Arnauld
5

J , 18 octets

0{[:I.1,~(64$2)#:]

Essayez-le en ligne!

J , 19 octets

1#.[:*/\0=(64$2)#:]

Essayez-le en ligne!

Explication:

                #:  - convert 
                  ] - the input to
          (64$2)    - 64 binary digits
         =          - check if each digit equals 
        0           - zero
   [:*/\            - find the running product
1#.                 - sum
Galen Ivanov
la source
1
1#.[:*/\1-_64{.#:(17) est proche mais ne fonctionne pas pour les nombres négatifs :(
Conor O'Brien
@Conor O'Brien Belle approche aussi!
Galen Ivanov
4

05AB1E , 10 9 octets

·bg65αsd*

Les E / S sont deux entiers

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

Explication:

·         # Double the (implicit) input
          #  i.e. -1 → -2
          #  i.e. 4503599627370496 → 9007199254740992
 b        # Convert it to binary
          #  i.e. -2 → "ÿ0"
          #  i.e. 9007199254740992 → 100000000000000000000000000000000000000000000000000000
  g       # Take its length
          #  i.e. "ÿ0" → 2
          #  i.e. 100000000000000000000000000000000000000000000000000000 → 54
   65α    # Take the absolute different with 65
          #  i.e. 65 and 2 → 63
          #  i.e. 65 and 54 → 11
      s   # Swap to take the (implicit) input again
       d  # Check if it's non-negative (>= 0): 0 if negative; 1 if 0 or positive
          #  i.e. -1 → 0
          #  i.e. 4503599627370496 → 1
        * # Multiply them (and output implicitly)
          #  i.e. 63 and 0 → 0
          #  i.e. 11 and 1 → 11
Kevin Cruijssen
la source
4

Haskell , 56 octets

Merci xnor d' avoir repéré une erreur!

f n|n<0=0|1>0=sum.fst.span(>0)$mapM(pure[1,0])[1..64]!!n

Pourrait allouer beaucoup de mémoire, essayez-le en ligne!

Vous souhaitez peut-être le tester avec une constante plus petite: Essayez 8 bits!

Explication

Au lieu d'utiliser mapM(pure[0,1])[1..64]pour convertir l'entrée en binaire, nous utiliserons mapM(pure[1,0])[1..64]ce qui génère essentiellement les chaînes inversées{0,1}64dans l'ordre lexicographique. Nous pouvons donc simplement résumer la1préfixe s en utilisant sum.fst.span(>0).

ბიმო
la source
3

Powershell, 51 octets

param([long]$n)for(;$n-shl$i++-gt0){}($i,65)[!$n]-1

Script de test:

$f = {

param([long]$n)for(;$n-shl$i++-gt0){}($i,65)[!$n]-1

}

@(
    ,(-1                   ,0 )
    ,(-9223372036854775808 ,0 )
    ,(9223372036854775807  ,1 )
    ,(4611686018427387903  ,2 )
    ,(1224979098644774911  ,3 )
    ,(9007199254740992     ,10)
    ,(4503599627370496     ,11)
    ,(4503599627370495     ,12)
    ,(2147483648           ,32)
    ,(2147483647           ,33)
    ,(2                    ,62)
    ,(1                    ,63)
    ,(0                    ,64)
) | % {
    $n,$expected = $_
    $result = &$f $n
    "$($result-eq$expected): $result"
}

Production:

True: 0
True: 0
True: 1
True: 2
True: 3
True: 10
True: 11
True: 12
True: 32
True: 33
True: 62
True: 63
True: 64
mazzy
la source
3

Java 8, 38 octets

int f(long n){return n<0?0:f(n-~n)+1;}

Entrée en tant que long(entier 64 bits), sortie en tant queint (entier 32 bits).

Port de la réponse C (gcc) de @ l4m2 .

Essayez-le en ligne.

Explication:

 int f(long n){       // Recursive method with long parameter and integer return-type
   return n<0?        //  If the input is negative:
           0          //   Return 0
          :           //  Else:
           f(n-~n)    //   Do a recursive call with n+n+1
                  +1  //   And add 1

EDIT: peut être de 26 octets en utilisant le module intégré Long::numberOfLeadingZeroscomme affiché dans la réponse Java 8 de @lukeg .

Kevin Cruijssen
la source
3

APL + WIN, 34 octets

+/×\0=(0>n),(63⍴2)⊤((2*63)××n)+n←⎕

Explication:

n←⎕ Prompts for input of number as integer

((2*63)××n) If n is negative add 2 to power 63

(63⍴2)⊤ Convert to 63 bit binary

(0>n), Concatinate 1 to front of binary vector if n negative, 0 if positive

+/×\0= Identify zeros, isolate first contiguous group and sum if first element is zero
Graham
la source
3

Gelée ,  10  9 octets

-1 grâce à une astuce d'Erik the Outgolfer (est-non-négatif est maintenant tout simplement )

ḤBL65_×AƑ

Un lien monadique acceptant un entier (dans la plage) qui donne un entier.

Essayez-le en ligne! Ou consultez la suite de tests .


Le 10 était ḤBL65_ɓ>-×

Voici une autre solution de 10 octets, que j'aime car elle dit que c'est "BOSS" ...

BoṠS»-~%65

Test-suite ici

... BoṠS63r0¤i, BoṠS63ŻṚ¤iou BoṠS64ḶṚ¤ifonctionnerait également.


Un autre 10 octets (de Dennis) est æ»64ḶṚ¤Äċ0(encore æ»63r0¤Äċ0et æ»63ŻṚ¤Äċ0fonctionnera également)

Jonathan Allan
la source
9 octets
Erik the Outgolfer
@EriktheOutgolfer Je me suis dit "il doit y avoir une manière golfique de multiplier par isNonNegative" et je n'ai pas du tout pensé au Ƒrapide, très beau travail!
Jonathan Allan
1
En fait, je théorise depuis un certain temps maintenant. Soyez averti qu'il ne vectorise pas! ;-) C'est en fait "aplatir puis vérifier si tous les éléments ne sont pas négatifs".
Erik the Outgolfer
2

Perl 5 , 37 octets

sub{sprintf("%064b",@_)=~/^0*/;$+[0]}

Essayez-le en ligne!

Ou ces 46 octets si la "stringification" n'est pas autorisée: sub z

sub{my$i=0;$_[0]>>64-$_?last:$i++for 1..64;$i}
Kjetil S.
la source
s/length$&/$+[0]/(-3 octets);)
Dada
OMI, vous n'êtes pas autorisé à supprimer le submot - clé des réponses contenant les fonctions Perl 5.
nwellnhof
J'ai vu ce qui est similaire à la suppression des subréponses pour d'autres langues, perl6, PowerShell et plus encore.
Kjetil S.
En Perl6, je pense que vous n'avez pas besoin sub{}de créer un sous (anonyme?), Ce qui explique pourquoi il est omis des réponses Perl6. Je suis d'accord avec @nwellnhof que vous ne devriez pas être autorisé à supprimer sub. (quand j'étais encore actif, il y a environ un an, c'était la règle)
Dada
changé maintenant. Et inclus $+[0].
Kjetil S.
2

Swift (sur une plate-forme 64 bits), 41 octets

Déclare une fermeture appelée fqui accepte et retourne un Int. Cette solution ne fonctionne que correctement sur les plates-formes 64 bits, où Intest typealiasédité Int64. (Sur une plate-forme 32 bits, Int64peut être utilisé explicitement pour le type de paramètre de fermeture, en ajoutant 2 octets.)

let f:(Int)->Int={$0.leadingZeroBitCount}

Dans Swift, même le type entier fondamental est un objet ordinaire déclaré dans la bibliothèque standard. Cela signifie Intpeut avoir des méthodes et des propriétés telles que leadingZeroBitCount(ce qui est requis sur tous les types conformes au FixedWidthIntegerprotocole de la bibliothèque standard ).

NobodyNada - Rétablir Monica
la source
intéressant. me rappelle Rust. Je pense que cela devrait compter comme 20 octets, .leadingZeroBitCount
Don
2

Haskell , 24 octets

f n|n<0=0
f n=1+f(2*n+1)

Essayez-le en ligne!

C'est fondamentalement la même que la solution Java de Kevin Cruijssen, mais je l'ai trouvée indépendamment.

L'argument doit avoir un type Intpour une version 64 bits, ouInt64 pour n'importe quoi.

Explication

Si l'argument est négatif, le résultat est immédiatement 0. Sinon, on décale vers la gauche, en remplissant avec ceux , jusqu'à ce que nous atteignions un nombre négatif. Ce remplissage nous permet d'éviter un cas spécial pour 0.

Juste pour référence, voici le moyen évident / efficace:

34 octets

import Data.Bits
countLeadingZeros
dfeuer
la source
1

Propre , 103 octets

Utilise le même "intégré" que la réponse de plafond.

f::!Int->Int
f _=code {
instruction 243
instruction 72
instruction 15
instruction 189
instruction 192
}

Essayez-le en ligne!

Nettoyer , 58 octets

import StdEnv
$0=64
$i=until(\e=(2^63>>e)bitand i<>0)inc 0

Essayez-le en ligne!

Οurous
la source
1

Perl 5 -p , 42 octets

1while$_>0&&2**++$a-1<$_;$_=0|$_>=0&&64-$a

Essayez-le en ligne!

Plus longue qu'une solution basée sur les chaînes de bits, mais une solution basée sur les mathématiques décente.

Xcali
la source
Ne fonctionne pas vraiment si je ne me trompe pas
Dada
@Dada Je vois qu'il y a quelques cas où la division en virgule flottante ne fonctionne pas tout à fait correctement. J'ai intlancé un appel qui devrait résoudre le problème.
Xcali
Désolé, j'ai échoué mon copier-coller, il semblerait. C'est ce que je voulais envoyer;)
Dada
1

APL (NARS), 15 caractères, 30 octets

{¯1+1⍳⍨⍵⊤⍨64⍴2}

testez quelques chiffres pour voir comment utiliser:

  f←{¯1+1⍳⍨⍵⊤⍨64⍴2}
  f ¯9223372036854775808
0
  f 9223372036854775807
1
RosLuP
la source
1

K (ngn / k) , 6 octets

64-#2\

Essayez-le en ligne!

2\ encoder l'argument en binaire

# longueur

64- soustraire de 64

ngn
la source
# = length... semble basé sur les chaînes
Titus
2
@Titus 2\ donne une liste d'entiers et #trouve sa longueur. aucune chaîne n'est impliquée ici.
ngn
1

PHP, 50 46 octets

for(;0<$n=&$argn;$n>>=1)$i++;echo$n<0?0:64-$i;

Exécuter en tant que pipe avec -Rou essayer en ligne ,

<?=$argn<0?0:0|64-log($argn+1,2);a des problèmes d'arrondi; j'ai donc pris le long chemin.

Titus
la source
1

Wolfram Language (Mathematica), 41 bytes

La formule des nombres positifs est juste 63-Floor@Log2@#& . Des règles de remplacement sont utilisées pour les cas spéciaux d'entrée nulle et négative.

L'entrée n'a pas besoin d'être un entier signé 64 bits. Cela prendra effectivement la parole de l'entrée pour la transformer en un entier. Si vous entrez un nombre en dehors des limites normales pour un entier 64 bits, il indiquera retourner un nombre négatif indiquant combien de bits supplémentaires seraient nécessaires pour stocker cet entier.

63-Floor@Log2[#/.{_?(#<0&):>2^63,0:>.5}]&

Essayez-le en ligne!

La solution de @ LegionMammal978 est un peu plus courte avec 28 octets. L'entrée doit être un entier. Selon la documentation: " BitLength[n]est effectivement une version efficace de Floor[Log[2,n]]+1." Il gère automatiquement le cas de zéro correctement rapportant 0plutôt que -∞.

Wolfram Language (Mathematica) , 28 octets

Boole[#>=0](64-BitLength@#)&

Essayez-le en ligne!

Kelly Lowder
la source
1
Boole[#>=0](64-BitLength@#)& is a good bit shorter at 28 bytes. It uses the same basic concept as yours, but applies BitLength and Boole.
LegionMammal978
I totally forgot about BitLength!
Kelly Lowder
1

bitNumber - math.ceil (math.log(number) / math.log(2))

e.g 64 bit NUMBER : 9223372036854775807 math.ceil (math.log(9223372036854775807) / math.log(2)) ANS: 63

user90293
la source
If you could add the language name to this, that would be great,as people are likely to down vote answers that don't have the language name included
Jono 2906