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

Pau*_*sik 24 .net c# vb.net math

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

所以:

f(3) = 3
f(0) = 0
f(-3) = 0
Run Code Online (Sandbox Code Playgroud)

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

Bub*_*rap 72

它被称为Math.Max:

Math.Max(0, x)
Run Code Online (Sandbox Code Playgroud)


Ron*_*lic 32

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

Math.Max(0, num);
Run Code Online (Sandbox Code Playgroud)


Tho*_*mas 14

我认为

Math.Max(0, x)
Run Code Online (Sandbox Code Playgroud)

是你想要的.


Gle*_*den 5

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

            (~num >> 31) & num

这种操作有时称为夹紧;小于零的值被钳位为零。要对num自身进行钳位,请使用以下语句:

            num &= ~num >> 31;



解释

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

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

通过使用此结果屏蔽原始值,您已将值归零,但前提是它最初为负值。

评论

  1. 由于&(bitwise- AND) 在C# 中的优先级非常低,您通常必须用外括号将这些表达式括起来:

    ((~num >> 31) & num)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果num无符号的(例如,uint ui),则必须使用强制转换来确保移位是有符号的。这称为右算术移位,它确保 MSB 被复制到每个向右移位的位置:

    ((int)~ui >> 31) & ui
    
    Run Code Online (Sandbox Code Playgroud)
  3. 对于 64 位值,移位 63 位而不是 31 位:

    /* signed */     long v;      (~v >> 63) & v
    
    /* unsigned */   ulong ul;    ((long)~ul >> 63) & ul
    
    Run Code Online (Sandbox Code Playgroud)
  4. 如图所示,您必须使用~(bitwise- NOT) 运算符来翻转符号位。如果您尝试使用“一元减号”-来代替,您将得到错误的 value 答案,0x80000000因为它恰好是两个整数值之一,不会受到对其应用减号的影响。Bitwise- NOT,在另一方面,是保证翻转的任何每比特/每一个值。(另一个不能否定的值是零,对于这个特定问题,无论哪种方式都可以正确解决)

  5. 如果您赶时间,这里有一些经过测试的扩展方法,可以复制/粘贴。

    public static int Clamp0(this int v) => v & ~v >> 31;
    public static long Clamp0(this long v) => v & ~v >> 63;
    
    Run Code Online (Sandbox Code Playgroud)
  6. 使用 (5.) 中显示的方法的一个危险是,如果调用者忘记将返回值分配给任何东西,则不会出现错误或警告。在C#7 中,您可以定义允许值类型的原位突变的按引用扩展方法。这些方法有助于避免上述问题,因为它们可以(因此总是应该)声明为返回:void

    public static void RefClamp0(this ref int v) => v &= ~v >> 31;
    public static void RefClamp0(this ref long v) => v &= ~v >> 63;
    //     'void' ??^          'ref' ??^                ^?? result assigned by callee
    
    Run Code Online (Sandbox Code Playgroud)

    前面的by-ref扩展方法的调用站点示例int

    int x = -999;
    x.RefClamp0();        // CORRECT, clamps the value of 'x' in-situ; now x == 0
    
    // x = x.RefClamp0(); // NO -- 'void' return enforces correct by-ref usage
                          // CS0029: Cannot implicitly convert type 'void' to 'int'
    
    // -999.RefClamp0();  // NO -- compiler errors:
                          // CS1510: A ref or out value must be an assignable variable
                          // CS0201: Only [expressions] can be used as a statement
    
    Run Code Online (Sandbox Code Playgroud)


了解更多关于非分支代码!

上面提供的这个代码示例是演示无分支代码的最简单的位处理示例之一 。如果您不熟悉它,该术语通常指的是各种微优化技术,这些技术试图最小化用户代码中的条件分支,以减少 CPU 管道中的错误预测停顿。