代码之家  ›  专栏  ›  技术社区  ›  Itamar Katz

在NSMutableArray中存储float会产生意外的结果

  •  0
  • Itamar Katz  · 技术社区  · 14 年前

    我正在写一个计算一系列事件之间平均时间间隔的方法(特别是iPhone中的按键点击)。由于我希望平均的时间间隔数在程序的生命周期中可能会发生变化,所以我将时间读数存储在一个名为 tapTimes 类型 NSMutableArray 所以我不必担心数组大小的管理。

    当我将时间读数存储为双倍时,一切正常(为简单起见,在下面的示例中,我只对一个时间间隔感兴趣):

    CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
    [tapTimes addObject:[NSNumber numberWithDouble:(double)time]];
    [tapTimes removeObjectAtIndex:0];
    double deltaT = [[tapTimes objectAtIndex:1] doubleValue] - [[tapTimes objectAtIndex:0] doubleValue];
    

    对于每秒钟左右的点击,它给出(第一个值只是数组初始化为零后的第一次读取):

    deltaT 311721948.947153
    deltaT 1.023200
    deltaT 1.080004
    deltaT 1.055961
    deltaT 1.087942
    deltaT 1.080074
    

    但是,如果我存储浮动:

    CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
    [tapTimes addObject:[NSNumber numberWithFloat:(float)time]];
    [tapTimes removeObjectAtIndex:0];
    float deltaT = [[tapTimes objectAtIndex:1] floatValue] - [[tapTimes objectAtIndex:0] floatValue];
    

    然后我得到了意想不到的结果 deltaT :

    deltaT 311721760.000000
    deltaT 0.000000
    deltaT 0.000000
    deltaT 0.000000
    deltaT 0.000000
    deltaT 32.000000
    deltaT 0.000000
    deltaT 0.000000
    deltaT 0.000000
    

    知道哪里出了问题吗?(我在Objective-c/cocoa中做mt的第一步,所以我希望答案不是太琐碎:)

    1 回复  |  直到 14 年前
        1
  •  3
  •   Jeremy W. Sherman    14 年前

    问题是 float 不够精确,不足以在一秒钟后区分一个时间戳和一个时间戳。坚持 double ;这是有原因的 CFAbsoluteTime 使用那种类型。

    下面是64位10.6.4下的问题演示:

    val: 311721760.000000 - val2: 311721761.000000 - (val2 - val): 1.000000
    v: 311721760.000000 - v2: 311721760.000000 - (v2 - v): 0.000000
    

    使用的第一行 双重的 价值观; val2 是通过添加 1 val . 使用的第二行 浮动 价值观。源代码如下:

    //clang so_float.m -o so_float
    #import <stdio.h>
    
    int
    main(void) {
      double val = 311721760.000000;
      double val2 = val + 1.0;
      fprintf(stderr, "val: %f - val2: %f - (val2 - val): %f\n", val, val2, val2 - val);
      float v = val;
      float v2 = val + 1.0;
      fprintf(stderr, "v: %f - v2: %f - (v2 - v): %f\n", v, v2, v2 - v);
      return 0;
    }