Знайдіть кількість провідних нулів у 64-бітовому цілому


18

Проблема:

Знайдіть кількість провідних нулів у 64-бітовому цілому цілому

Правила:

  • Вхід не може трактуватися як рядок; це може бути все, де математичні та бітові операції керують алгоритмом
  • Вихід повинен бути підтверджений відповідно до 64-розрядного цілочисленного подання числа, незалежно від мови
  • Діють правила гольфу за кодом за умовчанням
  • Виграє найкоротший код у байтах

Тестові приклади:

Ці тести передбачають два підписані цілими числами доповнення. Якщо у вашій мові / рішенні бракує або використовується інше представлення підписаних цілих чисел, будь ласка, зателефонуйте до цього та надайте додаткові тестові випадки, які можуть бути актуальними. Я включив кілька тестових випадків, які стосуються подвійної точності, але, будь ласка, не соромтесь запропонувати будь-які інші, які слід перелічити.

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

14
Ласкаво просимо до PPCG! У чому причина "введення не можна трактувати як рядок" ? Це дискваліфікує всі мови, які не можуть обробити 64-бітні цілі числа, і навряд чи призведе до отримання більшої кількості відповідей, які приймають ціле число, оскільки це прямолінійний спосіб, коли він все одно доступний.
Арнольд

1
Чи можемо ми повернутися Falseзамість 0?
Джо Кінг

4
@Arnauld Тут вже є подібні запитання та на інших сайтах, які спеціально закликають до строкових рішень, але нічого, що відкриває питання до математики та логічних операцій. Я сподіваюсь побачити купу різних підходів до цієї проблеми, на які вже не відповіли ніде. Чи слід це відкривати і для строкових рішень, щоб бути всеохоплюючим?
Дейв

4
Кілька ЦП, включаючи x86 і ARM, мають для цього конкретні вказівки (насправді x86 є декілька). Мені завжди було цікаво, чому мови програмування не піддають цій функції, оскільки в більшості мов програмування сьогодні не можна посилатися на інструкції зі зборки.
slebetman

1
@ user202729 Думаю, що я дуже погано сформулював це: "Вихід повинен бути підтверджений проти 64-бітного підписаного цілого числа представлення числа, незалежно від мови". Я маю на увазі під тим, що це питання визначає кількість нулів як кількість нулів в 64-бітному цілому цілому. Я думаю, я створив це обмеження для усунення підписаних чи непідписаних цілих чисел.
Дейв

Відповіді:


41

x86_64 машинна мова на Linux, 6 байт

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

Потрібен процесор Haswell або K10 або вище з lzcntінструкцією.

Спробуйте в Інтернеті!


20
Бульдінс знову
страйкує

1
Рекомендую вказати використаний конвент для викликів (хоча ви це сказали на Linux)
qwr

@qwr Це схоже на умовний виклик SysV, оскільки параметр передається у% rdi і повертається у% rax.
Логерн

24

Шестикутник , 78 70 байт

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

Спробуйте в Інтернеті!

Хіба це не надто банальне значення для практичної мови? ;)

довжина сторони 6. Я не можу помістити його в бічну частину шестикутника.

Пояснення


3
Я дуже сміявся з "пояснення". : D
Ерік Дюмініл

1
Я думаю, у вас може виникнути надто складна робота з негативними цифрами / нулем. Мені вдалося помістити аналогічну програму в бічну довжину 5, не зробивши цього обтяжливого обчислення 2 ^ 64 Це, очевидно, ще не добре гольф!
FryAmTheEggman

@fry Ага, негативні числа завжди мають 0 нульових нульових значень ... що, безумовно, призводить до скорочення програми, оскільки генерування 2 ^ 64 є довгим.
user202729

12

Пітон , 31 байт

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

Спробуйте в Інтернеті!

Експрес - порозрядна &частина двох частин:

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

67-len(bin(-n))Дає правильну відповідь для невід'ємних входів. Він займає бітну довжину і віднімає від 67, що на 3 більше 64, щоб компенсувати -0bпрефікс. Заперечення - це хитрість налаштувати на n==0використання того, що заперечення не створює -знаку спереду.

