Calculate the longest series of 1's in an integer's binary value

32

5

Goal

Given a non-negative integer, create a function that returns the starting position of number of largest consecutive 1's in that integer's binary value.

When given an input 0, return 0.

If the number has multiple streaks of equal length, you must return the position of the last streak.

Input

An integer greater than or equal to 0.

Output

An integer calculated as explained below.

Rules

  • This is code-golf, so the shortest code in bytes in each language wins.
  • Standard loopholes are forbidden.

Examples and Test Cases

Example 1

  • Your function is passed the integer 142
  • 142 is equal to 10001110 in binary
  • Longest streak is "111" (a streak of three ones)
  • The streak starts at the 2^1 position
  • Your function returns 1 as the result

Example 2

  • Your function is passed the integer 48
  • 48 is equal to 110000 in binary
  • Longest streak is "11" (a streak of two ones)
  • The streak starts at the 2^4 position
  • Your function returns 4 as the result

Example 3

  • Your function is passed the integer 750
  • 750 is equal to 1011101110 in binary
  • Longest streak is "111" (a streak of three ones)
  • Since there are two streaks of equal length, we return the later streak.
  • The later streak starts at the 2^5 position
  • Your function returns 5 as the result

Defacto

Posted 2017-09-16T19:47:44.550

Reputation: 545

1You need a winning criterion, like [tag:code-golf] – Okx – 2017-09-16T19:51:06.197

@Okx It had been mentioned in the body itself so I added the tag. – totallyhuman – 2017-09-16T20:04:09.243

Make sure people test 0. That's an important test case. – mbomb007 – 2017-09-16T23:39:47.327

2Instead of "last streak" or "latest streak", I'd suggest "streak with the largest place value". – aschepler – 2017-09-16T23:50:55.817

@Okx Why is a winning criterion necessary? Why can't it simply be a puzzle? – corsiKa – 2017-09-18T18:46:59.350

@corsiKa Because those are the rules on PPCG. – Okx – 2017-09-18T18:51:40.397

@Okx Interesting - apparently "puzzle" is specifically defined as "I have this code that you must change to win the puzzle" - an arbitrary definition that has apparently confused more than just myself in the past. Thank you for the accurate, if terse, response. – corsiKa – 2017-09-18T19:30:46.157

Congratulations to Dennis! A solution of only 8 bytes, written in Jelly. https://codegolf.stackexchange.com/a/143030/67327

– Defacto – 2017-09-18T21:41:35.557

Answers

21

Jelly, 10 8 bytes

Ba\ÐƤṀċ¬

Try it online!

How it works

Ba\ÐƤṀċ¬  Main link. Argument: n


B         Binary; convert n to base 2.

   ÐƤ     Apply the link to the left to all postfixes of the binary array.
 a\         Cumulatively reduce by logical AND.

          For example, the array

          [1, 0, 1, 1, 1, 0, 1, 1, 1, 0]

          becomes the following array of arrays.

          [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
             [0, 0, 0, 0, 0, 0, 0, 0, 0]
                [1, 1, 1, 0, 0, 0, 0, 0]
                   [1, 1, 0, 0, 0, 0, 0]
                      [1, 0, 0, 0, 0, 0]
                         [0, 0, 0, 0, 0]
                            [1, 1, 1, 0]
                               [1, 1, 0]
                                  [1, 0]
                                     [0]

     Ṁ    Take the lexicographical maximum, i.e., the array with the most 1's at
          the beginning, breaking ties by length.

       ¬  Yield the logical NOT of n, i.e., 0 if n > 0 and 1 if n = 0.

      ċ   Count the occurrences of the result to the right in the one to the left.

Dennis

Posted 2017-09-16T19:47:44.550

Reputation: 196 637

Congratulations! – Defacto – 2017-09-18T21:35:53.710

24

JavaScript (ES6), 41 40 36 34 bytes

Saved 4 bytes thanks to @ThePirateBay

f=x=>(k=x&x/2)?f(k):Math.log2(x)|0

Test cases

f=x=>(k=x&x/2)?f(k):Math.log2(x)|0

console.log(f(0))
console.log(f(142))
console.log(f(48))
console.log(f(750))

How?

General case x > 0

We recursively AND the input x with x / 2 which progressively reduces the patterns of consecutive set bits until only the rightmost bit of the sequence remains. We keep a copy of the last non-zero value and determine the position of its most significant bit by floor-rounding its base-2 logarithm.

Below are the steps we go through for x = 750 (1011101110 in binary).

    1011101110 --.
,----------------'
'-> 1011101110
AND 0101110111
    ----------
=   0001100110 --.
,----------------'
'-> 0001100110
AND 0000110011
    ----------
=   0000100010 --.  --> output = position of MSB = 5  (0000100010)
,----------------'                                         ^
'-> 0000100010
AND 0000010001
    ----------
=   0000000000

Edge case x = 0

The special case x = 0 immediately leads to Math.log2(0) | 0. The logarithm of 0 evaluates to -Infinity and the binary bitwise OR forces a coercion to a 32-bit integer. In compliance with the specification of the abstract operation ToInt32, this gives the expected 0:

If number is NaN, +0, −0, +∞, or −∞, return +0

Arnauld

Posted 2017-09-16T19:47:44.550

Reputation: 111 334

This errors for the input 0, which is part of the input range. – Justin Mariner – 2017-09-16T20:49:59.247

@JustinMariner Fixed. – Arnauld – 2017-09-16T21:01:35.890

What about Math.log2(k)|0 instead of 31-Math.clz32(k)? Or am I missing something? – None – 2017-09-16T22:56:19.893

@ThePirateBay Math.log2(k)|0 is actually both shorter and simpler for the special case x=0. Thanks. :) – Arnauld – 2017-09-16T23:06:56.233

