Encontre o número de zeros à esquerda em um número inteiro de 64 bits

18

Problema:

Encontre o número de zeros à esquerda em um número inteiro assinado de 64 bits

Regras:

  • A entrada não pode ser tratada como sequência; pode ser qualquer coisa em que operações matemáticas e bit a bit conduzem o algoritmo
  • A saída deve ser validada com relação à representação inteira assinada de 64 bits do número, independentemente do idioma
  • Aplicam-se as regras de código padrão de golfe
  • O menor código em bytes ganha

Casos de teste:

Esses testes assumem números inteiros assinados pelo complemento de dois. Se seu idioma / solução não possui ou usa uma representação diferente de números inteiros assinados, chame isso e forneça casos de teste adicionais que possam ser relevantes. Incluí alguns casos de teste que abordam precisão dupla, mas fique à vontade para sugerir outros que devem ser listados.

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
fonte
13
Bem-vindo ao PPCG! Qual é a razão por trás de "a entrada não pode ser tratada como string" ? Isso desqualifica todos os idiomas que não conseguem lidar com números inteiros de 64 bits e é improvável que leve a mais respostas que usem um número inteiro, porque essa é a maneira direta quando disponível de qualquer maneira.
Arnauld
1
Podemos voltar em Falsevez de 0?
Jo rei
4
@ Arnauld Já existem perguntas semelhantes aqui e em outros sites que exigem especificamente soluções baseadas em strings, mas nada que abre a questão para operações matemáticas e lógicas. Minha esperança é ver várias abordagens diferentes para esse problema que ainda não foram respondidas em outros lugares. Isso deve ser aberto a soluções de cadeia de caracteres, assim como com tudo incluído?
Dave
4
Várias CPUs, incluindo x86 e ARM, têm instruções específicas para isso (na verdade, x86 possui várias). Eu sempre me perguntei por que as linguagens de programação não expõem esse recurso, já que na maioria das linguagens de programação hoje você não pode invocar instruções de montagem.
slebetman
1
@ user202729 Acho que escrevi mal isso: 'A saída deve ser validada contra a representação inteira assinada de 64 bits do número, independentemente do idioma' O que quero dizer com isso é que essa pergunta define o número de zeros como o número de zeros em um número inteiro assinado de 64 bits. Acho que fiz essa restrição para eliminar números inteiros assinados vs não assinados.
Dave

Respostas:

41

Linguagem de máquina x86_64 no Linux, 6 bytes

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

Requer processador Haswell ou K10 ou superior com lzcnt instruções.

Experimente online!

teto
fonte
20
Builtins atacam novamente / s
Logern
1
Eu recomendo especificando a convenção de chamada utilizado (embora você disse em Linux)
QWR
@qwr Parece a convenção de chamada SysV porque o parâmetro é passado em% rdi e retornado em% rax.
Logern
24

Hexagonia , 78 70 bytes

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

Experimente online!

Esse desafio não é trivial demais para uma linguagem prática? ;)

comprimento lateral 6. Não consigo encaixá-lo em um hexágono de comprimento lateral 5.

Explicação

user202729
fonte
3
Eu ri muito com a "explicação". : D
Eric Duminil
1
Eu acho que você pode ter complicado demais lidar com números negativos / zero. Consegui encaixar um programa semelhante no comprimento do lado 5, não fazendo esse cálculo pesado de 2 ^ 64. Ainda não está claramente bem jogado de golfe!
FryAmTheEggman
@ frry Ah, certo, números negativos sempre têm 0 zeros à esquerda ... o que definitivamente leva a um programa mais curto, porque gera 2 ^ 64 é longo.
user202729
12

Python , 31 bytes

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

Experimente online!

O expresson é o bit a bit &de duas partes:

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

O 67-len(bin(-n))fornece a resposta correta para entradas não negativas. Ele pega o comprimento do bit e subtrai de 67, que é 3 a mais que 64 para compensar o -0bprefixo. A negação é um truque para ajustar ao n==0usar essa negação que não produz um- sinal na frente.

