53 * .01 = .531250

时间:2010-09-08 21:06:24

标签: iphone objective-c floating-point nsnumber

我正在将字符串日期/时间转换为数字时间值。在我的情况下,我只是用它来确定某些东西是否比其他东西更新/更旧,所以这个小小数问题不是一个真正的问题。它不需要秒精确。但是它还让我挠头,我想知道为什么......

我的约会格式为@“2010-09-08T17:33:53 + 0000”。所以我写了这个小方法来返回一个时间值。在没有人关心的情况下,如果有人在数月内跳了几天,有28天或31天。在我的数学中,可以假设所有月份都有31天,而且年份有31 * 12天,因为我不需要两个时间点之间的差异,只知道一个时间点是否晚于另一个时间点。

-(float) uniqueTimeFromCreatedTime: (NSString *)created_time {
float time;
    if ([created_time length]>19) {
      time = ([[created_time substringWithRange:NSMakeRange(2, 2)]floatValue]-10) * 535680; // max for 12 months is 535680.. uh oh y2100 bug!
      time=time + [[created_time substringWithRange:NSMakeRange(5, 2)]floatValue] * 44640; // to make it easy and since it doesn't matter we assume 31 days
      time=time + [[created_time substringWithRange:NSMakeRange(8, 2)]floatValue] * 1440;
      time=time + [[created_time substringWithRange:NSMakeRange(11, 2)]floatValue] * 60;
      time=time + [[created_time substringWithRange:NSMakeRange(14, 2)]floatValue];
      time = time + [[created_time substringWithRange:NSMakeRange(17, 2)]floatValue] * .01;
      return time;
    }
    else {
      //NSLog(@"error - time string not long enough");
      return 0.0;
    }
}

当传递上面列出的字符串时,结果应该是414333.53,而是返回414333.531250。

当我在每次之间抛出一个NSLog =跟踪它的位置时,我得到了这个结果:

time 0.000000
time 401760.000000
time 413280.000000
time 414300.000000
time 414333.000000
floatvalue 53.000000
time 414333.531250
Created Time: 2010-09-08T17:33:53+0000 414333.531250

所以最后一个floatValue返回53.0000但是当我乘以.01时它变成.53125。我也尝试过intValue,它做了同样的事情。

5 个答案:

答案 0 :(得分:10)

欢迎使用浮点舍入错误。如果你想要精确度两个固定数量的小数点,乘以100(对于2个小数点)然后round()它除以100除非它的数量不是很大(占据比我想象的更多) 57位)然后你应该没事,并且没有任何四舍五入的问题。

编辑:关于57位的说明应该注意我假设是双倍,浮点数的精度要低得多。如同其他读者所建议的那样做,并尽可能切换到双倍。

答案 1 :(得分:6)

IEEE浮点数只有24个有效位尾数(大致在7到8位十进制数字之间)。 0.00125是414333.53与最近的浮点表示之间的第24位舍入误差,因为确切的数字414333.53需要8位十进制数字。在将其添加到较大的数字并且在所得总和中失去精度之前,53 * 0.01本身将更准确地出来。 (这表明为什么在使用浮点运算进行计算时,从数值的角度来看,在不同大小的数字之间进行加/减是不好的。)

答案 2 :(得分:2)

这是由于数字以位为单位表示的经典浮点错误。首先,使用double而不是float,因为它在现代机器上使用起来非常快。当结果真的很重要时,使用十进制类型,它慢20倍但100%准确。

答案 3 :(得分:2)

您可以使用NSDate方法从NSString个日期创建+dateWithString:个实例。它需要格式化为YYYY-MM-DD HH:MM:SS ±HHMM的字符串,这是你正在处理的。如果您有两个NSDate,则可以使用-compare:方法查看哪个更晚。

答案 4 :(得分:1)

您可以尝试将所有常数乘以100,这样您就不必分开。除法是造成问题的原因,因为除以100会产生二进制的重复模式。