Натомість відповідь & ~n>>64робить 0негативним n. Коли n<0, ~n>>64дорівнює 0 (для 64-бітових цілих чисел), так і-ій з ним дає 0. Коли n>=0, ~n>>64оцінюючи -1, і робити &-1це не має ефекту.


Python 2 , 36 байт

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

Спробуйте в Інтернеті!

Арифметична альтернатива.


9

Java 8, 32 26 байт.

Long::numberOfLeadingZeros

Вбудовані FTW.

-6 байт завдяки Кевіну Крейсейну

Спробуйте в Інтернеті!


Ах, зовсім забув про numberOfLeadingZeros.. Ви можете n->n.numberOfLeadingZeros(n)
пограти в

2
Насправді Long::numberOfLeadingZerosвона ще коротша (26 байт).
Кевін Круїссен

6
Нічого собі, не так часто трапляється, що Java перемагає Python. Вітаю!
Ерік Думініл

9

C (gcc) , 14 байт

__builtin_clzl

Відмінно працює на tio

C (gcc) , 35 29 байт

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

Спробуйте в Інтернеті!

Чим Денніс на 6 байт

Прапорці компілятора C (gcc) , 29 байт Девід Фоерстер

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

Спробуйте в Інтернеті!


3
Варто зауважити, що це лише для 64-розрядних машин (або будь-яких інших з LP64 / ILP64 / тощо. ABI)
Руслан

1
Боже, це навіть коротше, ніж будь-яке використання вбудованої GCC,__builtin_clzl з якою я можу підійти .
Девід Фоерстер

@Ruslan: хороший момент, у системах, де longє 32 біти (включаючи Windows x64), вам потрібно __builtin_clzll(без підписання довго). godbolt.org/z/MACCKf . (На відміну від інтелігентних технологій Intel, вбудовані GNU C підтримуються незалежно від операцій, які можна виконати однією машинною інструкцією. На 32-бітному x86 clzll компілюється у гілку чи cmov для виконання lzcnt(low half)+32або lzcnt(high half). bsrЯкщо lzcntнемає,
Peter Cordes

Тестові випадки включають "0", але __builtin_clz(l)(l)не визначене поведінка для нуля: "Якщо x дорівнює 0, результат не визначений."
MCCCS

1
@MCCCS Якщо це працює, він рахується. Ось чому я дотримуюся останньої відповіді
l4m2

6

Perl 6 , 35 28 26 байт

-2 байти завдяки nwellnhof

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

Спробуйте в Інтернеті!

Блок анонімного коду, який приймає номер і повертає номер. Це перетворює число у двійковий рядок і рахує провідні нулі. Він працює для від'ємних чисел, тому що перший символ є -наприклад -00000101, тому немає провідних нулів.

Пояснення:

{                        }  # 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 байт

Вводить дані як буквар BigInt.

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

Спробуйте в Інтернеті!

0


Не вдалося б n=>n<1?0:n.toString(2)-64виконати те саме?
Ісмаїл Мігель

@IsmaelMiguel Я гадаю, ти мав на увазі n=>n<1?0:n.toString(2).length-64, але це все одно не вийде. Це було б , я думаю.
Арнольд

1
@IsmaelMiguel Не хвилюйтесь. :) Дійсно, що .toString()підхід працює, але нам все ж потрібен BigInt літерал як вхід. В іншому випадку ми маємо лише 52 біти мантіси, що призводить до недійсних результатів при втраті точності .
Арнольд

1
Те, що суфікс BigInt є тим самим символом, що і ваш параметр, дуже заплутано ...
Ніл

1
@Neil Нечитабельний код на PPCG ?? Цього не може бути! Виправлено! : p
Арнольд


5

J , 18 байт

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

Спробуйте в Інтернеті!

J , 19 байт

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

Спробуйте в Інтернеті!

Пояснення:

                #:  - 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) близько, але не працює для від'ємних чисел :(
Conor O'Brien

@Conor O'Brien Приємний підхід теж!
Гален Іванов



4

05AB1E , 10 9 байт

·bg65αsd*

Введення / виведення - обидва цілих числа