Em & ~n>>64vez disso, a resposta é 0negativa n. Quando n<0, ~n>>64é igual a 0 (em números inteiros de 64 bits), e assim por diante 0. Quando n>=0, o ~n>>64avalia -1e o fazer &-1não tem efeito.


Python 2 , 36 bytes

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

Experimente online!

Alternativa aritmética.

xnor
fonte
9

Java 8, 32 26 bytes.

Long::numberOfLeadingZeros

Builtins FTW.

-6 bytes graças a Kevin Cruijssen

Experimente online!

lukeg
fonte
Ah, esqueci completamente numberOfLeadingZeros. Você pode jogar com 28 bytes de btw:n->n.numberOfLeadingZeros(n)
Kevin Cruijssen
2
Na verdade, Long::numberOfLeadingZerosé ainda mais curto (26 bytes).
21818 Kevin Kevin Kurtzleren
6
Uau, não acontece com muita frequência que o Java vence o Python. Parabéns!
Eric Duminil
9

C (gcc) , 14 bytes

__builtin_clzl

Funciona bem em tio

C (gcc) , 35 29 bytes

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

Experimente online!

Than Dennis por 6 bytes

Sinalizadores do compilador C (gcc) , 29 bytes por David Foerster

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

Experimente online!

l4m2
fonte
3
Vale a pena notar que é apenas para máquinas de 64 bits (ou quaisquer outras com LP64 / ILP64 / etc. ABI)
Ruslan
1
Nossa, isso é ainda mais curto do que qualquer uso do GCC embutido__builtin_clzl com o qual eu possa criar .
David Foerster
@Ruslan: bom ponto, em sistemas com long32 bits (incluindo Windows x64), é necessário __builtin_clzll(sem assinatura por muito tempo). godbolt.org/z/MACCKf . (Diferentemente dos intrínsecos da Intel, os embutidos do GNU C são suportados, independentemente da operação ser executável com uma instrução de máquina. No x86 de 32 bits, o clzll compila em uma ramificação ou cmov para fazer lzcnt(low half)+32ou lzcnt(high half). Ou, bsrse lzcntnão estiver disponível.
Peter Cordes
Os casos de teste incluem "0", mas o __builtin_clz(l)(l)comportamento é indefinido para zero: "Se x for 0, o resultado será indefinido."
MCCCS
1
@MCCCS Se funcionar, conta. É também por isso que mantenho a última resposta
l4m2 12/12
6

Perl 6 , 35 28 26 bytes

-2 bytes graças a nwellnhof

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

Experimente online!

Bloco de código anônimo que pega um número e retorna um número. Isso converte o número em uma string binária e conta os zeros iniciais. Funciona para números negativos porque o primeiro caractere é um -exemplo -00000101, portanto, não há zeros à esquerda.

Explicação:

{                        }  # 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
Brincadeira
fonte
6

JavaScript (Node.js) , 25 bytes

Recebe a entrada como um literal BigInt.

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

Experimente online!

0 0

Arnauld
fonte
Não faria n=>n<1?0:n.toString(2)-64o mesmo?
Ismael Miguel
@IsmaelMiguel Suponho que você quis dizer n=>n<1?0:n.toString(2).length-64, mas isso não funcionaria de qualquer maneira. Isso seria , eu acho.
Arnauld
1
@IsmaelMiguel Não se preocupe. :) É realmente possível ter a .toString()abordagem funcionando, mas ainda precisamos de um literal BigInt como entrada. Caso contrário, temos apenas 52 bits de mantissa, levando a resultados inválidos quando a precisão é perdida .
Arnauld
1
O fato de que o sufixo BigInt é o mesmo personagem como seu parâmetro é muito confuso ...
Neil
1
@ Neil Código ilegível no PPCG ?? Isso não pode ser! Fixo! : p
Arnauld
5

J , 18 bytes

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

Experimente online!

J , 19 bytes

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

Experimente online!