1

Very nice algorithm, and good explanation. I implemented it in 14 bytes of x86 machine code.

– Peter Cordes – 2017-09-17T02:58:03.203

12

x86 machine code, 14 bytes

Using @Arnauld's algorithm of x &= x>>1 and taking the highest set bit position in the step before x becomes 0.

Callable from C/C++ with signature unsigned longest_set(unsigned edi); in the x86-64 System V ABI. The same machine-code bytes will decode the same way in 32-bit mode, but the standard 32-bit calling conventions don't put the first arg in edi. (Changing the input register to ecx or edx for Windows _fastcall / _vectorcall or gcc -mregparm could be done without breaking anything.)

   address   machine-code
             bytes
                         global longest_set
 1                       longest_set:
 2 00000000 31C0             xor  eax, eax    ; 0 for input = 0
 3                       
 4                       .loop:               ; do{
 5 00000002 0FBDC7           bsr  eax, edi    ;  eax = position of highest set bit
 6                           ;; bsr leaves output unmodified when input = 0 (and sets ZF)
 7                           ;; AMD documents this; Intel manuals say unspecified but Intel CPUs implement it
 8 00000005 89F9             mov  ecx, edi
 9 00000007 D1E9             shr  ecx, 1
10 00000009 21CF             and  edi, ecx
11 0000000B 75F5             jnz .loop        ; } while (x &= x>>1);
12                       
13 0000000D C3               ret

x86's BSR instruction (Bit Scan Reverse) is perfect for this, giving us the bit-index directly, rather than counting leading zeros. (bsr doesn't directly produce 0 for input=0 like 32-lzcnt(x) would, but we need bsr=31-lzcnt for non-zero inputs, so lzcnt wouldn't even save instructions, let alone byte count. Zeroing eax before the loop works because of bsr's semi-official behaviour of leaving the destination unmodified when the input is zero.)

This would be even shorter if we could return the MSB position of the longest run. In that case, lea ecx, [rdi+rdi] (3 bytes) would copy + left-shift instead of mov + shr (4 bytes).

See this TIO link for an asm caller that does exit(longest_set(argc-1));

Testing with a shell loop:

l=(); for ((i=0;i<1025;i++));do 
    ./longest-set-bitrun "${l[@]}";   # number of args = $i
    printf "$i %#x: $?\n" $i; 
    l+=($i); 
done | m

0 0: 0
1 0x1: 0
2 0x2: 1
3 0x3: 0
4 0x4: 2
5 0x5: 2
6 0x6: 1
7 0x7: 0
8 0x8: 3
9 0x9: 3
10 0xa: 3
11 0xb: 0
12 0xc: 2
13 0xd: 2
14 0xe: 1
15 0xf: 0
16 0x10: 4
17 0x11: 4
18 0x12: 4
19 0x13: 0
20 0x14: 4
21 0x15: 4

...

747 0x2eb: 5
748 0x2ec: 5
749 0x2ed: 5
750 0x2ee: 5
751 0x2ef: 0
752 0x2f0: 4
753 0x2f1: 4
754 0x2f2: 4

Peter Cordes

Posted 2017-09-16T19:47:44.550

Reputation: 2 810

1Nice! A note to those who (like me) are more familiar with other assembly dialects: the x86 BSR mnemonic stands for "Bit Scan Reverse", not "Branch to SubRoutine". – Arnauld – 2017-09-17T10:26:06.883

@Arnauld: good point, edited to decode the mnemonic as well as having a link to the insn reference manual entry. – Peter Cordes – 2017-09-17T10:28:40.877

5

Jelly, 19 17 11 bytes

HÐĿ&\ḟ0ṪBL’

Try it online!

-6 (!) bytes thanks to @Dennis's keen observations

How it Works