Спробуйте в Інтернеті або перевірте всі тестові випадки .

Пояснення:

·         # 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 байт

Дякуємо xnor за виявлення помилки!

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

Ви можете виділити досить багато пам'яті, спробуйте в Інтернеті!

Можливо, ви хочете протестувати його з меншою константою: Спробуйте 8-бітну!

Пояснення

Замість використання mapM(pure[0,1])[1..64]для перетворення вхідних даних у двійкові, ми використовуватимемо, mapM(pure[1,0])[1..64]по суті, генеруючи перевернуті рядки{0,1}64у лексикографічному порядку. Тож ми можемо просто підсумувати1s-префікс за допомогою sum.fst.span(>0).


3

Powershell, 51 байт

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

Тестовий сценарій:

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

Вихід:

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 байт

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

Введіть як long(64-бітове ціле число), виведіть як int(32-бітове ціле число).

Порт відповіді C (gcc) @ l4m2 .

Спробуйте в Інтернеті.

Пояснення:

 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

РЕДАКТУВАННЯ: Можливо 26 байт , використовуючи вбудований файл,Long::numberOfLeadingZeros як показано у відповіді @lukeg Java 8 .


3

APL + WIN, 34 байти

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

Пояснення:

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

C # (Visual C # Interactive Compiler) , 42 байти

x=>x!=0?64-Convert.ToString(x,2).Length:64

Спробуйте в Інтернеті!

C # (Visual C # Interactive Compiler) , 31 байт

int c(long x)=>x<0?0:c(x-~x)+1;

Ще коротше, виходячи з відповіді на C (gcc) @ l4m2. Ніколи не знав, що ти можеш оголосити такі функції, дякую @Dana!

Спробуйте в Інтернеті!


1
Я думаю, це справедливо? tio.run / ## ZZA / ...
Dana

3

Желе ,  10  9 байт

-1 завдяки акуратному трюку Еріка Побіжника (є негативним зараз просто )

ḤBL65_×AƑ

Монадічна посилання, що приймає ціле число (в межах діапазону), яке дає ціле число.

Спробуйте в Інтернеті! Або дивіться тестовий набір .


10 було ḤBL65_ɓ>-×

Ось ще 10-байтне рішення, яке мені подобається, оскільки там написано, що це "BOSS" ...

BoṠS»-~%65

Тут набір тестів

... BoṠS63r0¤i, BoṠS63ŻṚ¤iабо BoṠS64ḶṚ¤iтакож працювали б.


Ще 10 байт (від Денніса) є æ»64ḶṚ¤Äċ0(знову æ»63r0¤Äċ0і æ»63ŻṚ¤Äċ0теж буде працювати)



@EriktheOutgolfer Я подумав собі, що "повинен бути гольфіст спосіб множення на isNonNegative", і не думав про Ƒшвидке зовсім, дуже приємна робота!
Джонатан Аллан

1
Насправді я теоретизую вже досить давно. Попереджуйте, що він не векторизується! ;-) Це насправді "сплюснути, а потім перевірити, чи всі елементи невід'ємні".
Ерік Аутгольфер

2

Perl 5 , 37 байт

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

Спробуйте в Інтернеті!

Або це 46 байт, якщо "строфікація" не дозволена: sub z

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

s/length$&/$+[0]/(-3 байти);)
Дада

IMO, вам заборонено видаляти subключове слово з відповідей, що містять функції Perl 5.
nwellnhof

Я бачив те, що схоже на видалення subвідповідей на інші мови, perl6, powerhell та багато іншого.
Kjetil S.

У Perl6, я думаю, вам не потрібно sub{}вносити (анонімний?) Підрозділ, який пояснює, чому це не було у відповідях Perl6. Я погоджуюся з @nwellnhof, що вам не можна дозволяти видаляти sub. (коли я був ще активним, як рік тому чи так, це було правило)
Dada

змінився зараз. І включені $+[0].
Kjetil S.

2

Swift (на 64-бітній платформі), 41 байт

