Trova il numero di zeri iniziali in un numero intero a 64 bit


18

Problema:

Trova il numero di zeri iniziali in un numero intero con segno a 64 bit

Regole:

  • L'input non può essere trattato come stringa; può essere qualsiasi cosa in cui operazioni matematiche e bit per bit guidano l'algoritmo
  • L'output deve essere convalidato rispetto alla rappresentazione intera con segno a 64 bit del numero, indipendentemente dalla lingua
  • Si applicano le regole di golf del codice predefinito
  • Vince il codice più breve in byte

Casi test:

Questi test presuppongono numeri interi con segno di complemento a due. Se la tua lingua / soluzione manca o utilizza una diversa rappresentazione di numeri interi con segno, chiamalo e fornisci ulteriori casi di test che potrebbero essere pertinenti. Ho incluso alcuni casi di test che affrontano la doppia precisione, ma non esitare a suggerire altri che dovrebbero essere elencati.

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

13
Benvenuti in PPCG! Qual è il motivo dietro "l'input non può essere trattato come una stringa" ? Questo squalifica tutte le lingue che non sono in grado di gestire numeri interi a 64 bit ed è improbabile che porti a più risposte che accettano un numero intero, poiché questo è il modo più semplice se disponibile comunque.
Arnauld,

1
Possiamo tornare Falseinvece di 0?
Jo King,

4
@Arnauld Ci sono già domande simili qui e su altri siti che richiedono specificamente soluzioni basate su stringhe, ma nulla che apre la domanda a operazioni matematiche e logiche. La mia speranza è di vedere un sacco di approcci diversi a questo problema che non hanno già ricevuto risposta altrove. Questo dovrebbe essere aperto anche alle soluzioni di stringa per essere tutto compreso?
Dave,

4
Diverse CPU tra cui x86 e ARM hanno istruzioni specifiche per questo (x86 ne ha effettivamente diverse). Mi sono sempre chiesto perché i linguaggi di programmazione non espongano questa funzione poiché nella maggior parte dei linguaggi di programmazione oggi non è possibile invocare le istruzioni di assemblaggio.
Slebetman,

1
@ user202729 Penso di averlo espresso male: "L'output deve essere convalidato rispetto alla rappresentazione intera con segno a 64 bit del numero, indipendentemente dalla lingua" Ciò che intendo è che questa domanda definisce il numero di zeri come il numero di zeri in un numero intero con segno a 64 bit. Immagino di aver fatto quel vincolo per eliminare gli interi con segno o senza segno.
Dave,

Risposte:


41

linguaggio macchina x86_64 su Linux, 6 byte

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

Richiede un processore Haswell o K10 o superiore con lzcnt istruzioni.

Provalo online!


20
Builtin colpisce ancora / e
Logern il

1
Consiglio di specificare la convenzione di chiamata utilizzata (anche se hai detto su Linux)
qwr

@qwr Sembra una convenzione di chiamata SysV perché il parametro viene passato in% rdi e viene restituito in% rax.
Logern,

24

Esagonia , 78 70 byte

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

Provalo online!

Questa sfida non è troppo banale per un linguaggio pratico? ;)

lunghezza laterale 6. Non riesco a inserirlo in un esagono di lunghezza laterale 5.

Spiegazione


3
Ho riso davvero tanto per la "spiegazione". : D
Eric Duminil,

1
Penso che potresti aver complicato la gestione dei numeri negativi / zero. Sono riuscito ad adattare un programma simile alla lunghezza laterale 5 non facendo quel calcolo pesante 2 ^ 64. Ovviamente non è ancora ben golfato!
FryAmTheEggman,

@fry Ah giusto, i numeri negativi hanno sempre 0 zeri iniziali ... il che porta sicuramente a un programma più breve perché genera 2 ^ 64 è lungo.
user202729

12

Python , 31 byte

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

Provalo online!

L'espressione è bit a bit &di due parti:

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

Il 67-len(bin(-n)) fornisce la risposta corretta per input non negativi. Prende la lunghezza in bit e sottrae da 67, che è 3 in più di 64 per compensare il -0bprefisso. La negazione è un trucco da regolare per l' n==0uso che negare non produce a- segno davanti.

La & ~n>>64rende la risposta invece sia 0per il negativo n. Quando n<0, è ~n>>64uguale a 0 (su numeri interi a 64 bit), quindi e -ing con esso dà 0. Quando n>=0, viene ~n>>64valutato-1 e il fare &-1non ha alcun effetto.


Python 2 , 36 byte

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

Provalo online!

Alternativa aritmetica.


9

Java 8, 32 26 byte.

Long::numberOfLeadingZeros

Builtins FTW.

-6 byte grazie a Kevin Cruijssen

Provalo online!


