C#在运算后保留原始int/double变量符号的优雅方式

本文关键字:符号 变量 方式 double 运算 保留 int 原始 | 更新日期: 2023-09-27 18:28:30

有没有一种聪明的方法可以在对整数/双精度变量执行一系列操作后保留其符号?通过优雅,我可能更多地关注按位操作或某种函数来保留符号。

以下是我所说的不那么优雅的方式:

int myNum = -4;
bool isNegative = myNum < 0 ? true : false;
myNum += 8 / 2 % 4; //some operation
if ((isNegative && myNum > 0) || (!isNegative && myNum < 0))
    myNum *= -1;

编辑:在我的特定场景中,操作只是想更改数字的大小以匹配另一个数字。假设myNum是-2,matchNum是8,我希望myNum为-8。

C#在运算后保留原始int/double变量符号的优雅方式

"我的特殊情况是我有一个2D坐标系。如果abs(x)>abs(y)改变y的大小以匹配x,反之亦然,对于abs(x

根据你实际尝试的内容,这样的方法可能更简单:

int max = Math.Max(Math.Abs(x), Math.Abs(y));    // the larger of the two magnitudes
return (max * Math.Sign(x), max * Math.Sign(y));

一种更通用的方法(正如人们所说,您需要对Math.Sign()返回0进行补偿):

int myNum = -4;
int sign = Math.Sign(myNum);
myNum += 8 / 2 % 4; //some operation
myNum = Math.Abs(myNum) * sign;

一种有趣、快速但不可读的整数方法,它不受Math.Sign()问题的影响:

int origNum = -4;
int newNum = origNum + (8 / 2 % 4); //some operation
int signMask = (origNum ^ newNum) >> 31; // flip the sign of newNum if origNum
newNum = (newNum ^ signMask) - signMask; // and newNum have different signs.

或者,对于浮点类型,您可以屏蔽符号位,因为它们符合IEEE 754。如果JIT对此很明智,它将产生一些非常有效的SSE:

double myNum = -4.0;
long sign = GetSign(myNum);
myNum += 8.0 / 2.0 % 4.0; //some operation
myNum = SetSign(myNum, sign);
static long GetSign(double x)
{
    return BitConverter.DoubleToInt64Bits(x) & signMask;
}
static double SetSign(double x, long sign)
{
    return BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(x) & ~signMask | sign);
}
const long signMask = unchecked((long)(1UL << 63));

您的代码可以缩短为类似的代码

int myNum = -4;
bool isNegative = myNum < 0;
myNum += 8 / 2 % 4; //some operation
myNum *= (isNegative == myNum < 0) ? 1 : -1;

如果你想逐位尝试,你可以保存最高的一位,并将其用作新符号,但在我看来,它不会更优雅,但可读性较差。

这相当简短且易于理解,加上浮点类型的实现是相同的:

int myValue = -4;
int newValue = some_operation(myValue);
if ( (myValue < 0) ^ (newValue < 0) )
{
    newValue = -newValue;
}

不知道这是否是最优雅的方式。但下面的代码可以解决坐标操作问题。(y/absY)给我们一个符号。absY是一个星等。

int absX = Math.Abs(x);
int absY = Math.Abs(y);
if(  absX >  absY)
   y = (y/absY)*absX;
else if(  absX <  absY)
   x = (x/absX)*absY;