私は最近、コードの一部で数学の論理を困惑させているように見えるものに出くわしました
if((123/1000) > 0)
何らかの理由で、C#はこれは誤りであると主張していますが、論理的に考えると、0.123は0よりも大きくなります。
0.123が0より小さいと主張している理由はありますか?
2を底とするdoubleとの比較の問題があり、10を底とするdecimalを使用する方がよいことを読みました。
誰かが私を教えてもらえますか?
あなたの誤謬は、結果がそうであるの0.123
に対して、結果はそうであると思うということです0
。
C#(および他の多くのCのような言語)は、2つの整数を含む操作は常に整数1 + 1
を返すため2
、ではなく2.0
、3 / 2
を返し1
、ではなくを返すことを定義してい1.5
ます。この場合の小数部分は単純に破棄されるため、常にゼロに向かって丸められます(つまり、正の結果の場合は切り捨てられ、負の結果の場合は切り上げられます)。
これはおそらく少し直感に反しますが、これの主な理由は、言語/コンパイラの単純さ、実行速度(結果のタイプを把握する必要がないため)、次のような演算子を使用する機能/=
です。結果は別のタイプでした)そして歴史的な遺産と慣性。
これを解決するには、オペランドの少なくとも1つを浮動小数点数にする必要があります(他のオペランドは、結果と同様に自動的に追跡されます)。
// either
if (123.0 / 1000 > 0)
// or
if (123 / 1000.0 > 0)
// or
if (123.0 / 1000.0 > 0)
代わりに変数がある場合は、型キャストが必要になる場合があります(単純に追加することはできないため.0
:-)):
if ((double)a / b > 0)
また、ここでも通常のアドバイスが当てはまります。コンピューターは奇妙なマシンであり、プログラミング言語はさらに奇妙な場合があるため、プログラミングの際に直感を信頼することはめったにありません。結果をどこかに出力するか、変数に割り当ててデバッガーをチェックインすると、期待がずれていることがわかります:-)
123と1000は整数であり、結果は1未満であるため、0に丸められます。次を使用します。
123.0/1000.0 > 0.0
そしてそれは倍精度を使用します、すなわちあなたは分数を持つことができます!
これは答えられましたが、誰もこの問題について良い見解を示していないので、私はそれをより明確にしたいと思いました:
あなたがまたはであるdividing
場合multiplying
int
、float
次のような結果が得られます。
int/int => int
float/int => float
int/float => float
したがって、分割する場合:
123/1000 => 0 (as there is no int number 0.123, it will then set to 0)
123.0/1000 => 0.123 (this dividing is basically saying that I need a float result of dividing)
123/1000.0 => 0.123 (this says the same as previous)
したがって、ルールは基本的に、使用されているタイプよりも「上位」レベルのタイプを使用している場合、計算はその「親」タイプに変換されます。しかし、これは一般的には言えません。浮動小数点型が使用されているかのように、常に浮動小数点数に転送されます。その他の例は次のとおりです。
long/int => long
double/float => double
double/int => double
そして、あなたがあなたの質問に対する答えを持ちたいのなら、答えは次のようになります:
if(((float)123/1000) > 0)
また
if(((double)123/1000) > 0)
したがって、常にフロート数(0.123数)を計算します
int / int
はint
-です。これは、期待どおりで123/1000
は0
なく、そうであることを意味します-0.123
0は0より大きくないため、式はfalseと評価されます。
修正は、整数の1つをdoubleとして作成することです-
if(123.0 / 1000 > 0) <- true
if(123 / 1000.0 > 0) <- true
if(123.0 / 1000.0 > 0) <- true
これを使って:
if((123.0/1000) > 0)
をで割ろうとしてint
いint
ます。したがって、整数除算が得られます。ただし、doubleを使用する必要があります。
また、int変数を分割して二重に取得する場合は、次のように使用します。
double doubleNum = (double)intNum1/(double)intNum2;
整数値のみで除算を行うと、結果も整数になります。
小数点以下の部分を正しく思い出せば。
したがって、コードは次のようなものにコンパイルされます。
a = int(123/1000) <--- evaluates to 0.
if (a > 0) .... <--- false
@algreatの回答による解決策は、オペランドの1つを強制的にdoubleにすることです(.0
。を追加することにより、結果も強制的に浮動させます。