どうしたの?18
どちらの場合も整数の結果にならないのはなぜですか?
問題は、浮動小数点式の結果が整数値に変換されるときにゼロに向かって丸められることです (どちらの場合も)。
0.1
浮動小数点値として正確に表すことはできません (両方の場合)。コンパイラは、バイナリ IEEE754 浮動小数点数への変換を行い、表現可能な値に切り上げるか切り下げるかを決定します。次に、プロセッサは実行時にこの値を乗算し、結果を丸めて整数値を取得します。
わかりましたが、 と の両方がそのようdouble
にfloat
動作するのに、なぜ18
2 つのケースのいずれかになるのに17
、もう一方のケースになるのでしょうか? よくわかりません。
コードは関数の結果0.1f
(float) を取得20 * (1.0 - 0.1f)
し、どちらが double 式で、20 * (1.0f - 0.1f)
は float 式であるかを計算します。float バージョンはたまたま よりわずかに大きく、18.0
に切り捨てられますが18
、 double 式は よりわずかに小さく18.0
、 に切り捨てられ17
ます。
IEEE754 2 進浮動小数点数が 10 進数からどのように構成されているか正確にわからない場合、コードに入力した 10 進数よりわずかに小さいかわずかに大きい場合は、ほとんどランダムです。したがって、これを当てにしてはいけません。f
数値の 1 つに追加して、「今は機能するので、そのままにしておきます」と言って、このような問題を修正しようとしないでくださいf
。別の値が再び異なる動作をするためです。
式の型が this の優先度に依存するのはなぜf
ですか?
これは、C および C++ の浮動小数点リテラルがdouble
デフォルトの型であるためです。を追加するf
と、フロートになります。浮動小数点式の結果は「より大きな」タイプです。double 式と整数の結果は依然として double 式であり、int と float は float になります。したがって、式の結果は float または double のいずれかになります。
わかりましたが、ゼロに丸めたくありません。一番近い数字に丸めたい。
この問題を解決するには、結果を整数に変換する前に、結果に半分を追加します。
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()) + 0.5);
C++11 にはstd::round()
、そのための機能があります。標準の以前のバージョンでは、最も近い整数に丸める関数はありませんでした。(詳しくはコメントをご覧ください。)
持っていない場合はstd::round
、自分で書くことができます。負の数を扱うときは注意してください。整数に変換する場合、数値は切り捨てられます (ゼロに向かって丸められます)。つまり、負の値は切り捨てではなく切り上げられます。したがって、数値が負の場合は半分を引く必要があります。
int round(double x) {
return (x < 0.0) ? (x - .5) : (x + .5);
}