【问题标题】:Negative Integer Comparisons负整数比较
【发布时间】:2012-07-18 01:33:19
【问题描述】:

我正在尝试比较两个整数。一个是NSIndexPathrow,另一个是NSArraycountrow 等于 0,count 等于 2。我将它们放在 if 语句中,如下所示:

if([self.selectedSetpoint row] < ([self.theCategories count]-3))
{
    //Do true stuff
}

所以根据我的数学,if 声明应该是错误的,因为我正在比较 0 &lt; -1。但是,我一直认为这句话是真的,if 内的块正在运行。我已经尝试NSLog 这些值以确保我不只是得到错误的值。我把它放在if 声明之前:

NSLog(@"%d",[self.selectedSetpoint row]);
NSLog(@"%d",[self.theCategories count]-3);
NSLog(@"%@",[self.selectedSetpoint row] < ([self.theCategories count]-3)?@"Yes":@"No");

并在控制台上得到了这个:

2012-07-17 08:58:46.061 App[61345:11603] 0
2012-07-17 08:58:46.061 App[61345:11603] -1
2012-07-17 08:58:46.062 App[61345:11603] Yes

任何想法为什么这个比较是真实的?我对比较整数有什么误解吗?

我有另一个 if 语句就在这个比较的上面

[self.selectedSetpoint row]<([self.theCategories count]-2)

这是0 &lt; 0,它工作正常(返回NO)。所以我觉得使用负整数有一些问题,我没有得到。

提前谢谢你。

【问题讨论】:

  • 如果你的意思是 -1 应该是 +1,你可以使用 ABS(theCategories.count) 所以它返回整数的绝对值。
  • 不是因为你在比较 NSUInteger 和 NSInteger 吗?
  • @EPyLEpSY 不,我不是要获取绝对值,我希望它比较 0 和 -1。
  • @Luke 我不知道,计数是无符号的吗?我想如果我在日志中得到 -1,我将在比较中得到 -1。
  • 索引路径的行是 int 而数组的计数是无符号的。

标签: iphone objective-c ios


【解决方案1】:

我怀疑问题在于count 的返回是一个无符号 整数,减去超过它的大小,它会下溢并变得非常大。我已经运行了一些测试,并且得到了与您相同的基本行为(它看起来就像是-1,并且在某些情况下它似乎按预期工作。 .. 然而,在if() 块的上下文中,它显然是下溢的。

愚蠢的问题,但幸运的是有一个简单的解决方案:在 if 语句中将其强制转换:

if([self.selectedSetpoint row] < ( (int)[self.theCategories count] -3 ))
{
    //Do true stuff
}

【讨论】:

  • 什么菜鸟的错误!谢谢!
【解决方案2】:

我打算提出一个替代解决方案 - 即避免使用减法,而是在等式的另一边使用加法:

if ([self.selectedSetpoint row] + 3 < [self.theCategories count])
{
    //Do true stuff
}

这回避了被这些下溢错误捕获,但是它留下了另一个未触及的问题......即这个问题的答案中提到的转换规则:What are the general rules for comparing different data types in C?

引用该问题的答案,您会看到 C99 规范指出:

  • (当一个操作数有符号而另一个无符号时)否则,如果无符号整数类型的操作数的等级大于或等于另一个操作数类型的等级,则将带符号整数类型的操作数转换为无符号整数类型的操作数的类型。

因此,如果您的 [self.selectedSetpoint row] + 3 为负值,那么比较将失败...

这里的其他答案主张将 (NSUInteger) 转换为 (NSInteger) - 但请注意,如果您的无符号值非常庞大,这可能会导致溢出问题。例如:

(NSInteger) -3 < (NSInteger) 4294967289 == false...

想必有一个简单的方法来解决这个问题,我首先想出了一个很难的方法来解决它......

#define SafeLT(X, Y) \
({ typeof (X) _X = (X); \
   typeof (Y) _Y = (Y); \
( _X < (NSInteger) 0 ? (( _Y > 0) ? YES : _X < _Y ) : ( _Y < (NSInteger) 0 ? NO : _X < _Y));})

无论您如何混合 NSUInteger 和 NSInteger,这都应该有效,并且将确保操作数最多被评估一次(为了提高效率)。

作为正确性证明:

  1. 要使_X &lt; (NSInteger) 0 计算为True,_X 必须是NSInteger 并且 0。编译器将通过计算_Y 的类型来进行正确的比较。如果 Y > 0,那么根据定义,我们返回 YES。否则我们知道 X 和 Y 都是有符号的并且
  2. 但是,如果 X 是 NSUInteger 或 > 0,那么我们测试 Y 以查看它是否 0 并且 Y 是 NSUInteger 或 NSInteger > 0。由于混合比较将被提升为 NSUInteger,我们每次都会有一个安全的转换,因为没有下溢的机会。

然而,一个更简单的解决方案是将类型转换为更长的有符号整数(如果您的系统有一个):

#define EasySafeLT(X, Y) \
({ long long _X = (X); \
   long long _Y = (Y); \
   ( _X < _Y);})

虽然这取决于是否有更大的可用类型,但可能并不总是可行的。

【讨论】:

    【解决方案3】:

    这似乎是比较有符号整数和无符号整数的情况。您的日志语句会抛出您的假设,因为您要求打印签名的数字。

    NSLog(@"%d", -1); //Signed
    
    -1;
    
    NSLog(@"%u", -1); //Unsigned (tested on ios, 32 bit ints)
    
    4294967295;
    

    然后当你比较时:0 &lt; 4294967295 肯定是真的。

    @ctrahey 建议的投射应该可以解决您的问题:

    if([self.selectedSetpoint row] < ( (int)[self.theCategories count] -3 ))
    {
        //Do true stuff
    }
    

    【讨论】:

    • 感谢有关日志让我失望的信息。你拿到支票有点晚了!
    • 我知道!当我看到另一个答案通过时,我正在写答案。因为关于 NSLog 的额外信息,我才继续。 =]
    【解决方案4】:

    问题是count 属性类似于NSUInteger,当您从较小的数字中减去较大的数字时,您不会得到小于零的数字,您将得到一个非常大的正数,这会导致奇怪的行为。

    试试这个方法,你会得到好的结果:

    NSLog(@"%@",(NSInteger)[self.selectedSetpoint row] < ((NSInteger)[self.theCategories count]-3)?@"Yes":@"No");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-26
      • 2017-02-11
      • 2020-09-28
      • 1970-01-01
      • 2013-08-24
      • 2013-07-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多