5

Objective-C で次のような状況に遭遇しました。

NSLog(@"%i", (int) (0.2 * 10));         // prints 2
NSLog(@"%i", (int) ((1.2 - 1) * 10));   // prints 1

値が float または double で、整数が必要な場合(int)、キャストを行うために使用するだけでなく、 (int) round(someValue)? または、質問をひっくり返すと、いつ使用する必要があります(int)が、そのような状況で(int) round(someValue)は仕事をすることもできないため、ほとんど常に使用する必要があります(int) round(someValue)?

4

3 に答える 3

3

ここでの問題は、浮動小数点値を整数に変換することではなく、浮動小数点数で発生する丸め誤差です。浮動小数点を使用する場合は、それをよく理解する必要があります。

float と double の一般的な実装では、IEEE 754 バイナリ浮動小数点値が使用されます。これらの値は、符号 (+1 または -1) を乗じた 2 の累乗を掛けた仮数として表されます。浮動小数点数の場合、仮数は 24 ビットの 2 進数で、「小数点」(または必要に応じて「2 進小数点」) の前に 1 ビットあります。たとえば、数値 1.25 の有意桁は 1.0100000000000000000000 です。double の場合、仮数は 53 ビットの 2 進数で、ポイントの前に 1 ビットあります。

このため、10 進数の .1 および 1.1 の値を正確に表すことはできません。それらは概算する必要があります。ソースコードに「.1」または「1.1」と記述すると、コンパイラはそれを実際の値に非常に近い double に変換します。その結果が実際の値よりもわずかに大きくなる場合があります。場合によっては、実際の値よりもわずかに低くなることがあります。

float を int に変換すると、結果は (定義により) 値の整数部分のみになります (値はゼロに向かって切り捨てられます)。したがって、値が正の整数よりわずかに大きい場合は、整数が得られます。値が正の整数よりわずかに小さい場合は、次に小さい整数を取得します。

正確な計算で整数の結果が得られると予想し、実行している浮動小数点演算が非常に少なく単純であるため、誤差があまり蓄積されていない場合は、浮動小数点値を整数に丸めることができます。ラウンド機能を使用。単純な状況では、「(int) (f + .5)」のように、切り捨ての前に .5 を追加して丸めることもできます。

于 2012-06-27T15:34:36.500 に答える
1

それはあなたが望むものに依存します。明らかに、 へのストレート キャストは へintの呼び出しよりも高速ですがround、ラウンドではより正確な値が得られます。

速度が効果的であることに依存するコードを実行している場合を除き (この場合、浮動小数点値も使用するのに最適ではない可能性があります) round、. 画面に表示されるものを 1 ピクセルだけ変更するだけでも、特定のもの (角度測定、色など) を処理する場合は、精度が高いほど良い結果が得られます。

編集:キャストが丸めよりも速いという私の主張を裏付ける簡単なテスト:

Macbook Pro でテスト:

  • 2.8 GHz インテル Core 2 Duo
  • Mac OS 10.7.4
  • Apple LLVM 3.1 コンパイラ
  • -O0 (最適化なし)

コード:

int value;
void test_cast()
{
    clock_t start = clock();
    value = 0;
    for (int i = 0; i < 1000 * 1000; i++)
    {
        value += (int) (((i / 1000.0) - 1.0) * 10.0);
    }

    printf("test_cast: %lu\n", clock() - start);
}

void test_round()
{
    clock_t start = clock();
    value = 0;
    for (int i = 0; i < 1000 * 1000; i++)
    {
        value += round(((i / 1000.0) - 1.0) * 10.0);
    }

    printf("test_round: %lu\n", clock() - start);
}

int main()
{
    test_cast();
    test_round();
}

結果:

テストキャスト: 11895
テストラウンド: 14353

注: これclock()が最適なプロファイリング関数ではないことはわかっていますがround()、少なくともより多くの CPU サイクルを使用していることを示しています。

于 2012-06-27T14:59:26.460 に答える