在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

13
欢迎来到PPCG!“输入不能视为字符串”背后的原因是什么?这将取消所有不能处理64位整数的语言的资格,并且不太可能导致采用整数的更多答案,因为无论如何这都是直接的方法。
Arnauld

1
我们可以False代替0吗?
Jo King

4
@Arnauld在这里和其他站点上已经存在类似的问题,这些问题专门要求基于字符串的解决方案,但是没有任何问题使数学和逻辑运算成为可能。我希望看到一堆解决此问题的方法,这些方法在其他地方尚未解决。是否应该开放解决方案并使其包罗万象?
戴夫

4
包括x86和ARM在内的几个CPU对此都有特定的说明(x86实际上有几个)。我一直想知道为什么编程语言没有公开此功能,因为在当今大多数编程语言中,您都无法调用汇编指令。
slebetman

1
@ user202729我认为我的措辞很差:“无论数字是哪种语言,输出都应针对数字的64位带符号整数表示进行验证”,这意味着该问题将零的数量定义为零的数量以64位有符号整数表示。我想我做了这个约束来消除有符号和无符号整数。
戴夫

Answers:


41

Linux上的x86_64机器语言,6个字节

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

需要Haswell或K10或更高版本的lzcnt指令。

在线尝试!


20
内建

1
我建议指定使用的调用约定(尽管您确实在Linux上说过)
qwr

@qwr看起来像SysV调用约定,因为参数在%rdi中传递,并且在%rax中返回。
Logern

24

六角形78 70字节

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

在线尝试!

对于实际的语言来说,这不是一个微不足道的挑战吗?;)

边长为6。我无法将其放入边长为5的六角形中。

说明


3
我对“解释”感到非常难过。:D
埃里克·杜米尼尔

1
我认为您处理负数/零可能过于复杂。通过不进行大量的2 ^ 64计算,我设法使类似的程序适合边长5。不过,显然它还没有打好高尔夫!
FryAmTheEggman

@fry啊,对,负数总是有0个前导零...这肯定会导致程序更短,因为生成2 ^ 64很长。
user202729

12

Python,31个字节

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

在线尝试!

表达式是按位&划分的两个部分:

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

67-len(bin(-n))对于非负输入,它给出了正确的答案。它采用位长,然后从67中减去,即64的3来补偿-0b前缀。否定是一种调整技巧,可以n==0使用否定不会-在前面产生符号。

& ~n>>64使得答案,而不是为0n。当时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

C(gcc),14个字节

__builtin_clzl

在tio上工作正常

C(gcc)35 29字节

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

在线尝试!

比丹尼斯6个字节

C(gcc)编译器标志,David Foerster撰写的29个字节

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

在线尝试!


3
值得一提的是,它仅适用于64位计算机(或任何其他具有LP64 / ILP64 / ABI的计算机)
Ruslan

1
天啊,这比任何使用的更短GCC内置__builtin_clzl有,我可以上来
大卫·佛斯特

@Ruslan:好的一点,在long32位(包括Windows x64)的系统上,您需要__builtin_clzll(无符号long long)。 godbolt.org/z/MACCKf。(不像英特尔内部函数,GNU C内建的无论操作是可行的一个机器指令的支持在32位x86,clzll编译的分支或CMOV做的。lzcnt(low half)+32或者lzcnt(high half)或者,bsr如果lzcnt是不可用的。
彼得·科德斯

测试用例包括“ 0”,但__builtin_clz(l)(l)对于零而言是未定义的行为:“如果x为0,则结果未定义。”
MCCCS

1
@MCCCS如果有效,则很重要。这就是为什么我保留最后一个答案的
原因-l4m2

6

Perl 6的35 28 26个字节

-2字节归功于nwellnhof

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

在线尝试!

带有数字并返回数字的匿名代码块。这会将数字转换为二进制字符串并计算前导零。它适用于负数,因为第一个字符是-eg -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,但那还是行不通的。我想这会
Arnauld

1
@IsmaelMiguel不用担心。:)确实有可能使.toString()方法起作用,但是我们仍然需要一个BigInt文字作为输入。否则,我们只有52位的尾数,当精度丢失时,将导致无效的结果
Arnauld

1
BigInt后缀与您的参数相同是一个令人困惑的事实……
Neil

1
@Neil PPCG上不可读的代码?这不可能!固定!:p
Arnauld





4

05AB1E10 9 字节

·bg65αsd*

I / O都是整数

在线尝试验证所有测试用例

说明:

·         # 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]它本质上生成反向字符串的方法{01个}64按照字典顺序。所以我们可以总结一下1个使用的s前缀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位整数)。

@ l4m2的C(gcc)答案的端口。

在线尝试。

说明:

 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

编辑:可以使用@lukeg的Java 8 answer中显示的内置函数将其设置为26个字节Long::numberOfLeadingZeros


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

