【问题标题】:Determine if a number ends with "1" using bitwise operators使用按位运算符确定数字是否以“1”结尾
【发布时间】:2013-10-04 00:29:59
【问题描述】:

在给定任意数字(例如 21、81、35、123)的情况下,仅使用基本的位运算符,我如何确定十进制数的最后一位是否为 1?

我的目标是更熟悉位操作,例如xorand 以及移位。

我面临的问题是,即使某些数字不以十进制数字 one 结尾,也会设置最低有效位,否则最后一位数字可以用这样的掩码确定:

>>> '{0:08b}'.format( 5 & 1)
'00000001'
>>> '{0:08b}'.format( 500231 & 1)
'00000001'

显然,我有点困惑,想了解如何解决这个问题。示例代码使用 Python,但建议和可能的答案可以使用任何语言,包括自然英语。

到目前为止我所尝试的:

>>> def go():
...     for i in [35,123,01,11,21,31,41,51,61,71,81,91,101]:
            endswith1(i)

def endswith1(code):
    #   ...
    #   xxxxx
    # & 00111
    # ^ 00001
    #   00000
    filter = code & 7
    isone = filter ^ 1
    a =  'and 7: {0:08b}'.format( filter)
    x =  'xor 1: {0:08b}'.format( isone )
    b =  '{0:08b}'.format( code)
    one = isone == 0
    print '%3d:%s %12s %12s %s' %( code,b,  a,x, one) 
    #return ((code & 7) ^ 1 ) == 0

>>> go()
 35:00100011 and 7: 00000011 xor 1: 00000010 False
123:01111011 and 7: 00000011 xor 1: 00000010 False
  1:00000001 and 7: 00000001 xor 1: 00000000 True
 11:00001011 and 7: 00000011 xor 1: 00000010 False
 21:00010101 and 7: 00000101 xor 1: 00000100 False
 31:00011111 and 7: 00000111 xor 1: 00000110 False
 41:00101001 and 7: 00000001 xor 1: 00000000 True
 51:00110011 and 7: 00000011 xor 1: 00000010 False
 61:00111101 and 7: 00000101 xor 1: 00000100 False
 71:01000111 and 7: 00000111 xor 1: 00000110 False
 81:01010001 and 7: 00000001 xor 1: 00000000 True
 91:01011011 and 7: 00000011 xor 1: 00000010 False
101:01100101 and 7: 00000101 xor 1: 00000100 False

【问题讨论】:

  • n % 10 == 1 有什么问题?
  • 实际问题是确定一个棋子是否是棋子,其中所有棋子都编码为pawn:01,knight:02,bishop:03,rook:04,女王:05,国王:06和81、82、83、84、85、86为黑人对应。示例函数解决了这个问题,但我认为将函数推广到所有可能的数字会很有趣。我以为问题很简单,但两个小时后,我无法用一个简单的解决方案来解决。
  • n % 10 == 1没有错,但是%不是位运算符。
  • 这实际上是一个有趣的问题,我也很想知道答案(好奇......)。我的第一个猜测是看看 % 是如何在基本级别(例如电路)实现的,然后将 n % 10 转换为那个。
  • 您是否有某些原因不想将片段编码为 2 的幂,从而大大简化了您需要执行的检查?您还可以利用该机制来拥有一个黑色/白色位,从而更容易实现对任一颜色进行操作的代码。

标签: bitwise-operators


【解决方案1】:

我认为问题在于您正在尝试对十六进制值进行十进制运算。如果您将十六进制数转换为 BCD(二进制编码的十进制),那么您将获得一些可以屏蔽 0x0001 并查看最后一位是否为 1 的内容。

http://fayazkadir.com/blog/?p=2439有一个用于 VHDL 的按位版本

它……很长。但我认为移植会给你想要的。

【讨论】:

    【解决方案2】:

    在这种情况下使用位运算符效率会很低。如果您正在使用它们进行练习,那么我建议您使用@DanielWeaver 的答案。

    n % 10 == 1 操作可以转换为您机器上的一条指令。记录在herehere 中的div 指令将为您将除法的其余部分放在寄存器的上半部分。但是,正如@MatteoItalia 指出的那样,您的编译器会避免使用此指令,因为它很慢。请参阅下面的评论,了解您的编译器如何处理 n % 10 == 1 行。

    您可以在内联汇编或@DanielWeaver 的答案中使用这种较慢的指令形式。

    正如@DanielWeaver 指出的那样,位运算符不理想的原因是因为它们对原始二进制数字进行运算。

    【讨论】:

    • 确实DIV可以用来执行这个操作,但是编译器不惜一切代价避免它,因为“通用除法”操作码很慢。 This 是 gcc 为 return (i%10)==1;-O3 生成的内容(即使在 -O0 上它也不会发出 div)。
    • 好吧,我好像忘记了这部分。自从我处理 x86 汇编以来已经有一段时间了。感谢您指出。我已经更新了我的答案。
    【解决方案3】:

    这里的解决方案: 不涉及模 10

    我将使用号码 617283950 = 100100110010110000000101101110。

    首先将数字分成奇数位和偶数位(我称“偶数”为 对应于 2 的偶数次方的位):

       100100110010110000000101101110
        0 1 0 1 0 0 1 0 0 0 1 1 0 1 0 even
       1 0 0 1 0 1 1 0 0 0 0 0 1 1 1  odd
    

    现在在每一个中,交替加减数字,如 十进制除以 11 的标准测试(从 右侧添加):

       100100110010110000000101101110
       +0-1+0-1+0-0+1-0+0-0+1-1+0-1+0 = -2
      +1-0+0-1+0-1+1-0+0-0+0-0+1-1+1  =  1
    

    现在将奇数的总和加倍,然后将其加到偶数的总和上 数字:

       2*1 + -2 = 0
    

    如果结果能被 5 整除,如本例中,数字本身就是 能被 5 整除。

    因为这个数也能被 2 整除(最右边的数字是 0), 可以被 10 整除。

    这就是您的编译器将如何优化(在许多情况下)模 10 运算:)

    【讨论】:

      【解决方案4】:

      如果不找出至少某种方法来做到这一点,我就不能放手,所以我求助于作弊,因为你在 Python 中。请不要杀我。

      # Returns whether num ends with the digit ending
      def endsInDigit(num, ending):
          return (int(str(i), 16) & 0xf) == ending
      

      在我们的特定用例中,您可以执行endsInDigit(17, 1) # FalseendsInDigit(51, 1) # True 之类的操作。

      【讨论】:

      • 我同意。这不是程序员应该需要或想要做的事情。尽管从概念上讲,它通过将 11 解释为 0x11、将 71 解释为 0x71 等,与 Daniel Weaver 的回答做同样的事情。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-19
      • 2014-02-09
      • 1970-01-01
      • 2014-08-18
      • 1970-01-01
      • 2011-04-24
      • 2022-07-17
      相关资源
      最近更新 更多