这个数字是二进制的吗?


58

如果整数的二进制表示形式包含的1s比0s大,而忽略了前导零,则表示二进制为重。例如1是二进制重的,因为它的二进制表示很简单1,但是4不是二进制重的,因为它的二进制表示是100。如果出现平局(例如2,二进制表示为10),则该数字不视为二进制重数。

给定一个正整数作为输入,如果它是二进制重数,则输出一个真值,如果不是二进制数,则输出一个假值。

测试用例

格式: input -> binary -> output

1          ->                                1 -> True
2          ->                               10 -> False
4          ->                              100 -> False
5          ->                              101 -> True
60         ->                           111100 -> True
316        ->                        100111100 -> True
632        ->                       1001111000 -> False
2147483647 ->  1111111111111111111111111111111 -> True
2147483648 -> 10000000000000000000000000000000 -> False

计分

这是因此每种语言中的最少字节数获胜


如果我的语言由于超出了被认为是正整数的范围而无法处理最后一个测试用例,该怎么办?
musicman523

1
@ musicman523 afaik标准I / O规则指出,您只需要接受可以用您的语言的数字格式表示的数字。请注意,通过使用boolfuck之类的东西“赌博”被视为标准漏洞
Skidsdev

是否有任何真实/虚假值计数?还是我们需要两个不同的值?
暴民埃里克(Erik the Outgolfer)'17年

@EriktheOutgolfer任何值
Skidsdev'17年

6
阿卡A072600,如果这能帮助任何人。
dcsohl

Answers:


28

x86机器代码,15 14字节

F3 0F B8 C1 0F BD D1 03 C0 42 2B D0 D6 C3

此函数使用Microsoft的__fastcall调用约定(ecx中的第一个也是唯一的参数,eax中的返回值,允许被调用者阻塞edx),尽管它可以为在寄存器中传递参数的其他调用约定进行一些修改。

它返回255作为真实,返回0作为false。

它使用未记录(但得到广泛支持)的操作码salc

拆卸如下:

;F3 0F B8 C1 
  popcnt eax, ecx ; Sets eax to number of bits set in ecx

;0F BD D1
  bsr edx, ecx    ; Sets edx to the index of the leading 1 bit of ecx

;03 C0
  add eax, eax

;42
  inc edx

;2B D0
  sub edx, eax

  ; At this point, 
  ;   edx = (index of highest bit set) + 1 - 2*(number of bits set)
  ; This is negative if and only if ecx was binary-heavy.

;D6
  salc           ; undocumented opcode. Sets al to 255 if carry flag 
                 ; is set, and to 0 otherwise. 

;C3
  ret

在线尝试!

感谢彼得·科尔德的建议更换lzcntbsr


真好 至于明显我已经得到了popcnt向下滚动看答案之前,但没有想到的lzcnt对付只需要对这个问题的显著数字。
彼得·科德斯

有没有办法通过使用bsr而不是lzcnt(aka rep bsr)获得净节省?您必须使用sub而不是,lea因为它会给您32-lzcnt。(或者在所有现有的Intel和AMD硬件上使sst = 0的dst保持不变。AMD甚至记录了此行为,但Intel表示未定义...反正OP表示肯定,这是可以排除的0。)
Peter Cordes

1
我肯定在和@Peter一样思考,因为挑战确实明确地将输入限制为正整数。实际上,我有一个使用popcnt和拟定的解决方案bsr,但这是17个字节。与我看到的第一个asm答案相比,我认为这是相当不错的选择,但是这种巧妙的lea窍门使这条裤子破了。我也看了一下比较bsfpopcnt。但是,即使考虑到通过删除rep前缀可以节省的1个字节,我也看不出有什么办法可以击败该解决方案。
科迪·格雷

1
salc是不等效setc al:后者套al1,否则设定CF,不到255
鲁斯兰