Ah, completamente dimenticato numberOfLeadingZeros.. Puoi giocare a golf a 28 byte a proposito:n->n.numberOfLeadingZeros(n)
Kevin Cruijssen,

2
In realtà, Long::numberOfLeadingZerosè ancora più breve (26 byte).
Kevin Cruijssen,

6
Wow, non succede molto spesso che Java batte Python. Congratulazioni!
Eric Duminil,

9

C (gcc) , 14 byte

__builtin_clzl

Funziona bene su Tio

C (gcc) , 35 29 byte

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

Provalo online!

Di Dennis per 6 byte

Flag del compilatore C (gcc) , 29 byte di David Foerster

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

Provalo online!


3
Vale la pena notare che è solo per macchine a 64 bit (o qualsiasi altra con LP64 / ILP64 / ecc. ABI)
Ruslan,

1
Accidenti, è ancora più breve di qualsiasi uso del GCC integrato__builtin_clzl con cui posso trovare .
David Foerster,

@Ruslan: buon punto, su sistemi con long32 bit (incluso Windows x64), è necessario __builtin_clzll(unsigned long long). godbolt.org/z/MACCKf . (A differenza di Intel intrinsics, i builtin GNU C sono supportati indipendentemente dal fatto che l'operazione sia eseguibile con un'istruzione di macchina. Su x86 a 32 bit, clzll si compila in un ramo o cmov per fare lzcnt(low half)+32o lzcnt(high half). O bsrse lzcntnon è disponibile.
Peter Cordes

I casi di test includono "0" ma __builtin_clz(l)(l)è un comportamento indefinito per zero: "Se x è 0, il risultato non è definito."
MCCCS,

1
@MCCCS Se funziona, conta. Questo è anche il motivo per cui mantengo l'ultima risposta
l4m2

6

Perl 6 , 35 28 26 byte

-2 byte grazie a nwellnhof

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

Provalo online!

Blocco di codice anonimo che accetta un numero e restituisce un numero. Questo converte il numero in una stringa binaria e conta gli zeri iniziali. Funziona con numeri negativi perché il primo carattere è a- ad es-00000101 , quindi non ci sono zeri iniziali.

Spiegazione:

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

6

JavaScript (Node.js) , 25 byte

Accetta input come un letterale BigInt.

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

Provalo online!

0


Non farebbe n=>n<1?0:n.toString(2)-64lo stesso?
Ismael Miguel,

@IsmaelMiguel Suppongo che volevi dire n=>n<1?0:n.toString(2).length-64, ma non funzionerebbe comunque. Questo sarebbe , penso.
Arnauld,

1
@IsmaelMiguel Nessun problema. :) È davvero possibile avere l' .toString()approccio funzionante, ma abbiamo ancora bisogno di un valore letterale BigInt come input. Altrimenti, abbiamo solo 52 bit di mantissa, che portano a risultati non validi quando si perde la precisione .
Arnauld,

1
Il fatto che il suffisso BigInt abbia lo stesso carattere del parametro è molto confuso ...
Neil,

1
@Neil Codice illeggibile su PPCG ?? Questo non può essere! Fisso! : p
Arnauld,


5

J , 18 byte

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

Provalo online!

J , 19 byte

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

Provalo online!

Spiegazione:

                #:  - convert 
                  ] - the input to
          (64$2)    - 64 binary digits
         =          - check if each digit equals 
        0           - zero
   [:*/\            - find the running product
1#.                 - sum

1
1#.[:*/\1-_64{.#:(17) è vicino ma non funziona con numeri negativi :(
Conor O'Brien il

@Conor O'Brien Anche l'approccio piacevole!
Galen Ivanov,



4

05AB1E , 10 9 byte

·bg65αsd*

Gli I / O sono entrambi numeri interi

Provalo online o verifica tutti i casi di test .

Spiegazione:

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

4

Haskell , 56 byte

Grazie xnor per aver individuato un errore!

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

Potrebbe allocare un bel po 'di memoria, provalo online!

Forse vuoi testarlo con una costante più piccola: prova a 8 bit!

Spiegazione

Invece di usare mapM(pure[0,1])[1..64]per convertire l'input in binario, useremo mapM(pure[1,0])[1..64]che essenzialmente genera le stringhe invertite{0,1}64in ordine lessicografico. Quindi possiamo solo riassumere il1prefisso s usando sum.fst.span(>0).


3

Powershell, 51 byte

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

Script di prova:

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

Produzione:

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

3

Java 8, 38 byte

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

Input come long(numero intero a 64 bit), output come int(numero intero a 32 bit).

Porta della risposta C (gcc) di @l4m2 .

Provalo online.

Spiegazione:

 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: può essere di 26 byte usando l' integratoLong::numberOfLeadingZeros come visualizzato nella risposta Java 8 di @lukeg .


3

APL+WIN, 34 bytes

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

Explanation:

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


3

Jelly,  10  9 bytes

-1 thanks to a neat trick by Erik the Outgolfer (is-non-negative is now simply )

ḤBL65_×AƑ

A monadic Link accepting an integer (within range) which yields an integer.

Try it online! Or see the test-suite.


The 10 was ḤBL65_ɓ>-×

Here is another 10 byte solution, which I like since it says it is "BOSS"...

BoṠS»-~%65

Test-suite here

...BoṠS63r0¤i, BoṠS63ŻṚ¤i, or BoṠS64ḶṚ¤i would also work.


Another 10 byter (from Dennis) is æ»64ḶṚ¤Äċ0 (again æ»63r0¤Äċ0 and æ»63ŻṚ¤Äċ0 will also work)



@EriktheOutgolfer I thought to myself "there must be a golfier way to multiply by isNonNegative" and didn't think of the Ƒ quick at all, very nice work!
Jonathan Allan

1
Actually, I've been theorizing about for quite some while now. Be warned that it doesn't vectorize! ;-) It's actually "flatten and then check if all elements are nonnegative".
Erik the Outgolfer