Заявляє про закриття, fяке називається, яке приймає та повертає Int. Це рішення працює тільки правильно 64-розрядні платформи, де Intзнаходиться typealiasЕда Int64. (На 32-розрядної платформі Int64явно можна використовувати тип параметра закриття, додаючи 2 байти.)

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

У Swift навіть основний цілочисельний тип є звичайним об'єктом, оголошеним у стандартній бібліотеці. Це Intможе мати методи та властивості, такі як leadingZeroBitCount(що потрібно для всіх типів, що відповідають FixedWidthIntegerпротоколу стандартної бібліотеки ).


цікаво. нагадує мені про іржу. я думаю, що це має бути 20 байт, .leadingZeroBitCount
яскравий

2

Haskell , 24 байти

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

Спробуйте в Інтернеті!

Це в основному те саме, що рішення Java Kevin Cruijssen, але я знайшов його самостійно.

Аргумент повинен мати тип Intдля 64-бітної збірки абоInt64 для чого-небудь.

Пояснення

Якщо аргумент негативний, результат одразу дорівнює 0. У протилежному випадку ми зсуваємо вліво, заповнюючи їх , поки не досягнемо від’ємного числа. Ця заповнення дозволяє уникнути особливого випадку для 0.

Тільки для довідки, ось очевидний / ефективний спосіб:

34 байти

import Data.Bits
countLeadingZeros



1

Perl 5 -p , 42 байти

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

Спробуйте в Інтернеті!

Більш довге рішення, що базується на штрих, але пристойне рішення на основі математики.


Насправді не працює, якщо я не помиляюся
Dada

@Dada Я бачу, що є кілька випадків, коли поділ з плаваючою точкою не працює належним чином. Я звертаюся до intдзвінка, який повинен вирішити питання.
Xcali

Вибачте, я не вдався до свого копіювання минулого, здавалося б. Це те, що я хотів надіслати;)
Дада

1

APL (NARS), 15 символів, 30 байт

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

перевірити кілька номерів, щоб дізнатися, як користуватися:

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


1

K (ngn / k) , 6 байт

64-#2\

Спробуйте в Інтернеті!

2\ кодуйте аргумент у двійковій формі

# довжина

64- відняти від 64


# = length... виглядає на основі рядків
Тіт

2
@Titus 2\ дає список цілих чисел і #знаходить його довжину. тут не задіяно жодних струн.
ngn

1

PHP, 50 46 байт

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

Запустіть як трубу -Rабо спробуйте в Інтернеті ,

<?=$argn<0?0:0|64-log($argn+1,2);має питання округлення; тому я пройшов довгий шлях.


1

Мова Вольфрама (Mathematica) , 41 байт

Формула позитивних чисел просто 63-Floor@Log2@#& . Правила заміни застосовуються для особливих випадків нульового та негативного введення.

Вхід не повинен бути 64-бітовим цілим числом. Це фактично займе підлогу вводу, перетворивши його на ціле число. Якщо ви введете число за межами звичайних меж для 64-бітного цілого числа, воно покаже повернення від'ємного числа, вказуючи, скільки ще бітів знадобиться для зберігання цього цілого числа.

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

Спробуйте в Інтернеті!

@ Рішення LegionMammal978 досить коротше на 28 байт. Вхід повинен бути цілим числом. Згідно з документацією: " BitLength[n]фактично є ефективною версією" Floor[Log[2,n]]+1. Він автоматично обробляє випадки нульового правильного звітування, 0а не -∞.

Мова Вольфрама (Mathematica) , 28 байт

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

Спробуйте в Інтернеті!


1
Boole[#>=0](64-BitLength@#)&є хорошим трохи коротшим на 28 байт. Він використовує те саме базове поняття, що і ваше, але застосовується BitLengthі Boole.
LegionMammal978

Я повністю забув про BitLength!
Келлі Лоудер

1

bitNumber - math.ceil (math.log (кількість) / math.log (2))

наприклад 64-бітний номер: 9223372036854775807 math.ceil (math.log (9223372036854775807) / math.log (2)) ANS: 63


Якщо ви можете додати назву мови до цього, це було б чудово, оскільки люди, ймовірно, відмовляться від відповідей, які не містять мовної назви
Jono 2906,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.