Explicação:

                #:  - convert 
                  ] - the input to
          (64$2)    - 64 binary digits
         =          - check if each digit equals 
        0           - zero
   [:*/\            - find the running product
1#.                 - sum
Galen Ivanov
fonte
1
1#.[:*/\1-_64{.#:(17) está próximo, mas não funciona para números negativos :(
Conor O'Brien
@Conor O'Brien Boa abordagem também!
Galen Ivanov
5

Perl 6 , 18 bytes

-2 bytes graças a Jo King

64-(*%2**64*2).msb

Experimente online!

Nwellnhof
fonte
4

05AB1E , 10 9 bytes

·bg65αsd*

E / S são números inteiros

Experimente online ou verifique todos os casos de teste .

Explicação:

·         # 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
fonte
4

Haskell , 56 bytes

Obrigado xnor por detectar um erro!

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

Pode alocar bastante memória, experimente online!

Talvez você queira testá-lo com uma constante menor: tente 8 bits!

Explicação

mapM(pure[0,1])[1..64]mapM(pure[1,0])[1..64]{0 0,1}641sum.fst.span(>0)

ბიმო
fonte
3

Powershell, 51 bytes

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

Script de teste:

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

Resultado:

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
confuso
fonte
3

Java 8, 38 bytes

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

Entrada como long(número inteiro de 64 bits), saída como int(número inteiro de 32 bits).

Porta da resposta C (gcc) de @44m2 .

Experimente online.

Explicação:

 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: Pode ter 26 bytes usando o built-Long::numberOfLeadingZeros in conforme exibido na resposta Java 8 do @lukeg .

Kevin Cruijssen
fonte
3

APL + WIN, 34 bytes

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

Explicação:

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

Geléia ,  10  9 bytes

-1 graças a um puro truque de Erik, o Outgolfer (agora não é negativo, agora é simplesmente )

ḤBL65_×AƑ

Um link monádico que aceita um número inteiro (dentro do intervalo) que gera um número inteiro.

Experimente online! Ou veja a suíte de testes .


O 10 foi ḤBL65_ɓ>-×

Aqui está outra solução de 10 bytes, que eu gosto, pois diz que é "BOSS" ...

BoṠS»-~%65

Conjunto de teste aqui

... BoṠS63r0¤i, BoṠS63ŻṚ¤iou BoṠS64ḶṚ¤itambém funcionaria.


Outro 10 byter (de Dennis) é æ»64ḶṚ¤Äċ0(novamente æ»63r0¤Äċ0e æ»63ŻṚ¤Äċ0também funcionará)

Jonathan Allan
fonte
9 bytes
Erik the Outgolfer
@EriktheOutgolfer Pensei comigo mesmo: "deve haver uma maneira mais golfista de se multiplicar por isNonNegative" e não pensei no trabalho Ƒrápido, muito bom!
Jonathan Allan
1
Na verdade, eu tenho teorizado sobre isso há algum tempo agora. Esteja avisado de que não se vetoriza! ;-) Na verdade, é "achatar e depois verificar se todos os elementos não são negativos".
Erik the Outgolfer
2

Perl 5 , 37 bytes

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

Experimente online!

Ou 46 bytes se a "stringification" não for permitida: sub z

sub{my$i=0;$_[0]>>64-$_?last:$i++for 1..64;$i}
Kjetil S.
fonte
s/length$&/$+[0]/(-3 bytes);)
Dada
Na IMO, você não tem permissão para remover a subpalavra-chave das respostas que contêm funções do Perl 5.
Nwellnhof
Eu já vi o que é semelhante à remoção subde respostas para outros idiomas, perl6, powershell e muito mais.
Kjetil S.
No Perl6, acho que você não precisa sub{}criar um sub (anônimo?), O que explica por que é omitido nas respostas do Perl6. Concordo com o @nwellnhof que você não deve remover sub. (quando eu ainda estava ativo, há mais ou menos um ano, essa era a regra) #
Dada
mudou agora. E incluído $+[0].
precisa
2

Swift (em uma plataforma de 64 bits), 41 bytes

Declara um fechamento chamado fque aceita e retorna um Int. Esta solução funciona apenas corretamente em plataformas de 64 bits, para onde Inté typealiaseditada Int64. (Em uma plataforma de 32 bits, Int64pode ser usado explicitamente para o tipo de parâmetro do fechamento, adicionando 2 bytes.)

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