1
的实际等值salcsbb al, al,但是您节省了1个字节来对其进行编码。顺便说一下,它由AMD记录的,并且得到了Intel的广泛支持,其助记符甚至来自Intel的P6操作码图。因此,实际上这是一个非常安全的使用方式。另外,在这里可以考虑使用该指令进行很好的改进!这基本上是我最初的草稿所做的,除了(1)我使用x86-64代码,所以inc编码时间是原来的两倍,(2)我没想到salc,所以我在更长的路。太糟糕了,我只能投票一次。
科迪·格雷

17

果冻,5个字节

Bo-SR

产生非空输出(真实)或空输出(虚假)。

在线尝试!

这个怎么运作

Bo-SR  Main link. Argument: n

B      Binary; convert n to base 2.
 o-    Compute the logical OR with -1, mapping 1 -> 1 and 0 -> -1.
   S   Take the sum s. We need to check if the sum is strictly positive.
    R  Range; yield [1, ..., s], which is non-empty iff s > 0.

真好 我有Bo-S,但是我找不到能将正/非正转换成真实/虚假的1个字节的原子...
ETHproductions

逻辑还是-1,对吗?
林恩

@Lynn是的,的确如此。谢谢。
丹尼斯,


@cairdcoinheringaahing谢谢,但是Æṃ那时不存在。
丹尼斯

14

Python 2,35个字节

lambda n:max('10',key=bin(n).count)

在线尝试!

旧答案,38个字节

输出0为错误-2-1真实

lambda n:~cmp(*map(bin(n).count,'10'))

在线尝试!


2
返回的前导0是否bin会导致此解决方案问题?
阴影

3
@shadow没问题,因为这种方式max有效。如果出现平局,max将返回具有最大值的可迭代对象中的第一个值。这段代码利用这一事实来确保在出现平局的情况下返回1,这实际上意味着有多个而不是零,因为额外添加了零bin。如果不使用额外的零,则以这种方式编写时实际上是不正确的。
FryAmTheEggman'7

@FryAmTheEggman这在旧答案上也是如此,当两者都相等时,cmp收益0就等于
Rod

11

八度,18字节

@(n)mode(de2bi(n))

TIO不起作用,因为不包括通讯工具箱。可以在Octave-Online上进行测试。

工作原理:

de2bi将十进制数字转换为二进制数字矢量,而不是字符串dec2bin

mode返回向量中最频繁的数字。如果出现平局,则默认为最低。

@(n)                % Anonymous function that takes a decimal number as input 'n'
    mode(        )  % Computes the most frequent digit in the vector inside the parentheses
         de2bi(n)   % Converts the number 'n' to a binary vector

通信工具箱是Octave的标准组成部分还是更类似于其他语言的库?
dcsohl

它是安装随附的软件包。在某些安装中,您必须专门加载它,而在其他安装中,它会自动作为标准加载。它是Octave-Online.net上标准的一部分,因此我将其用作参考。(该代码必须在挑战之前至少存在一个解释器中工作)。
斯蒂夫·格里芬

9

JavaScript(ES6),36 34字节

f=(n,x=0)=>n?f(n>>>1,x+n%2-.5):x>0

f=(n,x=0)=>n?f(n>>>1,x+=n%2-.5):x>035个字节。
ovs

输入而不是负值,请使用n>>1而不是n>>>1保存字节。
kamoroso94 '17

@ kamoroso94谢谢,但之后它会失败在2147483648
ETHproductions

@ETHproductions达恩,并n/2|0没有更好:/
kamoroso94 '17



7

Brachylog,6个字节

ḃọtᵐ>₁

在线尝试!

说明

Example input: 13

ḃ        Base (default: binary): [1,1,0,1]
 ọ       Occurences:             [[1,3],[0,1]]
  tᵐ     Map Tail:               [3,1]
    >₁   Strictly decreasing list

由于将永远不会用前导零的数字列表来统一其输出,因此我们知道1will的出现总是在第一,而0will的出现总是在在第二



6

C(gcc)51 48 41 40字节

i;f(n){for(i=0;n;n/=2)i+=n%2*2-1;n=i>0;}

