Знайдіть другу нуль


10

Виклик

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

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

Якщо ви хочете, ви можете використовувати 1-індексацію, але нижче наведені тестові випадки використовуватимуть 0-індексацію.

Ви можете використовувати непідписані цілі числа, якщо хочете; якщо так, то ви повинні обробити цілі числа в діапазоні [0, 2^32). Якщо ви використовуєте підписані цілі числа, ви повинні обробити цілі числа в діапазоні [-2^31, 2^31). У тестових випадках тут будуть використані підписані цілі числа, але зауважте, що -x(підписаний) є 2^32 - x(непідписаний).

Випробування

0 (0b00) -> 1
1 (0b001) -> 2
10 (0b1010) -> 2
11 (0b01011) -> 4
12 (0b1100) -> 1
23 (0b010111) -> 5
-1 (0b11..11) -> Немає
-2 (0b11..10) -> Немає
-4 (0b11..00) -> 1
-5 (0b11..1011) -> Немає
-9 (0b11..10111) -> Немає
2 ^ 31-2 (0b0111..1110) -> 31

Оцінка балів

Це , тому найкоротша відповідь на кожній мові виграє!


Чи можемо ми замість цього використати непідписане ціле число?
Лина монашка

Так, ви можете, поки ви обробляєте цілі числа в діапазоні [0, 2^32).
musicman523

1
Чи беремо ми ціле число або рядок 0b...як вхідні дані?
TheLethalCoder

1
@JonathanAllan Я думаю, що ні, оскільки мене виправили у відповіді на "Джелі", 2^32-1тому що я не повинен був повертатися 33.
Ерік Аутгольфер

1
@JonathanAllan Erik відповідь правильна. Я оновив специфікацію виклику, щоб відобразити, що ви повинні обробляти 32-бітні цілі числа, чи не приймете ви їх як підписані чи без підписання
musicman523

Відповіді:


16

Python 2 , 45 байт

lambda n:[i for i in range(32)if n|1<<i>n][1]

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

Використовує 0-індексацію, непідписані числа та видаляє помилку без жодного другого нуля.

Просто створює список індексів не встановлених бітів, від найнижчого до найвищого, і повертає другий запис.


5
Ласкаво просимо до PPCG! Гарний перший пост!
Ерік Аутгольфер

Дякую! Я все ще по-новому в хитрість з гольфу в Python, тому радий, що цей код не вийшов з гольфу відразу.
Арнольд Палмер

Чудово :) а як з n = 2147483647?
mdahmoune

@mdahmoune 2 ** 31-1 має помилитися, оскільки його двійкове представлення у 32 бітах дорівнює 0b0111111111111111111111111111111, у якого немає секунди 0. Якщо я щось не пропускаю ...
Арнольд Палмер

6

JavaScript (ES6), 34 байти

Повертає індекс на основі 0 або -1якщо другий нуль не знайдений.

n=>31-Math.clz32((n=~n^~n&-~n)&-n)

Тестові справи

Черговий вираз

n=>31-Math.clz32((n=~n^++n&-n)&-n)

Рекурсивна версія, 42 байти

Повертає індекс на основі 0 або falseякщо другий нуль не знайдений.

f=(n,p=k=0)=>n&1||!k++?p<32&&f(n>>1,p+1):p

Як?

f=(n,p=k=0)=>                               // given n, p, k
             n&1||                          // if the least significant bit of n is set
                  !k++?                     // or this is the 1st zero (k was not set):
                       p<31&&               //   return false if p is >= 31
                             f(n>>1,p+1)    //   or do a recursive call with n>>1 / p+1
                                        :p  // else: return p

Тестові справи

Альтернативна версія, запропонована Нілом, 41 байт

Повертає індекс на основі 0 або видає занадто багато помилок рекурсії, якщо не знайдено другого нуля.

f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)

41-байт рекурсивна версія:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Ніл

5

Желе , 7 байт

|‘‘&~l2

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

Він виводить щось не в діапазоні [1,31], якщо немає другого нуля. Сюди входить 32 33і (-inf+nanj). Я думаю, це має певний сенс.

