寻找将负整数归零的.NET Math方法

问题描述 投票:22回答:6

类似于Math.Abs​​()的概念 - 我正在寻找一个函数,当给定正整数时将返回相同的整数。如果给出否定,则返回零。

所以:

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

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

c# .net vb.net math
6个回答
65
投票

它被称为Math.Max

Math.Max(0, x)

32
投票

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

Math.Max(0, num);

14
投票

我认为

Math.Max(0, x)

是你想要的。


3
投票

看起来像Math.Max是要走的路,但这也会起作用......;)

(num + Math.Abs(num)) / 2

3
投票

Math.Max是最好的,但是没有Math和VB

(num >= 0) * -num

3
投票

给定32位有符号整数num,如果它是负数,则以下表达式返回零,否则返回原始未更改的值:

(~num >> 31) & num

这种操作有时称为夹紧;小于零的值被钳制为零。


Explanation

只有正整数(和零)的符号位有0,这是最左边的,或“最重要的位”(a.ka。,“MSB”)。让我们考虑一下32位的情况。由于位位置从0开始从左到右编号,因此符号位为“位31”。通过翻转该位然后将其传播到31个其他位位置中的每一个,您将获得以下结果:

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

通过masking得到这个结果的原始值,你已经将该值归零,但前提是它只是负数。

备注

  1. 由于&(bitwise-AND)在C#中的优先级非常低,因此通常必须用外括号括起这些表达式: ((~num >> 31) & num)
  2. 如果num未签名(例如,uint ui),则必须使用强制转换以确保转移已签名。这称为右算术移位,它确保MSB复制到每个向右移位的位置: ((int)~ui >> 31) & ui
  3. 对于64位值,移位63位而不是31位: /* signed */ long v; (~v >> 63) & v /* unsigned */ ulong ul; ((long)~ul >> 63) & ul
  4. 如图所示,您必须使用~(bitwise-NOT)运算符来翻转符号位。如果您尝试使用“一元减去”-,您将得到值0x80000000的错误答案,因为这是两个整数值之一,不受应用减号影响。 (另一个是零,但无论哪种方式都可以正常工作)。另一方面,Bitwise-NOT保证可以翻转任何/每个值的每一位。
  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管道中的错误预测停顿。

© www.soinside.com 2019 - 2024. All rights reserved.