No Swift, mesmo o tipo inteiro fundamental é um objeto comum declarado na biblioteca padrão. Isso significa que Intpode ter métodos e propriedades, como leadingZeroBitCount(que é necessário em todos os tipos em conformidade com o FixedWidthIntegerprotocolo da biblioteca padrão ).

NobodyNada - Restabelecer Monica
fonte
interessante. me lembra Rust. Eu acho que deve contar como 20 bytes, .leadingZeroBitCount
don bright
2

Haskell , 24 bytes

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

Experimente online!

Isso é basicamente o mesmo que a solução Java de Kevin Cruijssen, mas eu a achei de forma independente.

O argumento deve ter um tipo Intpara uma compilação de 64 bits ouInt64 para qualquer coisa.

Explicação

Se o argumento for negativo, o resultado será imediatamente 0. Caso contrário, mudamos para a esquerda, preenchendo um , até chegar a um número negativo. Esse preenchimento nos permite evitar um caso especial para 0.

Apenas para referência, aqui está a maneira óbvia / eficiente:

34 bytes

import Data.Bits
countLeadingZeros
dfeuer
fonte
1

Limpo , 103 bytes

Usa o mesmo "embutido" que a resposta do tetocat.

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

Experimente online!

Limpo , 58 bytes

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

Experimente online!

Furioso
fonte
1

Perl 5 -p , 42 bytes

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

Experimente online!

Mais do que uma solução baseada em bitstring, mas uma solução decente baseada em matemática.

Xcali
fonte
Realmente não funciona se não me engano
Dada
@ Dadá vejo que existem alguns casos em que a divisão de ponto flutuante não funciona muito bem. Fiz uma intligação que deveria resolver o problema.
Xcali
Desculpe, mas não consegui copiar o passado. Isto é o que eu queria enviar;) #
Dada
1

APL (NARS), 15 caracteres, 30 bytes

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

teste alguns números para ver como usar:

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

K (ngn / k) , 6 bytes

64-#2\

Experimente online!

2\ codificar o argumento em binário

# comprimento

64- subtrair de 64

ngn
fonte
# = length... parece baseado em cadeia de caracteres
Titus
2
@Titus 2\ fornece uma lista de números inteiros e #encontra seu comprimento. aqui não há cordas envolvidas.
NGN
1

PHP, 50 46 bytes

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

Execute como pipe -Rou experimente on-line ,

<?=$argn<0?0:0|64-log($argn+1,2);tem problemas de arredondamento; então eu segui o longo caminho.

Titus
fonte
1

Wolfram Language (Mathematica) , 41 bytes

A fórmula para números positivos é justa 63-Floor@Log2@#&. Regras de substituição são usadas para casos especiais de entrada zero e negativa.

A entrada não precisa ser um número inteiro assinado de 64 bits. Isso levará efetivamente o piso da entrada para transformá-la em um número inteiro. Se você inserir um número fora dos limites normais para um número inteiro de 64 bits, ele retornará um número negativo indicando quantos bits mais seriam necessários para armazenar esse número inteiro.

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

Experimente online!

A solução da @ LegionMammal978 é um pouco menor em 28 bytes. A entrada deve ser um número inteiro. De acordo com a documentação: " BitLength[n]é efetivamente uma versão eficiente de Floor[Log[2,n]]+1". Ele lida automaticamente com o caso de zero relatório correto em 0vez de-∞ .

Wolfram Language (Mathematica) , 28 bytes

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

Experimente online!

Kelly Lowder
fonte
1
Boole[#>=0](64-BitLength@#)&é um pouco menor em 28 bytes. Ele usa o mesmo conceito básico que o seu, mas aplica BitLengthe Boole.
usar o seguinte
Eu esqueci totalmente o BitLength!
Kelly Lowder
1

bitNumber - math.ceil (math.log (número) / math.log (2))

por exemplo, 64 bits NÚMERO: 9223372036854775807 math.ceil (math.log (9223372036854775807) / math.log (2)) ANS: 63

user90293
fonte
Se você pudesse adicionar o nome do idioma a isso, seria ótimo, pois é provável que as pessoas votem negativamente nas respostas que não têm o nome do idioma incluído
Jono 2906