HÐĿ&\ḟ0ṪBL’
HÐĿ         - halve repeatedly until reaching 0 due to rounding
   &\       - cumulative AND
     ḟ0Ṫ    - final non-zero, or 0 if all elements are 0
        BL  - length of binary representation (log base 2). 0->[0]->1
          ’ - decrement

fireflame241

Posted 2017-09-16T19:47:44.550

Reputation: 7 021

Errors for 0, which is in the input range. – Mr. Xcoder – 2017-09-16T21:00:02.047

@Mr.Xcoder Fixed – fireflame241 – 2017-09-16T21:00:19.870

You can save a byte for the fix with ȯ-µ... – Jonathan Allan – 2017-09-16T21:28:55.973

@JonathanAllan I don't understand how OR-ing would help. Do you have code? – fireflame241 – 2017-09-16T21:33:47.830

Looks like you saved more with ×Ṡ anyway. It was OR-ing the input with -1, so all input remained the same except 0 which became -1, for which your method yields 0. code

– Jonathan Allan – 2017-09-16T21:36:26.643

1Since B always returns an array that begins with a 1, BUṪMṪ’×Ṡ can become ṪBL’. Also, you don't need the , and ḟ0 saves one byte over ¹Ðf. – Dennis – 2017-09-17T07:01:22.200

5

Python 2, 45 bytes

f=lambda x:f(x&x/2)if x&x/2else len(bin(x))-3

Try it online!

Saved plenty of bytes thanks to Dennis! (The heads up for len(bin(...))-3 instead of math.frexp)

Thanks to @xnor for finding a bug, which fortunately was easily fixable!

Mr. Xcoder

Posted 2017-09-16T19:47:44.550

Reputation: 39 774

This seems to give wrong answers such as for x=3, I think because the and/or short-circuits wrong when the function returns 0. – xnor – 2017-09-18T09:49:02.117

@xnor Thanks for noticing that! It's fixed. – Mr. Xcoder – 2017-09-18T12:46:36.220

4

Perl 6, 45 35 bytes

This highly improved version is courtesy of @nwellnhof.

{.msb+1-(.base(2)~~m:g/1+/).max.to}

Try it online!

Ramillies

Posted 2017-09-16T19:47:44.550

Reputation: 1 923

You can simply match with :g to get all matches. With the smart-match operator, I could golf it down to 40 bytes: {sort(.base(2).flip~~m:g/1+/).tail.from}

– nwellnhof – 2017-09-16T22:20:29.983

And to 35 bytes: {.msb+1-(.base(2)~~m:g/1+/).max.to}

– nwellnhof – 2017-09-16T22:24:33.400

@nwellnhof, thank you very much. I somehow missed the :g and didn't figure out how I can use adverb with the smartmatch operator. Also the .msb method is quite helpful here and I didn't know about it before. – Ramillies – 2017-09-17T16:18:34.880

3

Python 2, 89 78 bytes

m=t=i=j=0
for c in bin(input()):
 t=-~t*(c>'0');i+=1
 if t>m:j=i;m=t
print i-j

Try it online!

EDIT: Saved 11 bytes thanks to Mr. Xcoder.

Chas Brown

Posted 2017-09-16T19:47:44.550

Reputation: 8 959

86 bytes – Mr. Xcoder – 2017-09-16T20:40:34.750

78 bytes – Mr. Xcoder – 2017-09-16T20:48:30.960

@Mr.Xcoder I also thought of that, though the question specifically asks to write a function. – Jonathan Frech – 2017-09-16T20:50:20.117

@JonathanFrech I don't think the OP really meant function. Probably just a generic term. – Mr. Xcoder – 2017-09-16T20:51:35.683

@Mr.Xcoder Please explain this. Thanks, – lifebalance – 2017-09-17T05:41:01.217

@lifebalance (t+1) can be replaced by -~t, which is a bitwise operation that performs the exact same task. ~number = - number - 1, - is negation, hence -~t = - (- t - 1) = t + 1. This has the advantage of not requiring parenthesis. Then, c=='1' can be replaced by c>'0', because 1 has a higher ASCII code point, and thus can be compared using >. – Mr. Xcoder – 2017-09-17T06:13:20.233

For 926 (0b1110011110), this should return 1, but it returns 7. What gives? – lifebalance – 2017-09-17T08:29:06.643

@Mr.Xcoder As @lifebalance found out, you cannot use c>'0' instead of c=='1', as the bin(...) function adds a 0b in front to the binary string. Because 'b'>'0', though 'b'!='1', this method returns the wrong index for inputs like 926. – Jonathan Frech – 2017-09-17T19:35:34.150

@lifebalance The leading b in 0b1110011110 is falsely interpreted as a 1. – Jonathan Frech – 2017-09-17T19:37:59.300

If my edits are accepted using format(), we can avoid the 0b altogether. – lifebalance – 2017-09-17T21:50:39.307

@lifebalance I think it would be better for you to comment your golfed version instead of suggesting an edit. – Jonathan Frech – 2017-09-18T00:15:33.037

