【问题标题】:When to use Shift operators << >> in C#?何时在 C# 中使用 Shift 运算符 << >>?
【发布时间】:2009-12-19 17:38:11
【问题描述】:

我正在研究 C# 中的移位运算符,试图找出答案 何时在我的代码中使用它们。

我找到了答案,但对于 Java,您可以:

a) 使更快整数乘除运算:

*4839534 * 4* 可以这样完成: 4839534

543894 / 2 可以这样完成:543894 >> 1

对于大多数处理器而言,移位运算比乘法快得多。

b) 将字节流重组为 int 值

c) 用于加速图形操作,因为红色、绿色和蓝色由单独的字节编码。

d) 将小数字打包成一个长...


对于 b、c 和 d,我无法想象这里有一个真实的样本。

有谁知道我们是否可以在 C# 中完成所有这些项目? shift 运算符在 C# 中是否有更多实际用途?

【问题讨论】:

  • "进行更快的整数乘除运算。"不要这样做。现代编译器会为你做这件事。它只会让你的代码更难阅读。
  • 在 1980 年代 一些 严重优化的 C 编译器中,移位比乘法更快。这是一个城市传奇,它仍然有所作为。

标签: c# operators bit-shift


【解决方案1】:

无需将它们用于优化目的,因为编译器会为您处理这些问题。

仅在代码的真正意图是移位时使用它们(如您问题中的其余示例中所示)。其余时间只使用乘法和除法,以便代码的读者一眼就能理解。

【讨论】:

    【解决方案2】:

    除非有非常令人信服的理由,否则我的观点是,使用这样的巧妙技巧通常只会使代码更加混乱,几乎没有附加价值。编译器编写者是一群聪明的开发人员,并且比普通程序员更了解这些技巧。例如,使用移位运算符将整数除以 2 的幂比除法更快,但可能没有必要,因为编译器会为您执行此操作。您可以通过查看 Microsoft C/C++ 编译器和 gcc 执行这些优化的程序集来了解这一点。

    【讨论】:

      【解决方案3】:

      我将分享一个我过去偶然发现的有趣用途。这个例子无耻地复制了一个问题的补充答案,“What does the [Flags] Enum Attribute mean in C#?

      [Flags]
      public enum MyEnum
      {
          None   = 0,
          First  = 1 << 0,
          Second = 1 << 1,
          Third  = 1 << 2,
          Fourth = 1 << 3
      }
      

      这比编写文字 1, 2, 4, 8, ... 值更容易扩展,尤其是当您超过 17 个标志时。

      权衡是,如果您需要超过 31 个标志 (1 &lt;&lt; 30),您还需要小心地将您的枚举指定为具有比有符号整数更高的上限(通过将其声明为 public enum MyEnum : ulong,例如,这将为您提供最多 64 个标志)。这是因为……

      1 << 29 == 536870912
      1 << 30 == 1073741824
      1 << 31 == -2147483648
      1 << 32 == 1
      1 << 33 == 2
      

      相比之下,如果直接将枚举值设置为2147483648,编译器会抛出错误。

      正如 ClickRick 所指出的,即使您的枚举来自 ulong,也必须针对 ulong 执行位移操作,否则您的枚举值仍然会被破坏。

      [Flags]
      public enum MyEnum : ulong
      {
          None   = 0,
          First  = 1 << 0,
          Second = 1 << 1,
          Third  = 1 << 2,
          Fourth = 1 << 3,
      
          // Compiler error:
          // Constant value '-2147483648' cannot be converted to a 'ulong'
          // (Note this wouldn't be thrown if MyEnum derived from long)
          ThirtySecond = 1 << 31,
      
          // so what you would have to do instead is...
          ThirtySecond = 1UL << 31,
          ThirtyThird  = 1UL << 32,
          ThirtyFourth = 1UL << 33
      }
      

      【讨论】:

      • 如果超过 int.MaxValue,那么您需要将值明确指定为 long,或者将评估为 long 的值,例如 E32 = 1L &lt;&lt; 32,即使您已将枚举声明为源于长。 (或ulong,视情况而定)
      【解决方案4】:

      查看这些关于the binary number systemarithmetic shift 的维基百科文章。我想他们会回答你的问题。

      当今的业务应用程序中很少遇到班次运算符。它们将频繁出现在与硬件交互或操作打包数据的低级代码中。它们在 64k 内存段的时代更为常见。

      【讨论】:

      • 打包数据仍然很常见,但 C# 程序员应该使用 BitConverter(而不是 BinaryReader)或 BitVector 进行开发。只有当该代码被验证为性能问题时,您才会返回并使用显式位操作运算符重写。
      • “相当普遍”是一个相对术语。我最后一次处理打包数据是在 1992 年,我想当时我必须将 8000 颗恒星的坐标放入一个数据段中。
      猜你喜欢
      • 1970-01-01
      • 2017-07-28
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-05
      • 2010-12-13
      相关资源
      最近更新 更多