このコードブロックの場合:
int num = 5;
int denom = 7;
double d = num / denom;
の値はd
です0.0
。キャストすることで強制的に動作させることができます:
double d = ((double) num) / denom;
しかし、正しいdouble
結果を得る別の方法はありますか?何が起こるかを知っているプリミティブをキャストするのは好きではありません。
このコードブロックの場合:
int num = 5;
int denom = 7;
double d = num / denom;
の値はd
です0.0
。キャストすることで強制的に動作させることができます:
double d = ((double) num) / denom;
しかし、正しいdouble
結果を得る別の方法はありますか?何が起こるかを知っているプリミティブをキャストするのは好きではありません。
回答:
double num = 5;
それはキャストを避けます。しかし、キャスト変換は明確に定義されていることがわかります。推測する必要はありません。JLSを確認してください。intからdoubleへの変換は拡大されます。§5.1.2から:
プリミティブ変換を拡大しても、数値の全体的な大きさに関する情報は失われません。
[...]
intまたはlong値をfloatに変換したり、long値をdoubleに変換したりすると、精度が失われる可能性があります。つまり、値の最下位ビットの一部が失われる可能性があります。この場合、結果の浮動小数点値は、IEEE 754の四捨五入モード(§4.2.4)を使用して、整数値を正しく丸めたものになります。
5はdoubleとして正確に表現できます。
1.0
も、結果のタイプは変わります。「汚いコードのようです」は、どのシナリオで乗算を行う1.0
ほうが実際に優れていると考えているのか(またはなぜそうなのか)を説明していません。
(double)num
何らかの形で変更を行うという誤った信念(「変数の型の変更」と言う)の下で苦労しているようですnum
。それはしません-それはステートメントのコンテキストのために一時的なdoubleを作成します。
プリミティブのキャストの何が問題になっていますか?
何らかの理由でキャストしたくない場合は、
double d = num * 1.0 / denom;
double d = num * 1D / denom;
何が起こるかを知っているプリミティブをキャストするのは好きではありません。
なぜプリミティブをキャストするのに不合理な恐れがあるのですか?をにキャストしint
ても問題はありませんdouble
。動作がわからない場合は、Java言語仕様で調べてください。int
toのキャストdouble
は、拡張プリミティブ変換です。
分子の代わりに分母をキャストすることで、括弧の余分なペアを取り除くことができます:
double d = num / (double) denom;
double d = (double) num / denom;
...(OK、これは優先順位に依存します)
整数または整数の両方を浮動小数点にキャストして、演算を浮動小数点演算で強制的に実行します。それ以外の場合は、常に整数Mathが推奨されます。そう:
1. double d = (double)5 / 20;
2. double v = (double)5 / (double) 20;
3. double v = 5 / (double) 20;
結果をキャストしても機能しないことに注意してください。優先ルールに従って最初の除算が行われるためです。
double d = (double)(5 / 20); //produces 0.0
あなたが考えているようなキャストには問題はないと思います。
double
整数除算からaを生成する- キャストしないと他に方法はありません(明示的には行わないかもしれませんが、起こります)。
今、私たちは正確に取得しようとすることができ、いくつかの方法がありますdouble
(値num
とdenom
しているint
タイプ、のコースキャスティングとは) -
明示的なキャスト:
double d = (double) num / denom;
double d = ((double) num) / denom;
double d = num / (double) denom;
double d = (double) num / (double) denom;
だがしかし double d = (double) (num / denom);
暗黙的キャスト:
double d = num * 1.0 / denom;
double d = num / 1d / denom;
double d = ( num + 0.0 ) / denom;
double d = num; d /= denom;
でもそうでもdouble d = num / denom * 1.0;
ないdouble d = 0.0 + ( num / denom );
操作をラップすることを検討してください。例えば:
class Utils
{
public static double divide(int num, int denom) {
return ((double) num) / denom;
}
}
これにより、キャストが期待どおりに動作するかどうかを(一度だけ)調べることができます。このメソッドは、テストの対象となる可能性があり、希望どおりの動作を継続することを確認します。また、正しい結果が得られる限り、除算を行うためにどのトリックを使用するかは関係ありません(ここで任意の答えを使用できます)。2つの整数を除算する必要のある場所ならどこでも、呼び出しUtils::divide
て、それが正しいことを信頼することができます。