在线尝试!


根据OP的说明,您可以删除unsigned
musicman523 '17

由于nnn为正,因此您可以更改n>>=1n/=2。我也认为您可以使用~n代替n^-1,它也应该允许您更改&&&
musicman523 '17

当我编辑评论时,会发生一些奇怪的事情-“ nnn”的意思是n,不要介意将其更改&&&,我认为这行不通。但是将其更改为*似乎可行
musicman523 '17

@ musicman523 &&原本只能处理无符号的情况,但是由于我只需要处理正整数,因此可以将其全部删除。关于/=缩短一点的好点>>=,谢谢!
cleblanc

您可以保存一个字节,更改n&1?++i:--1i+=n%2*2-1。您可能还可以>0通过声明将输出零(对于重磅)和非零(对于不重型)输出来摆脱音乐
musicman523 '17

6

R54 53 51字节

-1个字节,感谢Max Lawnboy

n=scan();d=floor(log2(n))+1;sum(n%/%2^(0:d)%%2)*2>d

从stdin读取;返回TRUE二进制大数。d是二进制位数;sum(n%/%2^(0:d)%%2计算数字总和(即,个数)。

在线尝试!


在发布我的信息后才看到您的答案...无论如何,您可以使用log2(n)而不是 log(n,2)保存1个字节
Maxim Mikhaylov

@MaxLawnboy啊,当然。谢谢!
朱塞佩

打出另外12个字节:codegolf.stackexchange.com/a/132396/59530
JAD

6

x86_64机器码,23 22 21字节

31 c0 89 fa 83 e2 01 8d 44 50 ff d1 ef 75 f3 f7 d8 c1 e8 1f c3

拆解:

  # zero out eax
  xor  %eax, %eax
Loop:
  # copy input to edx
  mov  %edi, %edx
  # extract LSB(edx)
  and  $0x1, %edx
  # increment(1)/decrement(0) eax depending on that bit
  lea -1(%rax,%rdx,2), %eax
  # input >>= 1
  shr  %edi
  # if input != 0: repeat from Loop
  jnz  Loop

  # now `eax < 0` iff the input was not binary heavy,
  neg %eax
  # now `eax < 0` iff the input was binary heavy (which means the MSB is `1`)
  # set return value to MSB(eax)
  shr  $31, %eax
  ret

感谢@ Ruslan,@ PeterCordes的-1字节!

在线尝试!


有什么特别的原因为什么要使用8d 1f代替89 fb
Ruslan

2
真正的问题是,您为什么要使用这种令人讨厌的AT&T语法?此外,反汇编和您的反汇编都同意您有add eax, 2+ dec eax,但是您的注释建议您要递增ebx,而不是eax
科迪·格雷

1
您可以将jnz Nextadd/ dec(7字节)替换为lea -1(%rax, %rbx, 2), %eax(4字节)以进行操作eax += 2*ebx - 1(就像在其他x86机器码answer中一样)。然后在循环之外neg %eax(2个字节),然后将符号位移到底部。净节省1个字节。如果您的返回值为a 或,则Or test %eax,%eax/ setge %al也将起作用。boolint8_t
彼得·科德斯

1
@PeterCordes我想我知道发生了什么,但是我不确定:我可能没有尝试过lea -1(%rax,rbx,2),只是这样lea -1(%eax,%eax,2)浪费了字节。无论如何,你们俩都是对的,我可以这样保存一个字节。非常感谢(作为回报,我将更lea改为mov我正在处理的那段时间)!
ბიმო

1
@ moonheart08:那时我还不知道,但是有人发布了一个答案,该答案节省了7个字节。
ბიმო

5

Perl 6的 32  30个字节

{[>] .base(2).comb.Bag{qw<1 0>}}

测试一下

{[>] .polymod(2 xx*).Bag{1,0}}

测试一下

展开:

{      # bare block lambda with implicit parameter 「$_」

  [>]  # reduce the following with &infix:« > »

    .polymod(2 xx *) # turn into base 2 (reversed) (implicit method call on 「$_」)
    .Bag\            # put into a weighted Set
    { 1, 0 }         # key into that with 1 and 0
                     # (returns 2 element list that [>] will reduce)
}

5

明智40 39字节

::^?[:::^~-&[-~!-~-~?]!~-?|>]|:[>-?>?]|

在线尝试!

说明

::^?                                      Put a zero on the bottom
    [                                     While
     :::^~-&                              Get the last bit
            [-~!-~-~?]!~-?|               Increment counter if 0 decrement if 1
                           >              Remove the last bit
                            ]|            End while
                              :[>-?>?]|   Get the sign

5

哈斯克尔,41 34

g 0=0
g n=g(div n 2)+(-1)^n
(<0).g

如果n是奇数,则取一个,如果是偶数,-1则取一个1。使用添加一个递归调用,n/2如果停止n = 0。如果结果小于0该数字,则为二进制重数。

在线尝试!

编辑:@ØrjanJohansen找到了一些快捷方式,并保存了7个字节。谢谢!


mod n 2可以是n,而没有累加器则要短一个字节。在线尝试!
与Orjan约翰森

5

视网膜37 34字节

.+
$*
+`(1+)\1
$1@
@1
1
+`.\b.

1+

在线尝试!链接包括较小的测试用例(较大的测试用例可能会耗尽内存)。编辑:感谢@MartinEnder,节省了3个字节。说明:第一个阶段从十进制转换为一进制,而后两个阶段从一进制转换为二进制(这几乎是Retina Wiki上的一进制算术页面,除了我使用@而不是0)。第三阶段寻找成对的不同字符,可以是@11@,然后删除它们,直到不存在为止。然后,最后阶段检查剩余的1s。


${1}可以$+。或者,您可以使用!代替,0然后缩短01|10.\b.
Martin Ender

@MartinEnder Huh,$+当模式包含时,做正确的事|吗?我想知道我以前是否可以使用过……
Neil

2
不,这$+是超级愚蠢的行为,并且仅使用数量最大的组,而不管是否使用过。仅当您有9个以上的组或类似此处的情况时,它才对打高尔夫球有用,而且我不知道为什么我会在生产正则表达式中使用它。
Martin Ender


5

Kotlin,50个字节

{i:Int->i.toString(2).run{count{it>'0'}>length/2}}

隐式类型的Lambda (Int) -> Boolean。1.1版及更高版本仅由于使用Int.toString(radix: Int)

不幸的是,TIO的Kotlin运行时似乎是1.0.x,所以这是一条悲伤的狗,而不是TIO链接:



4

R,39 37字节

sum(intToBits(x<-scan())>0)>2+log2(x)

这是@MickyT和@Giuseppe使用的方法的组合,节省了另外几个字节。

sum(intToBits(x) > 0)向下舍入时,对1位数进行计数,并且2+log2(x)/2是位数总数的一半。由于两个值相等时的行为,我们不必四舍五入。



4

正则表达式(ECMAScript),85 73 71字节

^((?=(x*?)\2(\2{4})+$|(x*?)(\4\4xx)*$)(\2\4|(x*)\5\7\7(?=\4\7$\2)\B))*$

在线尝试!

Deadcode的解释

下面说明了早期的73字节版本。

^((?=(x*?)\2(\2{4})+$)\2|(?=(x*?)(\4\4xx)*$)(\4|\5(x*)\7\7(?=\4\7$)\B))+$

由于ECMAScript正则表达式的局限性,一种有效的策略通常是一次转换一个数字,同时又要保持每个步骤所需的属性不变。例如,要测试一个完美的平方或2的幂,请减少大小,同时在每一步将其保持为平方或2的幂。

以下是此解决方案在每个步骤中所做的工作:

111100101ones>zeroes1

ones>zeroesones1>zeroes1

当这些重复的步骤不再进行时,最终结果将是连续的1位串(很重,表示原始数也很重),或者是2的幂,表示原始数并不繁重。

当然,尽管以上是根据数字的二进制表示形式的印刷操作描述了这些步骤,但实际上它们是作为一元算术实现的。

# For these comments, N = the number to the right of the "cursor", a.k.a. "tail",
# and "rightmost" refers to the big-endian binary representation of N.
^
(                          # if N is even and not a power of 2:
    (?=(x*?)\2(\2{4})+$)   # \2 = smallest divisor of N/2 such that the quotient is
                           # odd and greater than 1; as such, it is guaranteed to be
                           # the largest power of 2 that divides N/2, iff N is not
                           # itself a power of 2 (using "+" instead of "*" is what
                           # prevents a match if N is a power of 2).
    \2                     # N = N - \2. This changes the rightmost "10" to a "01".
|                          # else (N is odd or a power of 2)
    (?=(x*?)(\4\4xx)*$)    # \4+1 = smallest divisor of N+1 such that the quotient is
                           # odd; as such, \4+1 is guaranteed to be the largest power
                           # of 2 that divides N+1. So, iff N is even, \4 will be 0.
                           # Another way of saying this: \4 = the string of
                           # contiguous 1 bits from the rightmost part of N.
                           # \5 = (\4+1) * 2 iff N+1 is not a power of 2, else
                           # \5 = unset (NPCG) (iff N+1 is a power of 2), but since
                           #   N==\4 iff this is the case, the loop will exit
                           #   immediately anyway, so an unset \5 will never be used.
    (
        \4                 # N = N - \4. If N==\4 before this, it was all 1 bits and
                           # therefore heavy, so the loop will exit and match. This
                           # would work as "\4$", and leaving out the "$" is a golf
                           # optimization. It still works without the "$" because if
                           # N is no longer heavy after having \4 subtracted from it,
                           # this will eventually result in a non-match which will
                           # then backtrack to a point where N was still heavy, at
                           # which point the following alternative will be tried.
    |
        # N = (N + \4 - 2) / 4. This removes the rightmost "01". As such, it removes
        # an equal number of 0 bits and 1 bits (one of each) and the heaviness of N
        # is invariant before and after. This fails to match if N is a power of 2,
        # and in fact causes the loop to reach a dead end in that case.
        \5                 # N = N - (\4+1)*2
        (x*)\7\7(?=\4\7$)  # N = (N - \4) / 4 + \4
        \B                 # Assert N > 0 (this would be the same as asserting N > 2
                           # before the above N = (N + \4 - 2) / 4 operation).
    )
)+
$       # This can only be a match if the loop was exited due to N==\4.

2
虽然这是从Deadcode的答案中获得启发,但算法却足够不同,以至于我觉得它应该单独给出答案,而不是发表评论。
凌晨

2
这是惊人的,而且正是我想要看到的(有人用更简洁的算法将我的正则表达式从水中吹了出来)。但是您的评论实际上根本没有解释它,并且评论过的73字节的regex版本甚至不起作用(\5向前的backref 减少了一个)。我已经研究了这个问题,在答案中对其进行了解释和评论(因为StackExchange不允许多行答复)。
Deadcode

4

正则表达式(ECMAScript),183字节

这是使用ECMA正则表达式要解决的另一个有趣的问题。处理此问题的“明显”方法是对1位数进行计数,然后将其与位数进行比较。但是您不能直接在ECMAScript regex中计算事物-缺少持久的反向引用意味着循环只能修改一个数字,而在每一步只能减少一个数字。

此一元算法的工作原理如下:

  1. 取适合N的2的最大幂的平方根,并记下平方根是完美的还是必须四舍五入。稍后将使用。
  2. 循环执行,将每个最高有效1位移动到存在该位的最低有效位置0。这些步骤中的每一个都是减法。在循环结束时,剩余的数字(将用二进制表示)是1s 的字符串,没有0s。这些操作实际上是在一元中完成的;仅从概念上讲,它们是以二进制形式完成的。
  3. 将此“ 1s的二进制字符串”与之前获得的平方根进行比较。如果必须对平方根进行四舍五入,则使用平方倍。这样可以确保“ 1s的二进制字符串”必须具有大于N一半数量的二进制数字,以便最终匹配。

为了获得平方根,使用了我的Rocco数字正则表达式中简要描述的乘法算法的一种变体。为了识别最低有效0位,使用了我的阶乘正则表达式中简要描述的除法算法。这些都是破坏者。因此,如果您不想破坏一些高级一元正则表达式魔术,请不要再继续阅读。如果您确实想自己弄清楚该魔术,我强烈建议您从解决此较早文章中连续扰流器标记的推荐问题列表中的一些问题开始,并尝试独立提出数学见解。

事不宜迟,正则表达式:

^(?=.*?(?!(x(xx)+)\1*$)(x)*?(x(x*))(?=(\4*)\5+$)\4*$\6)(?=(((?=(x(x+)(?=\10$))*(x*))(?!.*$\11)(?=(x*)(?=(x\12)*$)(?=\11+$)\11\12+$)(?=.*?(?!(x(xx)+)\14*$)\13(x*))\16)*))\7\4(.*$\3|\4)

在线尝试!

# For the purposes of these comments, the input number = N.
^
# Take the floor square root of N
(?=
    .*?
    (?!(x(xx)+)\1*$)    # tail = the largest power of 2 less than tail
    (x)*?               # \3 = nonzero if we will need to round this square root
                        #      up to the next power of two
    (x(x*))             # \4 = potential square root; \5 = \4 - 1
    (?=
        (\4*)\5+$       # Iff \4*\4 == our number, then the first match here must result in \6==0
    )
    \4*$\6              # Test for divisibility by \4 and for \6==0 simultaneously
)
# Move all binary bits to be as least-significant as possible, e.g. 11001001 -> 1111
(?=
    (                                 # \7 = tool for making tail = the result of this move
        (
            (?=
                (x(x+)(?=\10$))*(x*)  # \11 = {divisor for getting the least-significant 0 bit}-1
            )
            (?!.*$\11)                # Exit the loop when \11==0
            (?=
                (x*)                  # \12 = floor((tail+1) / (\11+1)) - 1
                (?=(x\12)*$)          # \13 = \12+1
                (?=\11+$)
                \11\12+$
            )
            (?=
                .*?
                (?!(x(xx)+)\14*$)     # tail = the largest power of 2 less than tail
                \13                   # tail -= \13
                (x*)                  # \16 = tool to move the most-significant 1 bit to the
                                      # least-significant 0 bit available spot for it
            )
            \16
        )*
    )
)
\7                  # tail = the result of the move
\4                  # Assert that \4 is less than or equal to the result of the move
(
    .*$\3
|
    \4              # Double the value of \4 to compare against if \3 is non-empty,
                    # i.e. if we had an even number of total digits.
)



3

J,12个字节

(+/>-:@#)@#:

J从右到左执行动词,所以让我们从结尾开始,朝着开头的方向努力。

说明

         #:       NB. Convert input to list of bits
       -:@#       NB. Half (-:) the (@) length (#)
          >       NB. Greater than 
         +/       NB. Sum (really plus (+) reduce (/)

1
(#<2*+/)@#:除非我错过了一些东西,否则应该保存1。
FrownyFrog





2

C#,82个字节

n=>{var s=System.Convert.ToString(n,2);return s.Replace("0","").Length>s.Length/2}

您可以通过将字符串视为IEnumerable <char>来修剪更多内容。 n=>{var s=Convert.ToString(n,2);return s.Count(c=>c=='1')>s.Length/2;}
GalacticCowboy

@GalacticCowboy这会增加11个字节,因为您必须完全限定Convert和包含using System.Linq;(写成namespace System.Linq{})。在这种情况下,好主意还不足以节省费用。
TheLethalCoder
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.