Найти второй ноль

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

счет

Это , поэтому выигрывает самый короткий ответ на каждом языке!

musicman523
источник
Можем ли мы использовать целое число без знака?
Утренняя монахиня
Да, вы можете, пока вы будете обрабатывать целые числа в диапазоне [0, 2^32).
musicman523
1
Мы принимаем целое число или строку в 0b...качестве входных данных?
TheLethalCoder
1
@JonathanAllan Полагаю, нет, так как меня поправили в ответе на Jelly, 2^32-1потому что я не должен был возвращаться 33.
Эрик Аутгольфер
1
@JonathanAllan Эрик ответ правильный. Я обновил спецификацию задания, чтобы отразить, что вы должны обрабатывать 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 битах равно 0b01111111111111111111111111111111, у которого нет секунды 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)
Arnauld
источник
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).

jimmy23013
источник
1
-inf+nanjЯ не думал, что это вообще может существовать
Луис Мендо
Он не выводит (-inf+nanj)для входа, 2147483647который имеет двоичное представление 31 1 с, следовательно, нет второго нуля в 32-битной знаковой записи (вот почему он намного короче, чем мой и ответы Эрика).
Джонатан Аллан
На самом деле, когда же она производит (-inf+nanj)?
Джонатан Аллан
... ах я думаю сработало, вы используете подписанный вариант?
Джонатан Аллан
4

Ява, ... 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, укорочение цикла

Ungolfed

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;
}
0x45
источник
Добро пожаловать в PPCG! Есть много вещей, которые вы static можете играть в гольф: могут быть удалены; if(n<0||n>o){return 0;}можно if(n<0|n>o)return 0;( |вместо ||и без скобок); bs, bsaи т. д. могут быть одиночными символами (никогда не используйте многобайтовые имена переменных / методов в code-golf); Вы можете комбинировать intс, как это: int o=2^32-2,c=0,i=x.length,l=i-1;. И есть еще кое-что для гольфа. Советы по игре в гольф на Java и советы по игре в гольф на всех языках могут быть интересными для чтения. Снова добро пожаловать, и приятного пребывания! :)
Кевин Круйссен
Я думаю, что есть еще пара пробелов, которые вы можете удалить в объявлениях переменных. Добро пожаловать! :)
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 байт.
Кевин Круйссен,
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 notи остается 0
  2. Один нулевой бит: ecx устанавливается в 0 btrи остается 0 послеbsf
  3. Два нулевых бита: для ecx установлено правильное значение bsf
anatolyg
источник
Это только документация 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 использовать соглашение о вызовах fastcall.
Коди Грей,
2

Dyalog 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
Уриэль
У TIO есть Dyalog 16, если вам нужно
TwiNight
1

Желе , 13 байт

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

Попробуйте онлайн!

Использует 1-индексирование, получает в качестве входных данных целое число без знака. Возвращает 0для не найдено.

Эрик Outgolfer
источник
Это выводит 33на вход 4294967295( 2^32-132-битный беззнаковый эквивалент -1)
musicman523
@ musicman523 Хм, что-то пахнет подозрительно ...
Эрик Outgolfer
1

Желе , 12 байт

,4BUFḣ32¬TḊḢ

Монадическая ссылка, принимающая целое число, использующая опцию unsigned и возвращающая результат с 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
Усадьба Хаоса
источник
0

R , 66 байт

w=which.min
x=strtoi(intToBits(scan()));w(x[-w(x)])*any(!x[-w(x)])

читает со стандартного ввода; возвращает 0не второй ноль и место в противном случае.

Попробуйте онлайн!

Giuseppe
источник