2

文字列の日付/時刻を数値の時刻値に変換しています。私の場合、何かが他のものよりも新しい/古いかどうかを判断するためにのみ使用しているため、この小さな小数の問題は実際の問題ではありません。秒単位の精度である必要はありません。しかし、それでも頭を悩ませているので、その理由を知りたい..

私の日付は、@"2010-09-08T17:33:53+0000" の文字列形式になっています。そこで、時間値を返すこの小さなメソッドを書きました。28 日または 31 日で 1 か月が何秒になるかについて誰かが飛びつく前に、私は気にしません。私の計算では、すべての月が 31 日で、年が 31*12 日であると想定しても問題ありません。これは、ある時点が別の時点よりも遅いかどうかを知るためだけに、2 つの時点の差を必要としないためです。

-(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 が返されます。

各 time= の間に 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 も試してみましたが、同じことができました。

4

5 に答える 5

10

浮動小数点丸め誤差へようこそ。固定小数点数の精度が必要な場合は、100 を掛けて (小数点以下 2 桁の場合)、round()それを 100 で割ります。数値が極端に大きくない限り (57 ビット以上を占めます)、次のようにします。除算で丸めの問題が発生しないはずです。

編集: 57 ビットに関する私のメモは、倍精度浮動小数点数の精度がはるかに低いと想定していたことに注意してください。別の読者が示唆するように行い、可能であれば double に切り替えます。

于 2010-09-08T21:11:32.977 に答える
6

IEEE 浮動小数点数には、有効な仮数ビットが 24 ビットしかありません (およそ 7 桁から 8 桁の間)。0.00125 は、414333.53 と最も近い float 表現との間の 24 ビットの丸め誤差です。正確な数値 414333.53 には 8 桁の 10 進数が必要だからです。53 * 0.01 自体は、より大きな数値に追加して結果の合計で精度を失う前に、はるかに正確になります。(これは、浮動小数点演算で計算する場合、数値の観点から、非常に異なるサイズの数値間の加算/減算が良くない理由を示しています。)

于 2010-09-08T23:45:36.220 に答える
2

メソッドを使用して、これらの日付からNSDateインスタンスを作成できます。それはあなたが扱っているものであるとしてフォーマットされた文字列を取ります。2つあると、このメソッドを使用して、どちらが後であるかを確認できます。NSString+dateWithString:YYYY-MM-DD HH:MM:SS ±HHMMNSDate-compare:

于 2010-09-09T03:33:08.810 に答える
2

これは、数値がビットで表される方法に起因する従来の浮動小数点エラーによるものです。まず、最新のマシンで使用すると非常に高速であるため、float の代わりに double を使用します。結果が本当に重要な場合は、20 倍遅くなりますが 100% 正確な decimal 型を使用してください。

于 2010-09-08T21:19:47.240 に答える
1

すべての定数に100を掛けてみると、除算する必要がなくなります。100で割るとバイナリの繰り返しパターンが生成されるため、除算が問題の原因です。

于 2010-09-09T03:24:06.757 に答える