Це обчислює log(((x|(x+1))+1)&~x)/log(2).


1
-inf+nanjЯ не думав, що це може існувати
Луїс Мендо

Він не виводить (-inf+nanj)для входу, 2147483647який має двійкове представлення 31 1s, отже, немає жодного нуля в 32-бітовій підписаній нотації (саме тому він набагато коротший, ніж мій і відповіді Еріка).
Джонатан Аллан

На насправді, коли ж вона виробляє (-inf+nanj)?
Джонатан Аллан

... ага, я думаю, це вийшло, ви використовуєте підписаний варіант?
Джонатан Аллан

4

Java, ... 194 191 186 байт

static int f(int n){char[] c=Integer.toBinaryString(n).toCharArray();int j=0,o=2^32-2,i=c.length,l=i-1;if(n<0|n>o)return 0;for(;j<2&i>0;j+=c[--i]==48?1:0);if(j==2)return l-i;return 0;}

-159 байт для використання менших імен змінних та видалення пробілів
-25 байт, після взяття ще коротших змінних і завдяки @KevinCruijssen підказки
-18 байт, більше пробілів, ім'я функції
-3 байти, завдяки @KevinCruijssen, скорочення, якщо умова
-5 байт , Завдяки @Arnold Palmer, @KevinCruijssen, скорочуючи цикл

Безумовно

public static int getPosSecondZero2(int number){
    int overflow = 2^32-2;
    if(number < 0 || number > overflow){
        return 0;
    }    
    String binaryString = Integer.toBinaryString(number);   
    char[] binaryCharArray = binaryString.toCharArray();    
    int count = 0;
    int idx = binaryCharArray.length;
    int length = binaryCharArray.length -1;
    while(count < 2 && idx>0){
        idx--;
        if(binaryCharArray[idx] == '0'){
            count++;
        }   
    }
    if(count == 2)
        return length-idx;
    return 0;
}

Ласкаво просимо до PPCG! У гольф static можна досить багато речей: їх можна видалити; if(n<0||n>o){return 0;}може бути if(n<0|n>o)return 0;( |замість ||дужок і без них); bs, bsaі т.д. можуть бути єдиними символами (ніколи не використовуйте багатобайтові назви змінних / методів у коді-гольф); Ви можете комбінувати intз, як це: int o=2^32-2,c=0,i=x.length,l=i-1;. І є ще деякі речі для гольфу. Поради щодо гольфу на Яві та Поради щодо гольфу на всіх мовах можуть бути цікавими для читання. Ще раз ласкаво просимо і насолоджуйтесь своїм перебуванням! :)
Кевін Круїйсен

Я думаю, є ще кілька пробілів, які можна видалити у своїх змінних декларацій. Ласкаво просимо! :)
musicman523

@ musicman523 Спасибі, так це виправлено. 194 зараз :)
0x45

1
if(c[i]=='0'){j++;}ще можна пограти в гольф до if(c[i]==48)j++;-3 байт :) РЕДАКТУВАННЯ : Або ще краще: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}може бути for(;j<2&i>0;j+=c[i--]==48?1:0);на -8 байт.
Kevin Cruijssen

1
@ 0x45 Я вважаю, що якщо змінити код @ KevinCruijssen, for(;j<2&i>0;j+=c[--i]==48?1:0);він повинен працювати. Помилка пов’язана з iтим, що це довжина рядка, тому спочатку ви намагаєтеся проіндексувати межі масиву. Якщо ви робите попередній декремент (як показано в оновленому фрагменті), то при першому використанні він отримає доступ, c[c.length-1]як у вашому оригінальному коді.
Арнольд Палмер


3

Машинний код IA-32, 14 13 байт

Hexdump:

F7 D1 0F BC C1 0F B3 C1 0F BC C9 91 C3

Список розбирання:

0:  f7 d1                   not    ecx
2:  0f bc c1                bsf    eax,ecx
5:  0f b3 c1                btr    ecx,eax
8:  0f bc c1                bsf    ecx,ecx
b:  91                      xchg   eax, ecx
c:  c3                      ret

