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

05AB1E,10 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]它本质上生成反向字符串的方法{0,1个}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的巧妙技巧(现在非负就是简单的AƑ)

ḤBL65_×AƑ

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

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


10是 ḤBL65_ɓ>-×

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

BoṠS»-~%65

测试套件在这里

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


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



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

1
实际上,我已经理论化了AƑ一段时间了。警告它不会向量化!;-)实际上是“扁平化,然后检查所有元素是否都是非负数”。
— 暴民埃里克(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位平台,其中Int被typealias编到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.