代码之家  ›  专栏  ›  技术社区  ›  Paul Sasik

正在查找将使负整数为零的.NET数学方法

  •  22
  • Paul Sasik  · 技术社区  · 14 年前

    在概念上类似于math.abs()-我在寻找一个函数,当给定一个正整数时,它将返回相同的整数。如果给定负值,则返回零。

    所以:

    f(3) = 3
    f(0) = 0
    f(-3) = 0
    

    是的,这很简单,可以自己写,但我想知道.NET数学类是否已经内置了这一功能,或者通过巧妙地链接几个数学*调用是否可以实现这一功能。

    6 回复  |  直到 6 年前
        1
  •  60
  •   Tim Cooper    12 年前

    它叫 Math.Max :

    Math.Max(0, x)
    
        2
  •  31
  •   Ron Warholic    14 年前

    这似乎是你想要的,不是吗?

    Math.Max(0, num);
    
        3
  •  14
  •   Thomas    14 年前

    我想

    Math.Max(0, x)
    

    是你想要的。

        4
  •  3
  •   ileff    14 年前

    它看起来像数学。麦克斯是前进的道路,但这也会起作用…;)

    (num + Math.Abs(num)) / 2
    
        5
  •  3
  •   correiadefreitas    11 年前

    max是最好的,但是没有数学和vb

    (num >= 0) * -num
    
        6
  •  0
  •   Glenn Slayden    6 年前

    给定32位有符号整数 num ,如果为负,则以下表达式将其设置为零:

    (~num >> 31) & num



    解释

    只有正整数(和零)具有 0 为了他们 符号位 ,哪个是最左边的,或“最有意义的位”(a.ka.,) MSB “”。让我们考虑一下32位的情况。通过翻转符号位,然后将其传播到其他31个位位置中的每一个,可以得到如下结果:

    • 对于正值和零,设置所有位( 0xFFFFFFFF , -1 )
    • 对于负值,清除所有位( 0x00000000 , )。

    通过 masking 原始值与此结果一起,您已将该值清零,但仅当它最初为负数时。

    评论

    1. 自从 & (按位- AND )具有非常低的优先级 C.* ,通常必须用外圆括号将这些表达式括起来:

      ((~num >> 31) & num)
      
    2. 如果 号码 未签名 (例如, uint ui ,您必须使用强制转换来确保已签署该班次。这叫A 右算术移位 ,并将MSB复制到每个向右移位的位置:

      ((int)~ui >> 31) & ui
      
    3. 对于64位值,移动63位而不是31位:

      signed long sl:       (~sl >> 63) & sl
      
      unsigned ulong ul:    ((long)~ul >> 63) & ul
      
    4. 如图所示,您必须使用 ~ (按位- NOT )操作员翻转符号位。如果你试图用“一元减号” - 相反,你会得到错误的价值答案。 0x80000000 因为这是两个整数值中的一个(零是另一个),即 不受对其应用减号的影响 . 按位- 不是 另一方面,保证为任何/每个值翻转每个位。

    5. 如果您很忙,这里有一些经过测试的扩展方法,可以复制/粘贴:

      public static int Clamp0(this int v) => v & ~v >> 31;
      
      public static long Clamp0(this long v) => v & ~v >> 63;
      


    了解有关非分支代码的更多信息!

    上面提供的代码示例是最简单的示例之一 bit-twiddling 举例说明 branchless code . 如果您不熟悉它,这个术语通常是指各种各样的微优化技术,它们试图最小化用户代码中的条件分支,以减少CPU管道中的预测失误暂停。