2

Perl 5, 37 bytes

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

Try it online!

Or this 46 bytes if the "stringification" is not allowed: sub z

sub{my$i=0;$_[0]>>64-$_?last:$i++for 1..64;$i}

s/length$&/$+[0]/ (-3 bytes) ;)
Dada

IMO, you're not allowed to remove the sub keyword from answers containing Perl 5 functions.
nwellnhof

I've seen whats similar to removing sub in answers for other languages, perl6, powershell and more.
Kjetil S.

In Perl6, I think you don't need sub{} to make a (anonymous?) sub, which explain why it's omitted from Perl6 answers. I agree with @nwellnhof that you shouldn't be allowed to remove sub. (when I was still active, like a year ago or so, that was the rule)
Dada

changed now. And included $+[0].
Kjetil S.

2

Swift (on a 64-bit platform), 41 bytes

Declares a closure called f which accepts and returns an Int. This solution only works correctly 64-bit platforms, where Int is typealiased to Int64. (On a 32-bit platform, Int64 can be used explicitly for the closure’s parameter type, adding 2 bytes.)

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

In Swift, even the fundamental integer type is an ordinary object declared in the standard library. This means Int can have methods and properties, such as leadingZeroBitCount (which is required on all types conforming to the standard library’s FixedWidthInteger protocol).


interesting. reminds me of Rust. i think it should count as 20 bytes, .leadingZeroBitCount
don bright

2

Haskell, 24 bytes

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

Try it online!

This is basically the same as Kevin Cruijssen's Java solution, but I found it independently.

The argument should have type Int for a 64-bit build, or Int64 for anything.

Explanation

If the argument is negative, the result is immediately 0. Otherwise, we shift left, filling in with ones, until we reach a negative number. That filling lets us avoid a special case for 0.

Just for reference, here's the obvious/efficient way:

34 bytes

import Data.Bits
countLeadingZeros

1

Clean, 103 bytes

Uses the same "builtin" as ceilingcat's answer.

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

Try it online!

Clean, 58 bytes

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

Try it online!



1

Perl 5 -p, 42 bytes

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

Try it online!

Longer than a bitstring based solution, but a decent math based solution.


Doesn't really work if I'm not mistaken
Dada

@Dada I see that there are a few cases where the floating point division doesn't quite work out properly. I put in an int call that should solve the issue.
Xcali

Sorry, I failed my copy-past it would seem. This is what I wanted to send ;)
Dada

1

APL(NARS), 15 chars, 30 bytes

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

test for few numbers for see how to use:

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


1

K (ngn/k), 6 bytes

64-#2\

Try it online!

2\ encode the argument in binary

# length

64- subtract from 64


# = length ... looks string based
Titus

2
@Titus 2\ gives a list of integers and # finds its length. no strings are involved here.
ngn

1

PHP, 50 46 bytes

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

Run as pipe with -R or try it online,

<?=$argn<0?0:0|64-log($argn+1,2); has rounding issues; so I took the long way.


1

Wolfram Language (Mathematica), 41 bytes

The formula for positive numbers is just 63-Floor@Log2@#&. Replacement rules are used for the special cases of zero and negative input.

The input need not be a 64-bit signed integer. This will effectively take the floor of the input to turn it into an integer. If you input a number outside of the normal bounds for a 64-bit integer, it will tell return a negative number indicating how many more bits would be needed to store this integer.

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

Try it online!

@LegionMammal978's solution is quite a bit shorter at 28 bytes. The input must be an integer. Per the documentation: "BitLength[n] is effectively an efficient version of Floor[Log[2,n]]+1. " It automatically handles the case of zero correctly reporting 0 rather than -∞.

Wolfram Language (Mathematica), 28 bytes

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

Try it online!


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


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
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.