从给定数字开始,如果为负数则将var设置为-1,如果为正数则设置为1(不使用if)

时间:2010-07-05 00:45:04

标签: bit-manipulation

我经常需要这种功能,例如,为了理解iPhone触摸的方向以及解决这个问题的唯一方法就是使用逻辑,如下所示:

int dir,distY;
distY = newY-oldY;

if (distY > 0) 
{
    dir = 1;
}
else if (distY < 0) 
{
    dir = -1;
}

我想知道是否有办法通过数学方法或时尚的老派方式在一个拍摄mybey中进行。

澄清,我正在寻找的类似例子是:

i = ++i % max;

而不是:

i++;
if ( i > max ) { i = 0; }

8 个答案:

答案 0 :(得分:2)

如果您知道该值将非零,则可以除以绝对值:

dir = distY / abs(distY);

如果它可能为零,并且你仍然希望将标志设置为某个东西,你可以做这样的事情(在C / C ++中):

dir = distY >= 0 ? 1 : -1;

当distY为零时,这会将dir设置为1.

答案 1 :(得分:2)

假设您正在使用C或C ++之类的东西将true转换为1而false为0,则可以使用:direction = (distY > 0) - (distY < 0);。在distY=0时你没有说出你想要的东西 - 这给了0(这对我来说似乎是明显的选择,但谁知道)。

当然,不能保证它会有任何好处 - 这将取决于编译器,编译器标志,CPU,甚至可能是月相的组合。 OTOH,我猜它有更多的机会做好事而不是伤害。

答案 2 :(得分:1)

direction = dirtY /和(dustY)

但是你仍然需要检查以确保distY不是0。

答案 3 :(得分:1)

您似乎正在寻找signum功能。如果您的编程语言/库没有它,那么编写起来非常简单:只需将if / else语句包装在一个函数中,这样就可以更容易和更好地使用它。

用数学符号:

sign(n) =  
|-1 if n < 0  
| 0 if n = 0  
| 1 if n > 0

如果速度较慢或较快,则位操作取决于语言,目标平台和库(如果使用的话)。以任何方式参与abs(如某些答案中所建议的)可能是一种矫枉过正,因为它将在内部包含几乎相同的逻辑,并且您还有一个呼叫和分组+您必须处理潜在的分裂零。

答案 4 :(得分:0)

如果你坚持要简洁,试试

(i>0)?1:((i<0)?-1:0)

(假设您想以最明智的方式覆盖零案例)。

可能存在使用符号位移位的黑客攻击,但我怀疑它们是优雅还是高效。

就个人而言,我会使用if-else结构。

答案 5 :(得分:0)

如果您使用的语言中0为false且1为真(或提供类型转换),则使用伪代码:

i = abs(distY) == distY; // 0 or 1
i = i*2 - 1; // -1 or 1

答案 6 :(得分:0)

你可能会告诉我C中是否有类似的东西,但Perl只有这个工作的相等运算符。

<=>运算符的使用方式如下:

$dir = $distY <=> 0;

从文档(perldoc perlop):

  

二进制"<=>"返回-1,0或1,具体取决于左参数是否在数值上小于,等于或大于右参数。

现在我想知道的是C,C ++和/或Objective-C中是否存在类似内容。

答案 7 :(得分:0)

在支持基本位操作(移位)的任何语言中,这都有效 - 即使该语言未明确使用01用于FALSETRUE

C#样本:

    // Explanatory version:
    static int Sign(int val)
    {
        val = -(int)((uint)val >> 31); // int is 32 bit, so shift by n - 1.
        // uval now contains -1 for negative and 0 for positive.
        return val * 2 + 1;
        // -1 * 2 + 1 = -1
        //  0 * 2 + 1 = +1
    }

    // Terse form:
    static int Sign(int val)
    {
        return 1 - (int)((uint)val >> 31) * 2;
    }

这是因为在小端two's complement硬件(如x86 / x64)上如何表示负数。基本上,对于负值,数字中的第一位将为“1”(参见示例文章)。

  1. 首先我们将其转换为无符号格式。这是为了消除语言对签名格式(例如.Net)上的操作进行任何特殊处理。
  2. 在此阶段,我们可能会使用AND进行0x80000000操作。这样就可以从值中消除与符号无关的位。我们不需要这样做是因为轮班的工作方式(如果你的语言只有ROL和ROR,你需要首先进行此操作)。
  3. 我们将值右移31位。移位运算符将“消灭”任何“落后”的位 - 所以我们在位2^0处留下1或0。这意味着如果值为负,则值为1,如果为正,则为0。
  4. 我们将它强制转换为int,然后使用简单的数学运算将0和1分别映射为1和-1。
  5. 如果您的目标是big-endian,我认为只需更改班次即可获得正确的结果。