果冻 10  9 字节

-1得益于Outgolfer的Erik的巧妙技巧(现在非负就是简单的

ḤBL65_×AƑ

接受整数(在范围内)的单子链接,该整数产生一个整数。

在线尝试!或查看测试套件


10是 ḤBL65_ɓ>-×

这是另一个10字节的解决方案,我喜欢它,因为它说的是“ BOSS” ...

BoṠS»-~%65

测试套件在这里

... BoṠS63r0¤iBoṠS63ŻṚ¤i或者BoṠS64ḶṚ¤i也可以。


另有10 byter(丹尼斯)是æ»64ḶṚ¤Äċ0(再次æ»63r0¤Äċ0æ»63ŻṚ¤Äċ0也将工作)



@EriktheOutgolfer我对自己说:“一定有一种高尔夫球手的方法可以乘以isNonNegative”,却一点也没有想到Ƒ非常出色的工作!
乔纳森·艾伦

1
实际上,我已经理论化了一段时间了。警告它不会向量化!;-)实际上是“扁平化,然后检查所有元素是否都是非负数”。
暴民埃里克(Erik the Outgolfer)

2

Perl 5 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个字节);)
Dada

IMO,您不允许sub从包含Perl 5函数的答案中删除关键字。
nwellnhof

我已经看到了类似于删除sub其他语言,perl6,powershell等的答案的功能。
Kjetil S.

在Perl6中,我认为您不需要sub{}做一个(匿名的?)子,这解释了为什么在Perl6答案中省略了它。我同意@nwellnhof的观点,认为您不应该被删除sub。(当我仍然活跃时,就像一年前一样,那是规则)
Dada

现在改变了。并包括在内$+[0]
Kjetil S.

2

Swift(在64位平台上),41字节

声明一个闭包f,它接受并返回Int。此解决方案仅正常工作的64位平台,其中Inttypealias编到Int64。(在32位平台上,Int64可以显式地使用闭包的参数类型,增加2个字节。)

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

在Swift中,即使基本整数类型也是在标准库中声明的普通对象。这意味着Int可以具有方法和属性,例如leadingZeroBitCount(在符合标准库FixedWidthInteger协议的所有类型上都是必需的)。


有趣。让我想起了Rust。我想这应该算作是20个字节,.leadingZeroBitCount
穿上鲜艳

2

Haskell,24个字节

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

在线尝试!

这基本上与Kevin Cruijssen的Java解决方案相同,但是我是独立找到的。

该参数应具有Int64位版本的类型,或者Int64其他任何。

说明

如果参数为负,则结果立即为0。否则,我们向左移动,用1填充,直到达到负数。这种填充使我们避免将0用作特殊情况。

仅供参考,这是显而易见的/有效的方法:

34字节

import Data.Bits
countLeadingZeros

1

干净,103字节

使用与ceilingcat答案相同的“内置”

f::!Int->Int
f _=code {
instruction 243
instruction 72
instruction 15
instruction 189
instruction 192
}

在线尝试!

干净,58字节

import StdEnv
$0=64
$i=until(\e=(2^63>>e)bitand i<>0)inc 0

在线尝试!



1

Perl -p 5,42个字节

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

在线尝试!

比基于位串的解决方案长,但基于数学的解决方案还不错。


如果我没记错的话,那真的行不通
Dada

@Dada我看到在某些情况下浮点除法无法正常工作。我打了个int电话,应该可以解决问题。
Xcali

抱歉,复制粘贴失败了。就是我想发送的;)
Dada

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...看起来是基于字符串的
Titus

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

Wolfram Language (Mathematica), 41 bytes

正数的公式为63-Floor@Log2@#&。替换规则用于零和负输入的特殊情况。

输入不必是64位有符号整数。这将有效地占用输入底限,将其转换为整数。如果您为64位整数输入了超出正常范围的数字,它将告诉返回一个负数,指示存储该整数还需要多少位。

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

在线尝试!

@ LegionMammal978的解决方案要短得多,只有28个字节。输入必须是整数。根据文档:“ BitLength[n]实际上是的有效版本Floor[Log[2,n]]+1。”它会自动处理零报告0而不是的情况-∞

Wolfram语言(Mathematica),28个字节

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

在线尝试!


1
Boole[#>=0](64-BitLength@#)& is a good bit shorter at 28 bytes. It uses the same basic concept as yours, but applies BitLength and Boole.
LegionMammal978

I totally forgot about BitLength!
Kelly Lowder

1

bitNumber - math.ceil (math.log(number) / math.log(2))

e.g 64 bit NUMBER : 9223372036854775807 math.ceil (math.log(9223372036854775807) / math.log(2)) ANS: 63


If you could add the language name to this, that would be great,as people are likely to down vote answers that don't have the language name included
Jono 2906
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.