3

05AB1E, 14 12 11 bytes

bDγàŠrkrJgα

Try it online! or run test cases.

Explanation

bDγàŠrkrJgα  Implicit input (ex: 750)
bD           Convert input to binary string and duplicate
                 '1011101110', '1011101110'
  γ          Split into groups of 1s or 0s
                 '1011101110', ['1', '0', '111', '0', '111', '0']
   à         Pull out max, parsing each as an integer
                 '1011101110', ['1', '0', '0', '111', '0'], '111'
    Šrk      Rearrange stack and get first index of max run of ones
                 ['1', '0', '0', '111', '0'], 2
       rJg   Reverse stack, join the array to a string, and get its length
                 2, 7
          α  Get absolute difference
                 5

Justin Mariner

Posted 2017-09-16T19:47:44.550

Reputation: 4 746

3

J, 18 17 bytes

(#-0{#\\:#.~\)@#:

Try it online!

Explanation

(#-0{#\\:#.~\)@#:  Input: integer n
               #:  Binary
     #\            Length of each prefix
       \:          Sorted down using
         #.~\      Mixed base conversion on each prefix
   0{              Get the value at index 0
  -                Subtract from
 #                 Length

miles

Posted 2017-09-16T19:47:44.550

Reputation: 15 654

Very slick. Not sure I fully understand what's going on with the mixed base conversion though. Why does it count the number of consecutive ones at the end of the string? Also, if the bases being specified on the x of the dyad are all 0 and 1, what does that mean? A base 2 number has digits 0 and 1, so a base 1 number has digits... 0? then what does a 1 mean in that context? And is a base 0 number just always 0? – Jonah – 2017-09-16T23:16:49.293

@Jonah It's more due to how mixed base conversion is implemented. x #. y first computes w =: */\. }. x , 1 then returns +/ w * y – miles – 2017-09-16T23:31:47.803

so would you consider this a golf hack rather than a legitimate use of #., since you are relying on internal implementation details rather than the public api? – Jonah – 2017-09-17T04:21:32.070

3

C# (.NET Core), 64 60 bytes

T=a=>(a&a/2)>0?T(a&a/2):Math.Log(a,2)<0?0:(int)Math.Log(a,2)

Try it online!

A C# version of @Arnauld's answer

Acknowledgements

4 bytes saved thanks to Kevin Cruijssen.

C# (.NET Core), 131 123+18=141 bytes

a=>{string s=Convert.ToString(a,2),t=s.Split('0').OrderBy(x=>x.Length).Last();return a<1?0:s.Length-s.IndexOf(t)-t.Length;}

Try it online!

+18 bytes for using System.Linq;

Acknowledgements

8 bytes saved thanks to Grzegorz Puławski.

Degolfed

a=>{
    string s=Convert.ToString(a,2),      // Convert to binary
    t=s.Split('0')                       // get largest group of 1's
       .OrderBy(x=>x.Length)
       .Last();
    return 
        a<1?0:                          // handle 0 case
        s.Length-s.IndexOf(t)-t.Length; // get position in reversed string
}

C# (.NET Core), 164 161 bytes

a=>{var s=Convert.ToString(a,2);int c=0,l=0,p=0,k=0,j=s.Length-1,i=j;for(;i>=0;i--){if(s[i]>'0'){if(i==j||s[i+1]<'1'){p=i;c=0;}if(++c>=l){l=c;k=p;}}}return j-k;}

Try it online!

A non-Linq solution, which I'm sure could be improved, though nothing is immediately apparent.

Degolfed

a=>{
    var s=Convert.ToString(a,2); // Convert to binary
    int c=0,l=0,p=0,k=0,j=s.Length-1,i=j;
    for(;i>=0;i--)               // Loop from end of string
    {
        if(s[i]>'0')             // if '1'
        {
            if(i==j||s[i+1]<'1') // if first digit or previous digit was '0'
            {
                p=i;             // set the position of the current group
                c=0;             // reset the count
            }
            if(++c>=l)           // if count is equal or greater than current largest count
            {
                l=c;             // update largest count
                k=p;             // store position for this group
            }
        }
    }
    return j-k;                  // as the string is reversed, return string length minus position of largest group
}

Ayb4btu

Posted 2017-09-16T19:47:44.550

Reputation: 541

You can save two bytes in your port of Arnauld's like this: T=a=>{int x=(int)Math.Log(a,2);return(a&=a/2)>0?T(a):x<0?0:x;} – Kevin Cruijssen – 2017-09-19T07:10:26.963

1Or even two more bytes saved (60 bytes): T=a=>(a&a/2)>0?T(a&a/2):Math.Log(a,2)<0?0:(int)Math.Log(a,2) – Kevin Cruijssen – 2017-09-19T07:18:40.103

2

Jelly, 19 bytes

BŒgḄṀB
BwÇɓÇL+ɓBL_‘

Try it online!

Thanks to Jonathan Allan for saving  4  6 bytes!

I've worked too much to just abandon this, although it is kind of long. I really wanted to add a solution that literally searches for the longest substring of 1s in the binary representation...

Explanation

BŒgḄṀB  - Monadic helper link. Will be used with Ç in the next link.

B       - Binary representation.
 Œg     - Group runs of consecutive equal elements.
   Ḅ    - Convert from binary to integer.
    Ṁ   - Maximum value.
     B  - Convert from integer to binary.


BwÇɓÇL+ɓBL_‘  - Main link.

B             - Binary representation (of the input).
  Ç           - Last link as a monad. Takes the input integer.
 w            - First sublist index.
   ɓ          - Start a separate dyadic chain. Reverses the arguments.
    Ç         - Last link as a monad.
     L        - Length.
      +       - Addition
       ɓ      - Start a separate dyadic chain. Reverses the arguments.
        B     - Binary.
         L    - Length.
          _‘  - Subtract and increment the result (because Jelly uses 1-indexing).
              - Implicitly output.

Mr. Xcoder

Posted 2017-09-16T19:47:44.550

Reputation: 39 774

Your helper link could be BŒgḄṀB instead – Jonathan Allan – 2017-09-16T21:45:09.367

@JonathanAllan Oh wow thanks! – Mr. Xcoder – 2017-09-16T21:45:52.903

Your main link could be BwÇɓÇL+ɓBL_‘ – Jonathan Allan – 2017-09-16T22:01:41.050

@JonathanAllan Wow, thanks again! – Mr. Xcoder – 2017-09-17T06:04:45.507

2

Haskell, 101 98 96 75 bytes

snd.maximum.(`zip`[0..]).c
c 0=[0]
c n|r<-c$div n 2=sum[r!!0+1|mod n 2>0]:r

Try it online! Usage: snd.maximum.(`zip`[0..]).c $ 142 yields 1.

Explanation:

  • c converts the input into binary while at the same time counting the length of streaks of one, collecting the results in a list. r<-c$div n 2 recursively computes the rest r of this list, while sum[r!!0+1|mod n 2>0]:r adds the current length of the streak to r. The list comprehension checks if mod n 2>0, that is whether the current binary digit is a one, and if so, takes the length of the previous streak (the first element of r) and adds one. Otherwise the list comprehension is empty, and sum[] yields 0. For the example input, c 142 yields the list [0,3,2,1,0,0,0,1,0].

  • (`zip`[0..]) adds the position to each element of the previous list as the second component of a tuple. For the example this gives [(0,0),(3,1),(2,2),(1,3),(0,4),(0,5),(0,6),(1,7),(0,8)].

  • maximum finds the lexicographically maximal tuple in this list, that is the streak lengths are considered first as they are the first component, and in the event of a tie the second component, namely the larger index, decides. This yields (3,1) in the example, and snd returns the second component of the tuple.

Laikoni

Posted 2017-09-16T19:47:44.550

Reputation: 23 676

2

Jelly,  14 13 12  11 bytes

Bµṣ0Ṫ$ƤMḢạL

A monadic link taking and returning non-negative integers.

Try it online! or see the test-suite.

How?

Bµṣ0Ṫ$ƤMḢạL - Main link: number, n                   e.g. 750
B           - convert to a binary list                    [1,0,1,1,1,0,1,1,1,0]
 µ          - monadic chain separation, call that b
      Ƥ     - map over prefixes:  (i.e. for [1], [1,0], [1,0,1], [1,0,1,1],...)
     $      -   last two links as a monad:                e.g.: [1,0,1,1,1,0,1,1]
   0        -     literal zero                                   0
  ṣ         -     split (prefix) at occurrences of (0)           [[1],[1,1,1],[1,1]]
    Ṫ       -     tail                                                        [1,1]
       M    - maximal indices                             [5,9]
        Ḣ   - head                                        5
          L - length (of b)                               10
         ạ  - absolute difference                         5

Jonathan Allan

Posted 2017-09-16T19:47:44.550

Reputation: 67 804

I had a similar solution but used ŒrṪP on the prefixes instead. – miles – 2017-09-16T22:34:37.020

2

Husk, 12 bytes

→S§-€¤≠Lo▲gḋ

Try it online!

Explanation

                 Implicit input, e.g                           750
           ḋ     Convert to binary                             [1,0,1,1,1,0,1,1,1,0]
          g      Group equal elements                          [[1],[0],[1,1,1],[0],[1,1,1],[0]]
        o▲       Maximum                                       [1,1,1]
    €            Index of that substring in the binary number  3
     ¤≠L         Absolute difference of lengths                abs (3 - 10) = 7
 S§-             Subtract the two                              7 - 3 = 4
→                Increment                                     5

H.PWiz

Posted 2017-09-16T19:47:44.550

Reputation: 10 962

2

Python 2 or 3, 58 bytes

import math
f=lambda x:x&x>>1and f(x&x>>1)or len(bin(x))-3

Try it online!

lifebalance

Posted 2017-09-16T19:47:44.550

Reputation: 131

2

Kotlin, 77 bytes

{val b=it.toString(2)
b.reversed().lastIndexOf(b.split(Regex("0+")).max()!!)}

Beautified

{
    val b = it.toString(2)
    // Find the left position of the first instance of
    b.reversed().lastIndexOf(
            // The largest group of 1s
            b.split(Regex("0+")).max()!!)
}

Test

var s:(Int)->Int =
{val b=it.toString(2)
b.reversed().lastIndexOf(b.split(Regex("0+")).max()!!)}
fun main(args: Array<String>) {
    r(0, 0)
    r(142, 1)
    r(48, 4)
    r(750, 5)
}

fun r(i: Int, i1: Int) {
    var v = s(i)
    println("$i -> $v [$i1] ${i1 == v}")
}

jrtapsell

Posted 2017-09-16T19:47:44.550

Reputation: 915

I did not test but think this works in scala too. – V. Courtois – 2017-09-18T12:20:44.117

2

C (gcc), 81 80 bytes

i,l,c,r;f(n){for(i=l=c=r=0;n;n/=2,i++)c=n&1?c+1:c>=l?r=i-(l=c),0:0;n=c<l?r:i-c;}

Try it online!

C (gcc), 43 bytes

A C version of @Arnauld's answer

k;f(n){n=(k=n&n/2)?f(k):(k=log2(n))<0?0:k;}

Try it online!

cleblanc

Posted 2017-09-16T19:47:44.550

Reputation: 3 360

Miss the return n; or return k; statement – RosLuP – 2017-12-19T15:43:47.447

Suggest n<1?0:log2(n) instead of (k=log2(n))<0?0:k – ceilingcat – 2019-07-29T03:14:58.457

2

APL (Dyalog Unicode), 22 chars = 53 bytes

Requires ⎕IO←0 which is default on many systems.

⊃⌽⍸(∨⌿↑⊆⍨b)⍷⌽b←2⊥⍣¯1⊢⎕

Try it online!

 prompt for input

 yield that (separates ¯1 from )

2⊥⍣¯1 convert to base-2, using as many positions as needed

b← store as b (for binary)

 reverse

() mark the starting positions of the following in that:

⊆⍨b self-partition b (i.e. the 1-streaks of b)

 mix (make list of lists into matrix, padding with zeros)

∨⌿ vertical OR reduction (yields longest streak)

ɩndices of starting positions

 reverse

 pick the first one (yields zero if none available)

Adám

Posted 2017-09-16T19:47:44.550

Reputation: 37 779

you're missing a ∇ in the footer on tio – ngn – 2017-09-20T18:09:55.643

@ngn Right you are. – Adám – 2017-09-23T20:20:53.263

2

MS SQL Server, 437 426 407 398 bytes

SQL Fiddle

I'm sure that I could remove line breaks, etc, but this is as compact as I was willing to make it:

create function j(@ int)
returns int
as BEGIN
declare @a varchar(max)='',@b int,@c int=0,@d int=0,@e int=0,@f int=0,@g int=0,@h int=0
while @>0 BEGIN SELECT @a=cast(@%2 as char(1))+@a,@=@/2
END
SET @b=len(@a)
while @<@b
BEGIN
select @c=@d,@d=cast(substring(@a,@b-@,1)as int)
IF @d=1
BEGIN IF @c=0
SELECT @e=@,@g=1
else SET @g+=1 END
IF @g>=@h BEGIN select @h=@g,@f=@e END
SET @+=1
END
return @f
END

Here's a more readable version:

create function BinaryString(@id int)
returns int
as BEGIN
  declare @bin varchar(max)
  declare @binLen int
  declare @pVal int = 0
  declare @Val int = 0
  declare @stC int = 0 --start of current string of 1s
  declare @stB int = 0 --start of biggest string of 1s
  declare @lenC int = 0 --length of current string of 1s
  declare @lenB int = 0 --length of biggest string of 1s

  set @bin = ''

    while @id>0
      BEGIN
        SET @bin = cast(@id%2 as varchar(1)) + @bin
        SET @id = @id/2
      END

    SET @binLen = len(@bin)

    while @id<@binLen
      BEGIN
        set @pVal = @Val
        set @Val = cast(substring(@bin,@binLen-@id,1) as int)
        IF @Val = 1 and @pVal = 0
          BEGIN 
            SET @stC = @id
            SET @lenC = 1
          END
        IF @Val = 1 and @pVal = 1
          BEGIN 
            SET @lenC = @lenC + 1
          END
        IF @lenC >= @lenB
          BEGIN
            set @lenB = @lenC
            set @StB = @StC
          END

        SET @id = @id + 1 
      END

  return @StB
END

The real trick is that as far as I could find, there is no native SQL functionality to convert a number from decimal to binary. As a result, I had to code the conversion to binary manually, then I could compare that as a string, one character at a time until I found the right number.

I'm sure there's a better way to do this, but I didn't see a(n) SQL answer, so I figured I'd throw it out there.

phroureo

Posted 2017-09-16T19:47:44.550

Reputation: 183

If you can golf it more, please do so. But otherwise, this is great! Welcome to PPCG! – NoOneIsHere – 2017-09-18T22:03:48.833

@NoOneIsHere thanks! I realized I can shorten my function name too ;) – phroureo – 2017-09-18T22:04:54.063

1

MATL, 15 bytes

`tt2/kZ&t]xBnq&

Try it online!

Uses the half and AND idea. The k is necessary only to make it terminate for 1 - for some reason, 1 AND 0.5 returns 1, causing an infinite loop.

(alternate solution: BtnwY'tYswb*&X>)- by converting to binary and run-length encoding)

B. Mehta

Posted 2017-09-16T19:47:44.550

Reputation: 763

1

APL (Dyalog Classic), 24 21 bytes

63|-⊃⍒+/×\↑,⍨\⎕⊤⍨64⍴2

Try it online!

ngn

Posted 2017-09-16T19:47:44.550

Reputation: 11 449

1

Excel VBA, 54 44 Bytes

-10 Bytes thanks to @EngineerToast

Anonymous VBE immediate window function that takes input from range [A1] and outputs to the VBE immediate window

?Instr(1,StrReverse([Dec2Bin(A1)]),1)+[A1>0]

Taylor Scott

Posted 2017-09-16T19:47:44.550

Reputation: 6 709

1Besides the oversight having C1 still in there instead of A1, I think you can output the Instr results directly with a little twisting for the zero input correction: ?Instr(1,StrReverse([Dec2Bin(A1)]),1)+([A1]>0) (46 bytes). True = -1 because... VBA. – Engineer Toast – 2017-09-18T19:32:32.790

@EngineerToast - Sweet! I should have seen that; I was able to drop it down 2 bytes by bringing the >0 into the [A1] notation – Taylor Scott – 2017-09-20T00:19:54.243

1

Google Sheets, 94 bytes

=Len(Dec2Bin(A1))-Find(MAX(Split(Dec2Bin(A1),0)),Dec2Bin(A1))-Len(MAX(Split(Dec2Bin(A1),0)))+1

No, it's not very pretty. It'd be real nice to be able to store Dec2Bin(A1) as a variable for reference.

Key point: Like Excel, the Dec2Bin function has a max input value of 511. Anything larger than that returns an error, as seen below.

Results

Engineer Toast

Posted 2017-09-16T19:47:44.550

Reputation: 5 769

1

R, 117 Bytes

z=rev(Reduce(function(x,y)ifelse(y==1,x+y,y),strtoi(intToBits(scan())),,,T));ifelse(!sum(z),0,33-which.max(z)-max(z))

Zahiro Mor

Posted 2017-09-16T19:47:44.550

Reputation: 371

104 bytes! Instead of rev, use Reduce(...,T,T) to accumulate from the right (switching x,y in the function definition). Then use 1+max(z)-which.max(z) since the result is somewhat different. Use "if" instead of "ifelse" since we don't need the vectorization; aaand if you use any(z) instead of !sum(z) you drop a byte. – Giuseppe – 2017-09-19T21:06:07.487

I think we should be able to get this to less than 100 bytes. – Giuseppe – 2017-09-19T21:07:25.477

@giuseppe I feel somewhat a cheater for being here before you! Will do times tnx a bunch! – Zahiro Mor – 2017-09-19T21:07:57.183

But a nice approach no ? – Zahiro Mor – 2017-09-19T21:09:20.593

1Oh, no worries, I saw this earlier but didn't feel like answering it because R is so bad at bit operations... Yeah, good work, you got my +1 – Giuseppe – 2017-09-19T21:09:33.857

instead of that nasty Reduce, use y=strtoi(intToBits(scan()));z=cumsum(y)*y – Giuseppe – 2017-09-19T21:15:31.173

76 bytes – Giuseppe – 2017-09-19T21:16:53.690

Ahhh but using the reduce is what I liked in this.... anyways I think your suggestion is a completely different approach and you should post it.... – Zahiro Mor – 2017-09-19T21:16:58.470

Well, the cumsum(y)*y is equivalent to your Reduce, so I'd say it's still your answer, but I leave it to your conscience. – Giuseppe – 2017-09-19T21:18:38.000

Please do man... I'm with no R till Monday anyways.... – Zahiro Mor – 2017-09-19T21:19:51.317

0

Retina, 52 43 bytes

Convert to binary, then replace with the length of what follows the largest string of ones.

.*
$*
+`(1+)\1
$+0
01
1

$'¶
O`
A-3`
^1+

.

Try it online - all test cases

Saved 9 bytes thanks to Martin.

mbomb007

Posted 2017-09-16T19:47:44.550

Reputation: 21 944

You can use $+ for ${1}. But you can save even more by replacing the last stage with a bunch of stages like this: https://tio.run/##K0otycxL/K/qrpHA9V9Pi0tFi0s7QcNQWzPGkEtF24DLwJDLkItLRf3QNi7/BC5HXeMErjhDbS4uvf//DbgMTYy4TCy4zE0NAA

– Martin Ender – 2017-09-18T13:33:50.583

@MartinEnder Ok. The ${1} was copied from your tutorial on Github. – mbomb007 – 2017-09-18T16:33:48.143

0

Pyth, 17 bytes

This is a recursive function. The link includes y in order to call the function on the given input.

L|&K.&b/b2yKsl|b1

Verify all test cases.

Pyth, 20 bytes

-lK.B|Q1+xKJeScK\0lJ

Verify all test cases.

Mr. Xcoder

Posted 2017-09-16T19:47:44.550

Reputation: 39 774

0

R, 66 Bytes

function(i){a=rle(intToBits(i));max(0,a[[1]][which(a[[2]]==1)])}

Explanation:

function(i){
  a = rle(                  # Run-length encode
    intToBits(i)            # The bits in i
  );                        # And assign it to a.
  max(0,                    # Return the maximum of zero and
      a[[1]][               # The lengths of a,
        which(a[[2]]==1)    # But only those where the repeated bit is 1
        ])
}

Julian Zucker

Posted 2017-09-16T19:47:44.550

Reputation: 129

1This returns the length of the longest streak, not its position. Check against the test cases and the specs at the top. – user2390246 – 2017-09-18T09:54:59.257

I will change my downvote to an upvote once this answer is corrected. Also, note that you can use a$l instead of a[[1]] and a$v instead of a[[2]] to save some bytes :), as well as >0 instead of ==1. – Giuseppe – 2017-09-19T21:27:14.470

0

Javascript, 54 chars

f=i=>i.toString(2).split(0).sort().reverse()[0].length
  • i.toString(2) gets the binary string for the integer.
  • The .split(0) gets each sequential ones part in an array element.
  • .sort().reverse() gets us the highest value as first.
  • The [0].length gives us the length of that first value.

nl-x

Posted 2017-09-16T19:47:44.550

Reputation: 306

the starting position of number of largest consecutive 1's – L3viathan – 2017-09-18T11:19:46.020

0

Python 2, 41 bytes

f=lambda n:n/2and(n&n/2<1)+f(n&n/2or n/2)

Try it online!

Based on this solution by Mr. Xcoder.

xnor

Posted 2017-09-16T19:47:44.550

Reputation: 115 687

0

Objective-C, 96 chars

for(int h=0,c=0,l=0,p=0;;x/=2,p++){if(x%2==0){if(c<=h){h=c;l=p;}c=0;if(x==0){return p;}}else{c++;}}
  • If x is even the highest count is checked and count resets
  • If x is also 0 then return the highest count
  • If x isn't even, then the last digit is 1 and count increments
  • x is divided by two

Fennelouski

Posted 2017-09-16T19:47:44.550

Reputation: 121

Isn't this supposed to return the bit position of the highest count, not the count value. – cleblanc – 2017-09-18T20:07:55.833

Yes it is. I did not catch that. Thank you for pointing that out. – Fennelouski – 2017-09-18T23:12:13.227

0

Perl 5, 45 + 1 (-p)

(sprintf"%b",$_)=~/(1+)(?!.*1\1)/;$_=length$'

If you write this out on the command line of most shells, you may have to type this as:

perl -pE'(sprintf"%b",$_)=~/(1+)(?!.*1\1)/;$_=length$'"'"

The dance of the quotes at the end is just to get perl see a ', which would otherwise be consumed by the shell.

user73921

Posted 2017-09-16T19:47:44.550

Reputation:

0

Java 8, 81 bytes

int c(int n){int x=(int)(Math.log(n)/Math.log(2));return(n&=n/2)>0?c(n):x<0?0:x;}

Port of @Arnauld's JavaScript answer.

Try it here.

Kevin Cruijssen

Posted 2017-09-16T19:47:44.550

Reputation: 67 575

0

Javascript, 71 bytes

I was thinking about regular expressions and...

x=>+x.toString(2).replace(/.*?0?(1*)(?!.*\1[1])(.*)/,(x,m,a)=>a.length)

Regex101 link

Washington Guedes

Posted 2017-09-16T19:47:44.550

Reputation: 549