2012-05-11 16 views
2

私はこのコード奇妙な行動

#include <stdio.h> 
#include <math.h> 

static double const x = 665857; 
static double const y = 470832; 

int main(){ 
    double z = x*x*x*x -y*y*y*y*4 - y*y*4; 
    printf("%f \n",z); 
    return 0; 
} 

これの真の解決策は、方程式であるを持っているが、1としては、すでに自分で前の質問に答えている、このコードがあるため、壊滅的なキャンセルの失敗します。しかし、今私はさらに奇妙なことを見つけました。私が知っている限り、彼らはダブルスよりも狭い範囲を持っている間、あなたは長いロングを使用する場合に機能します。どうして?

+0

[倍精度の奇妙な動作の可能な重複。説明が必要](http://stackoverflow.com/questions/10505411/double-precision-strange-behaviour-need-an-explanation) –

+0

これは重複していません。私はすでにこれが自分自身が尋ねた同様の問題の第2の問題だと指摘しました。 – bluehallu

答えて

4

long longの範囲は小さいが、精度よりもdoubleである。

しかし、これはここではうまくいきません。計算は実際にはlong longの範囲を超えていますが、システム上で整数のオーバーフローが処理されるため、正しい結果が得られません。 (符号付き整数オーバーフローの動作はC標準では固定されていませんが、通常はここに示すように動作します)。

代わりに中間結果x*x*x*xを調べると、doubleを使用して計算すると分かりやすい値になります。正確ではありませんが、ほとんどの目的のために丸められています。しかし、それをlong longで計算すると、オーバーフローのために最初に表示された番号を見つけることになります。

+1

これについて少し詳しく説明します:_unsigned_整数型の算術は、乗算、加算、減算のみを含む計算結果が2^BITS_IN_TYPEのモジュロであるように、標準によって定義されます。一般的に、符号付き(2の補数)整数のオーバーフローがラップアラウンドの振る舞いを持つ場合、符号付きの型でも同じことが成り立ちます(ただし、繰り返しますが、符号付き整数のオーバーフローは標準では定義されていません)。 –

0

浮動小数点型のオーバーフローは、言語と環境によって、未定義またはエラーとみなされる可能性があります。積分型のオーバーフローは単純に折り返されます(時には正しい結果が得られないこともありますが、時には正しくない場合もあります)。

+1

符号付き整数型のオーバーフローは未定義です。浮動小数点型のオーバーフローは、実装が一般的なIEEE-754に準拠する場合に完全に定義されます。 –

1

倍数には、仮数と指数のビットがあります。大きい倍数の場合、2つの倍数(同じ指数、仮数に1を加えたもの)の距離は1よりはるかに大きくなります。したがって、あなたは無限+ 1 =無限と同じ状況になります。

long longはオーバーフローし、モジュロ2 "を計算します。その結果、1になるべき結果は実際には1になります。

+1

標準では、符号付きの型の算術が2^nのモジュロで行われることは保証されていません(最も一般的な動作ですが)。符号付き型のオーバーフローは未定義です。 –

+0

@StephenCanon:良い点; Javaではモジューロに定義されていますが、Cではそのようなことを回避する必要があります。 C環境はより異機種であるため、コンパイラベンダーやプラットフォームが増えています。 –