Отримує вхід в ecx; вихід у al. Повертає 0 за помилкою.

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

Якщо в інструкції з бітового сканування не знайдено жодного встановленого біту, документація Intel говорить, що вихід не визначений. Однак на практиці всі процесори залишають у цьому випадку регістр призначення незмінним (як зазначає Коді Грей, документація AMD описує цю поведінку як обов'язкову).

Отже, є такі випадки:

  1. Немає нульових бітів (двійкові 111 ... 1): ecx встановлюється на 0 by notі залишається 0
  2. Один нульовий біт: ecx встановлюється на 0, btrа після залишається 0bsf
  3. Два нульових біта: ecx встановлюється на відповідне значення на bsf

Лише документація Intel говорить, що бітові сканування на 0 не визначені. Документація AMD чітко підтверджує, що пункт призначення не змінюється. Якщо ви хочете уникнути такої поведінки, вам зазвичай слід додати префікс REP, щоб отримати або LZCNT, або TZCNT, але це збільшує кількість байтів, що, природно, небажано для гольфу з кодом.
Коді Грей

1
Ви насправді робите тут занадто багато роботи. Завдання не вимагає від вас розмежування між випадком, коли немає нульових бітів, і випадком, коли є лише 1 нульовий біт. Це дозволяє повернути 0 (або будь-яке негативне значення) в обох випадках. Отже, хоча 1-байт SALC+ DECє надзвичайно розумним, ви можете голити байт, просто використовуючи те, що є у ECXдругій BSFінструкції. Єдине, що потрібно - це 1-байт, XCHGщоб отримати результат, EAXщоб його можна було повернути. Іншими словами,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Коді Грей

1
Ось посилання "спробуйте в Інтернеті" для вищезазначеного . Оскільки ви використовуєте ECXв якості вхідного регістра, нам потрібно сказати GCC використовувати режим швидкого дзвінка.
Коді Грей

2

Діалог APL, 20 байт

{2⊃(⍳32)/⍨~⌽⍵⊤⍨32⍴2}

Використовує 1-індексацію, кидає INDEX ERRORу разі не другого нуля.

Як?

⍵⊤⍨- кодувати як

32⍴2 - двійковий рядок довжиною 32

- зворотний

~ - заперечення (0 → 1, 1 → 0)

(⍳32)/⍨ - стиснення з діапазоном 1-32 (залишаючи індекси нулів)

2⊃ - підберіть другий елемент


Ви можете зберегти багато байтів, використовуючи Where ( )
TwiNight

@TwiNight Я використовую dyalog 14
Uriel

TIO має Діялог 16, якщо вам потрібно
TwiNight

1

Желе , 13 байт

B¬Ṛ;1,1ḣ32TḊḢ

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

Використовує 1-індексацію, отримує непідписане ціле число як вхід. Повернення 0для не знайдено.


Це виводить 33на вхід 4294967295( 2^32-132-розрядний безпідписаний еквівалент -1)
musicman523

@ musicman523 Хм, щось пахне риб'ячим ...
Ерік Вихідник

1

Желе , 12 байт

,4BUFḣ32¬TḊḢ

Монадічне посилання, приймаючи ціле число, використовуючи опцію без підпису та повертаючи результат 1-індексування (повертає 0, коли такого немає).

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

або

32Ḷ2*|€n⁸TḊḢ

Спробуйте це

Як?

1.

,4BUFḣ32¬TḊḢ - Link: number, n   e.g. 14
,4           - pair with 4            [14,4]
  B          - to binary              [[1,1,1,0],[1,0,0]]
   U         - upend                  [[0,1,1,1],[0,0,1]]
    F        - flatten                [0,1,1,1,0,0,1]
     ḣ32     - head to 32             [0,1,1,1,0,0,1] (truncates the right if need be)
        ¬    - not (vectorises)       [1,0,0,0,1,1,0]
         T   - truthy indexes         [1,5,6]
          Ḋ  - dequeue                [5,6]
           Ḣ - head                   5
             -   if the dequeued list is empty the head yields 0

2.

32Ḷ2*|€n⁸TḊḢ - Link: number, n   e.g. 14
32Ḷ          - lowered range of 32    [ 0, 1, 2, 3, 4, 5, ...,31]
   2*        - 2 exponentiated        [ 1, 2, 4, 8,16,32, ...,2147483648]
     |€      - bitwise or for €ach    [15,14,14,14,30,46, ...,2147483662]
        ⁸    - chain's right argument 14
       n     - not equal?             [ 1, 0, 0, 0, 1, 1, ..., 1]
         T   - truthy indexes         [ 1, 5, 6, ..., 32]
          Ḋ  - dequeue                [ 5, 6, ..., 32]
           Ḣ - head                   5
             -   if the dequeued list is empty the head yields 0

1

машинний код x86_64, 34 32 байти

Не впевнений, що це правильний підхід, досить багато байтів (виявляється, це не так ):

31 c0 83 c9 ff 89 fa 83 e2 01 83 f2 01 01 d1 7f 09 ff c0 d1 ef eb ee 83 c8 ff 83 f8 1f 7f f8 c3

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

second_zero:
  # Set eax = 0
  xor  %eax, %eax
  # Set ecx = -1
  xor %ecx,%ecx
  not %ecx

  # Loop over all bits
Loop:
  # Get current bit
  mov %edi, %edx
  and $0x1, %edx
  # Check if it's zero and possibly increment ecx
  xor $0x1, %edx
  add %edx, %ecx
  # If ecx > 0: we found the position & return
  jg Return
  # Increment the position
  inc %eax
  # Shift the input and loop
  shr %edi
  jmp Loop

Fix:
  # If there's not two 0, set value to -1
  xor %eax,%eax
  not %eax

Return:
  # Nasty fix: if position > 31 (e.g for -1 == 0b11..11)
  cmp $31, %eax
  jg  Fix

  ret

Дякуємо @CodyGray за -2байти.


1
Прокручування всіх біт, мабуть, не є правильним підходом, як для кодового гольфу, так і для реального світу. Справжній прорив буде використовувати одну з команд , які дозволяють управляти всіма 32 (або 64) біт на один раз, як BSF, BSR, POPCNT, BTі т.д. Anatolyg було представлено рішення за цими напрямками . Я ще не визначив, чи можна це побити. :-p
Коді Грей

1
До речі, потенційно корисний трюк з гольф-кодом для встановлення регістра на -1 - це АБО це з -1. Наприклад, or ecx, -1. Це 3 байти, на 1 байт коротше XOR + NEG. Це не гарний трюк, коли не грати в гольф, оскільки він вводить помилкову залежність читання від реєстру пункту призначення, але там ви просто використаєте mov ecx, -1і витратите 5 байт.
Коді Грей

1

8-е , 149 байт

2 base swap >s nip decimal s:len 32 swap n:- ( "0" s:<+ ) swap times s:rev null s:/ a:new swap ( "0" s:= if a:push else drop then ) a:each swap 1 a:@

Коментований код

: f \ n -- a1 a2 n 

  \ decimal to binary conversion
  2 base swap >s nip decimal     

  \ 32bit formatting (padding with 0)            
  s:len 32 swap n:- ( "0" s:<+ ) swap times  

  \ put reversed binary number into an array 
  s:rev null s:/

  \ build a new array with position of each zero 
  a:new swap ( "0" s:= if a:push else drop then ) a:each

  \ put on TOS the position of the 2nd least least-significant zero digit
  swap 1 a:@
;

Використання та вихід

ok> : f 2 base swap >s nip decimal s:len 32 swap n:- ( "0" s:<+ ) swap times s:rev null s:/ a:new swap ( "0" s:= if a:push else drop then ) a:each swap 1 a:@ ;

ok> [0, 1, 10, 11, 12, 23, -1, -2, -4, -5, -9, 2147483646]

ok> ( dup . " -> " .  f . 2drop cr ) a:each
0 -> 1
1 -> 2
10 -> 2
11 -> 4
12 -> 1
23 -> 5
-1 -> null
-2 -> null
-4 -> 1
-5 -> null
-9 -> null
2147483646 -> 31

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