googletag.defineSlot('/21812778492/blog_728x90_common_eyecatch01_adsence', [728, 90], 'div-gpt-ad-1566564252373-0').addService(googletag.pubads()); こんにちは!フリーランスの長野です。 割り算を行う場合、計算結果の数値の小数点以下を四捨五入したり、切り上げ・切り捨てなどの端数処理をしたいことがありますよね。 そんな時にJavaではBigDecimalクラスを使用します。 この記事では、BigDecimalクラスについて BigDecimalクラスとは 当プログラミングスクール「侍エンジニア塾」では、これまで6000人以上のエンジニアを輩出してきました。 googletag.defineSlot('/21812778492/blog_300x250_common_sidetop01_adsense', [[300, 250], [336, 280]], 'div-gpt-ad-1565330658303-0').addService(googletag.pubads()); googletag.defineSlot('/21812778492/blog_728x90_common_overlay', [728, 90], 'div-gpt-ad-1584694002281-0').addService(googletag.pubads()); googletag.defineSlot('/21812778492/blog_468x60_common_eyecatch02_adsence', [728, 90], 'div-gpt-ad-1567575393317-0').addService(googletag.pubads()); // 16進数 指数表記(-0x1.23×2の-4乗) → -0.071044921875, // → 0.5、intの5をdoubleの10で割るので、5もdoubleになり、計算結果はdoubleの0.5になる, // → 3.3333333333333335(計算上は10 / 3 = 3.333…だが、途中で打ち切られて丸められる), // コンパイルエラー!! お問合せはこちらでも受け付けています。 double(ダブル)は、小数点以下を含む幅広い範囲の数字を扱えるデータ型で、プリミティブ型(primitive、基本データ型)の一つです。一つのdoubleのサイズは64ビット(8バイト)です。doubleは「倍精度浮動小数点数」とも呼ばれます。 名前が“double”なのは、何かの「二倍」だからです。その何かとは、同じ基本データ型である32ビット(4バイト)のfloatです。doubleではfloatの倍のビット数を使って、floatよりもずっと広い範囲の数 … 0.1000000000000000055511151231257827021181583404541015625. 普通の計算方法とは違うので慣れが必要かもしれませんが、そんな場合はこの記事を何度も参考にして下さいね! googletag.pubads().collapseEmptyDivs(); googletag.cmd.push(function() { // → 123456789012345.123456789012345、情報落ちしていない!! その経験を通してプログラミング学習に成功する人は、「目的目標が明確でそれに合わせた学習プランがあること」「常に相談できる人がそばにいること」「自己解決能力が身につくこと」この3つが根付いている傾向を発見しました。 googletag.enableServices(); [email protected], 【Java入門】StringUtilsの使い方総まとめ(Apache Commons Lang). // → nullをdoubleに変換できないので、実行するとNullPointerExceptionが発生する!! 小数部の四捨五入は下記のように行えますが、 整数部の下二桁を四捨五入するには、どの様にすればよいでしょうか? 例: 60012→60000 60046→60100 // 小数の四捨五入 BigDecimal value1 = new BigDecimal("152.3"); BigDecimal value2 = new BigDecimal("273.42"); googletag.defineSlot('/21812778492/blog_300x250_common_fixed02_adsense', [[300, 250], [336, 280]], 'div-gpt-ad-1565198391774-0').addService(googletag.pubads()); }); 割り算を行う場合、計算結果の数値の小数点以下を四捨五入したり、切り上げ・切り捨てなどの端数処理をしたいことがありますよね。, BigDecimalは小数点以下の値に誤差が出ないように正確に計算するために使います。, また、小数点以下を四捨五入したり、切り上げ・切り捨てなどの端数処理を行いたい場合に使用します。, それではBigDecimalを使って小数点以下を誤差なく扱う方法や、小数点以下の端数処理を行う方法について詳しくみていきましょう!, BigDecimalのコンストラクタの引数に浮動小数点数型と文字列型どちらも指定することができます。, 正確な値を扱うためには、BigDecimalのコンストラクタの引数は文字列型で指定しましょう!, このサンプルコードではBigDecimalのコンストラクタの引数をdouble型とString型で指定しています。, 1つ目はdouble型で指定していますが、実行結果をみると誤差が発生しているのがわかります。, 一般的な浮動小数点数型の四則演算の結果とBigDecimalクラスの四則演算用のメソッドを使った計算結果を比べてみましょう。, このサンプルコードでは一般的なdouble型の四則演算とBigDecimalクラスを使った四則演算を行い、同じ式で同じ計算結果が得られるようにしています。, しかし、一般的なdouble型の四則演算の結果は0.2とは少し違って誤差が生じています。, これに対してBigDecimalクラスを使った四則演算の結果は意図通りの結果となっています。, 次に、切り捨て、切り上げの処理をする場合の実際のコードとその処理結果をみていきましょう。, 割り算で四捨五入をする場合は、2番目の引数で桁数の指定を、3番目の引数で丸め方法を指定します。, 割り算の場合、下記のように丸め処理を記述せずに割り切れない計算をすると無限小数となり、ArithmeticExceptionの例外が発生します。, BigDecimalのオブジェクトを比較する場合は、compareToメソッドを使います。, compareToメソッドでBigDecimalのオブジェクトを比較する方法についてはこちらで詳しく解説していますので、参考にしてくださいね!, BigDeciamlクラスを使って誤差なく正確に計算する方法については、次の記事にまとめているのでぜひ確認してみてくださいね!, ここでは、端数の丸め処理について小数点の桁数の指定、丸め方法の指定、四則演算の方法について説明しました。, float型やdouble型では、演算処理の過程で誤差が積み重なり、正確な値が出力されない場合もあります。, 厳密なお金の計算が必要な場合などはBigDecimalクラスを使って計算するようにしましょう。. 0.100000001490116119384765625, // → 0.1ではない!! googletag.pubads().setTargeting('blog_type', 'Tech'); © Copyright 2018ENGINEER.CLUB(エンジニアクラブ)All rights reserved. // fixed01のWORKSが不定期なため共通処理とする googletag.defineSlot('/21812778492/blog_300x250_common_sidemiddle01_adsense', [[300, 250], [336, 280]], 'div-gpt-ad-1565198726712-0').addService(googletag.pubads()); いわゆる四捨五入を行います。 負数の場合の結果は想定外かもしれません。「0.5未満を切り捨てる(0に近づける)」のではなく、「0.5より小さければ小さい整数にする(負の∞に近づける)」という、正負に依らない規則になっています。 googletag.pubads().enableSingleRequest(); googletag.defineSlot('/21812778492/blog_300x250_common_ctc02_adsence', [300, 250], 'div-gpt-ad-1566564559478-0').addService(googletag.pubads()); // BigDecimal bd3 = bd1.divide(bd2); // → 1/3は割り切れないので、java.lang.ArithmeticExceptionが発生する, // → 0.3333333333、小数点10桁まで計算、11桁目で四捨五入されている, // → 0.3333333334、小数点10桁まで計算、11桁目で切り上げされる, // → 0.1ではない!! googletag.defineSlot('/21812778492/blog_728x90_common_overlay_adsence', [728, 90], 'div-gpt-ad-1583302554779-0').addService(googletag.pubads()); 「演算子 & は引数の型 double, double で未定義です」, // → 4607182418800017408(0x3ff0000000000000), // 符号や区切り文字も含めて全体で18文字、0埋めあり、小数部は4桁目で四捨五入, // → 0100000001011110110111010010111100011010100111111011111001110111. Javaのdoubleはプリミティブ型の一つで、小数点を持つ数字を64ビットの範囲で表現できます。doubleは浮動小数点と指数表記という考え方のおかげで、およそ10の308乗というとても大きな数字から、10のマイナス324乗というとても小さい数字まで、大変広い範囲の数字を扱えます。, doubleを使えば簡単・高速に計算できますが、きちんと理解をしないままdoubleを使うと、「どうしてこの計算結果になるの?」となることもあります。特に、64ビットもあるとはいえサイズに限りがあることや、2進数によるいろいろな制限や計算上起きる誤差からは逃れられません。, だからこそ、doubleの特徴や使い方をしっかり知っているということは、数値計算がしっかりと行えるスキルがあるということです。どのような計算誤差がどのような仕組みで発生するかあらかじめ分かっていれば対策はしっかりとできますし、結果として実用上求められる精度での計算ができるのです。, この記事ではdoubleについて、そもそもdoubleとはどういうものか、doubleはどうやって使うのか、気を付けたい所などを初心者向けにお伝えします。, double(ダブル)は、小数点以下を含む幅広い範囲の数字を扱えるデータ型で、プリミティブ型(primitive、基本データ型)の一つです。一つのdoubleのサイズは64ビット(8バイト)です。doubleは「倍精度浮動小数点数」とも呼ばれます。, 名前が“double”なのは、何かの「二倍」だからです。その何かとは、同じ基本データ型である32ビット(4バイト)のfloatです。doubleではfloatの倍のビット数を使って、floatよりもずっと広い範囲の数字を表現できるのです。, 「浮動」小数点数と呼ばれるのは、数字の整数部と小数部の長さが可変なので、小数点の位置が数字に合わせてふわふわ移動するからです。一方で、固定小数点数というものも数値計算の世界にはありますが、Javaのdouble/floatは浮動小数点数です。, doubleを他のプリミティブ型と簡単に比較すると、以下のとおりです。doubleでは、もっとも広い範囲の数字を扱えることが分かるかと思います。, doubleは、ものすごく広い範囲の数字を表現できます。前述の表にもあるとおり、10の308乗というちょっとよくわからない大きさの数字や、10のマイナス324乗というこれまたすごい小さな数字を表現できます。, これほど広い範囲の数字を表現できるのは、doubleは内部で「指数表記」を使うからです。指数表記では符号、仮数、基数、指数の組み合わせで数字を表現しますが、doubleの64ビットの範囲を符号、仮数、指数それぞれに割り当てています。, 例えば、123,000は「1.23×10の5乗」です。0.0000123も同様に「1.23×10の-5乗」です。両方とも1.23×10の何乗と言っているだけで、違うのは10の乗数だけです。doubleでは大きな数字も小さな数字もこのように言い換えて、ビットを効率的に使っています。, doubleを使うと、広い範囲の数字の計算を高速に行えます。ですが、その高速さは常に誤差と引き換えです。コンピュータでの数値計算は、昔も今もこれからも、誤差との戦いです。ですから、誤差はdoubleを使う上ではいつも意識しておきたいことです。, doubleのような浮動小数点数が苦手とするのは、小数点以下の数字を正確に表現することです。これは大事なことなので必ず覚えておきましょう。doubleで小数点以下の数字を扱うと、doubleが64ビットもあるとはいえ限られたビット数しか持っていないため、誤差がどうしても発生します。, 例えば、実はdoubleでは0.1すら正確に表せません。以下のとおり、doubleの0.1を10回足しても1にはなりません。プログラム上では“0.1”と明確に書いていますが、実際のdoubleが表している数字は、0.1とはほんのちょっとだけ違う数字なのです。, この0.1との誤差は、丸め誤差というものが影響しています。doubleでは、この他にもいろいろな計算上の誤差が発生します。誤差の種類はあとで簡単に紹介しますが、どうにも計算結果が式と合わないな、という時は計算誤差を疑いましょう。計算誤差を回避するためのテクニックもいろいろあります。, Javaのdoubleは、国際的な浮動小数点数の標準規格「IEEE 754」に準拠しています。他のプログラミング言語でもIEEE 754に準拠していることが普通なので、doubleでの計算結果は他のプログラミング言語での実行結果と概ね一致します。, IEEE 754では、64ビット中のどの部分を符号、仮数、指数に使うかや、計算ルールが決められています。いろいろな理由や経緯があり、ビットパターンを作るにも少々計算が必要ですが、doubleを使う側はそれを強く意識しなくてもOKです。なお、doubleの基数は2固定なので、この64ビット中に基数はありません。, ここでは、doubleの使い方のサンプルをお伝えします。そして、doubleを使う上では注意すべきことがいくつかありますので、それらも順番にお伝えします。, doubleは型の一つですから、以下のように変数や配列変数の型として使えます。もちろんメソッドの引数や、戻り値としても使えます。, doubleの変数へ代入できる数字のリテラル(文字どおりの、という意味)は、以下のいずれかの形式で書けます。小数点以下の数字を書けるのが、intなどの整数とは違いますね。Javaでは小数点がある数字を書くと、自動的にdouble扱いになります。“_”での桁区切りもできます(Java 7以降)。, とても大きい、または小さい数字を表すなら、指数表記も使えます。指数表記にすると自動的にdoubleになります。指数表記は前述のとおり符号、仮数、指数の組み合わせなので、リテラルでも同様に書きます。指数表記でのdoubleの基数は、10(e)と2(p)を選べて、10進数と16進数へだけ使えます。, リテラルがdoubleだと明示的に表現したいなら、接尾語としてDあるいはdを付けて「これはdoubleだよ」とJavaに教えます。小数点以下がない数値リテラルは、Javaでは自動的にintになるので注意しましょう。, なお、doubleには正負の無限大(Inifinity)や非数(NaN、Not a Number)などの、特殊なものがあります。また、0にも正負の0(+0.0、-0.0)があって区別されます。これらはIEEE 754で決められているもので、普通のプログラムで意識することはあまりありませんが、あることは知っておきましょう。, フィールドとしてdouble型の変数を使ったり、double型の配列を使う場合は、未初期化だと0.0になります。他の数値型のプリミティブと同じです。, doubleを使った四則演算(加減乗除)には、四則演算用の算術演算子、つまり+-*/を使います。余りを求めるなら%です。ですので、ごく直感的に計算できるかと思います。, なお、doubleと計算した結果はdoubleになります。もう少し正確に言えば、doubleとdoubleでないもので計算をすると、doubleでないものの方が自動的にdoubleに変換(キャスト)されて計算されます。doubleが関係するキャストのルールは後述します。, 計算した結果、doubleで表現できる範囲よりも絶対値が大きくなったなら無限大(Infinity)になります(いわゆるオーバーフロー)。doubleで表現できる範囲よりも絶対値が小さくなったなら0.0になります(いわゆるアンダーフロー)。, 非数(NaN)はどんな数字とどんな計算をしてもNaNになります。この動きは、SQLでのNULLと似ていますね。, doubleでは、0での割り算(いわゆる0除算)を行ってもArithmeticExceptionはthrowされません。割られる数により結果は違い、InfinityやNaNになります。これらの結果は、NaNやInfinityへの計算も含め、浮動小数点数の計算ルールで決められています。, doubleへは直接ビット演算を行えません。Javaでのビット演算は、intなどの整数型プリミティブかbooleanにだけ定義されている計算だからです。, どうしてもdoubleが持つビットパターンへビット演算を行いたいなら、Double.doubleToLongBitsあるいはdoubleToRawLongBitsを使ってlongに変換してから行います。ちなみに、longのビットパターンからdoubleに変換するには、Double.longBitsToDoubleを使います。, double同士を比較する時は、比較演算子==を使います。==での比較では、比べる数字同士が完全に一致していなければtrueにはならず、「大体同じ」とは判断してはくれません。==が正確に比較するのは当たり前のように思えますが、これがdoubleを使う上では思わぬ罠になることもあります。, 以下の例では、本当にごくわずかしか数字が違わないdouble同士ですが、それでも==の結果はfalseです。実際の数値計算では、計算式の上では値が一致するはずだけれども、いろいろな誤差により完全に一致しないケースは普通にあり得ます。doubleの計算結果は非常に細かい数字になりうるからです。, そういうケースでは、ある程度の範囲なら数字のぶれは許容することにして、その範囲内にあれば等しいとみなすこともあります。そうしないと、実用上の計算に支障をきたすこともあるからです。, Javaでは数字のプリミティブ型として、整数(byte/short/char/long)と、小数点が扱えるもの(float/double)があります。doubleとそれらとの変換や演算の時には注意することがいくつかあります。, double以外のプリミティブ型からdoubleへのキャストでは、元のプリミティブ型が持っていた数字がdoubleへそのまま設定されます。doubleは、Javaのプリミティブ型でもっとも表現できる数字の範囲が広いので、どのプリミティブ型の数字でもdoubleで表現できるからです。, 整数型プリミティブ同士のキャストのように、キャスト先の型のサイズの分だけビットパターンが同じになるわけではありません。, doubleからdouble以外のプリミティブ型への変換は、ビット数が少なくなるので値が変わることがあります。変換方法は、変換先がfloatかlongか、それ以外かで少し異なります。, キャスト先がfloatの場合は、doubleが持っている仮数と指数がfloatで表現できる範囲に縮小されます。floatで表現できる範囲を超えていると±Infinityになります。また、doubleがNaNや±Infinityだった場合はそのままです。, キャスト先がlongの場合は、doubleで表されている数字の小数部は切り捨てられ、整数部だけをlongで表現できる範囲内で変換します。longで表現できる範囲を超えている場合は、longの±の最大値です。doubleが±Inifinityならlongの最大値・最小値になり、NaNの場合は0です。, キャスト先がlong以外の整数型プリミティブ(int/short/char/byte)の場合はlongの場合とほぼ同じですが、変換先の範囲がintになります。さらにそのintからそれぞれの型のビットサイズに応じたキャストが行われます。±InfinityとNaNの扱いはlongと同じです。以下ではintを例としています。, Stringもdoubleと並んでJavaでは重要なクラスです。Stringをdoubleにすること、またdoubleをStringにすることは、プログラムでは日常茶飯事です。ここではその方法をお伝えします。, ファイルから読み込んだ文字列や、引数で受け取った文字列からdoubleを作りたい時があります。そういう時はDouble.parseDoubleを使って文字列をdoubleに変換しましょう。doubleと解釈できない文字列の場合はNumberFormatExceptionがthrowされます。, Double.parseDoubleやvalueOfが受け付ける文字列は、リテラルのところでもお伝えした、10進数、10進数の指数表記、16進数の指数表記、非数(NaN)、±の無限大(Infinity)です。±0もきちんと区別されます。, なお、整数の2進数、8進数、16進数はDouble.parseDoubleは受け付けません。Long.valueOfの基数を指定できるメソッドでLongに変換した後、doubleValueでdoubleに変換するといいでしょう。また、longはdoubleにそのまま変換できますので、Long.parseLongの戻り値のlongをdoubleにキャストしてもいいです。, doubleをStringにしたい時も頻繁にあります。簡単に行うなら、Double.toString(double)か、String.valueOf(double)を使いましょう。ちなみに、どちらを使っても結果は同じです。, 絶対値が大きかったり、小数点以下の桁が多いdoubleを、Double.toStringやString.valueOfで文字列にすると指数表記になります。普通の書き方の10進数文字列にしたいなら、BigDecimalに変換した後、BigDecimal.toPlainStringを使うのが簡単です。, doubleを3桁区切りなどでフォーマットしたり、0埋めをしたり、小数部の四捨五入をしたい場合もあるでしょう。その場合は、java.text.DecimalFormatやString.formatなどを使います。それぞれの書式の詳細は、Javadocを参照してください。, https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/text/DecimalFormat.html, https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/String.html#format(java.lang.String,java.lang.Object…), https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Formatter.html, doubleが持つビットパターンをそのまま文字列にしたい場合は、Double.doubleToRawLongBitsまたはdoubleToLongBitsでlongに変換した後、Long.toBinaryStringで01の文字列にします。さらにString.formatとreplaceを経由しているのは、符号が正なら先頭へ0を付けたいからです。, このビットパターンはIEEE 754の倍精度浮動小数点の仕様そのままなので、IEEE 754の勉強をするのにも使えたりします。, なお、Double.doubleToRawLongBits・doubleToLongBitsの違いは非数(NaN)の扱いで、doubleToRawLongBitsはビットパターンそのまま、doubleToLongBitsは正規化された一つのNaNに変換します。, Javaでは64ビットの浮動小数点数を表現するために、doubleとDoubleの二つの方法があります。Javaプログラミングの初心者は、なぜ表し方が二つあるのか混乱すると思います。, この章ではその理由と、doubleとDoubleの使い分けの方針などをお伝えします。, Javaではプリミティブ型のdoubleと、クラスのDoubleは別物です。C#などではこういう区別がないのに、なぜJavaではあるのか。これは、Javaが生まれた当時にプログラムの実行速度を確保するためでした。, Javaは1995年に登場したプログラミング言語です。当時のCPUのクロック周波数は今とは桁が違い、一般向けのCPUでようやく100MHzを超えたくらい。メモリの量も全体で数MB~数10MBと非常に乏しかったものです。, doubleは64ビットの浮動小数点数そのものですし、コンピュータには浮動小数点数を専用に計算するハードウェアが搭載されているので、楽に速く扱えます。しかし、doubleをクラスとすると、一つのdoubleの数字に64ビット以上のメモリを使いますし、計算上でも余分なオーバーヘッドが発生します。, JavaでDoubleを使うのは、Doubleが持つメソッドを使いたい時と、値がない場合…すなわちnullを表現したい時です。例えば、SQLでは値の有り無しをNULLかどうかで表現できますが、それをJavaのdoubleでは上手に表現できません。, ですから、プログラム上では0や-1などの値に特別な意味を持たせたりするのですが、確実さには欠けます。そういう値のチェックを忘れるなどのミスもしがちです。, そういう時に参照型であるDoubleを使えば、値がないことをnullとして表現できるのです。Doubleをどういう時に使うか分からない方は、その変数でnullを表現する必要があるかを一つの指針にしてみてください。, Java 1.5でオートボクシング(auto boxing)という仕組みが導入されました。オートボクシングで、doubleとDoubleをプログラム上でほぼ同じものとして扱えます。, プログラム上でdoubleを使う所ではDoubleを使えますし、Doubleを使う所ではdoubleが使えます。本当のプログラム上は相変わらずdoubleとDoubleは別物なのですが、その違いをJavaが裏で自動的に変換をしてくれるのです。, これでJavaの面倒な部分がある程度解消されました。ですが、前述のとおりDoubleはnullを表せますが、doubleは必ず何かの整数なので、nullに相当するものがありません。, ですので、以下のように予期せぬところでNullPodoubleerExceptionが発生したりします。これは2019年のJava 11の時点でも変わっていません。プログラマが注意するか、Optionalを使う必要があります。, doubleのような浮動小数点を使った計算では、いろいろな誤差に気を付ける必要があります。誤差が出る理由は、doubleが2進数であることと、数字に使えるビット数、特に仮数が有限であることが主な原因なのですが、ここでは具体例を挙げて説明してみます。, これらの内容を正確に理解するには、数値計算を行う時の「有効数字(有効桁数)」と浮動小数点数の「正規化」という考え方の知識が前提となります。有効数字や正規化の考え方は、以下などを参考にしてください。, 本来表したい数字と実際の数字に、数字に使える桁数のせいで差が出ることを「丸め誤差」や「打切り誤差」と呼びます。先述のとおり、doubleでは1/10=0.1を正確に表せません。0.1は2進数だと循環小数ですが、doubleは有限なので、どこかで四捨五入などで丸めるか、打ち切らなければならないのです。, doubleだと途中で打ち切られ0.1000000000000000055511151231257827021181583404541015625になる, 数字はコンピュータ上では2進数になります。2の倍数とその合計で表す2進数では、10進数できっちり表せる小数でもそのまま表せないものがほとんどです。正確な計算が必要なら、二進化十進数(BCD、Binary-coded decimal)のクラスや、有理数のまま計算できるクラスなどを使う必要があるかもしれません。, なお、丸め誤差/打切り誤差は2進数だけではありません。例えば、1/3は10進数で0.333…ですが、有限の桁で表すなら無限に続く3をどこかで終わらせます。そして、1/3とどこかの桁で終わった0.333…は違うものです。これと理屈は同じで、コンピュータは2進数がベースなだけです。, 近い数字同士を引き算した結果、数字の有効数字(有効桁数)が少なくなることを桁落ちと言います。誤差を考慮した計算では、このような計算が途中でされないようにしなければなりません。, 以下の例では2つの数字両方で有効数字は15桁で、小数部15桁目に1だけ差があります。d1とd2を引き算すると10進数では0.000000000000001で、正規化すると1e-15となり、有効数字は15桁から1桁へ一気に減ります。, 実際のdoubleでの計算結果は、2進数への変換誤差のため1e-15ちょうどにはならず、ごくわずかに小さな数字です。そして、計算結果の有効数字は16桁あるように見えますが、計算に使ったdoubleの有効数字より小さい数字なので、計算上で意味がある数字ではありません。, 桁落ちが問題なのは、不確かな数字が計算途中に出現することにより、以後の計算結果に大きな影響を与えるからです。, 例えば、途中の計算結果で1.000e-3という数字が出たとして、仮数の0の部分が本当に0か、桁落ちによる正規化で埋められた0かはわかりません。もし、計算上でこの数字を使うなら、この不確かな0がずっと付きまとうのです。, doubleで計算をすれば何らかの数字は出て来ます。でも、その数字にどれだけ意味があるかの観点は、プログラマが強く意識すべきことです。そして、桁落ちも2進数特有の事象ではないことは知っておきましょう。, 情報落ちとは、絶対値が大きく違う数字同士で計算をすると、絶対値が小さな方の数字がなくなってしまう現象です。桁落ちよりは計算誤差への影響は少ないですが、できるだけ避けるべきものなのは変わりません。, 例えば、以下の足し算では、d1とd2ともに15桁分の有効桁数があります。この二つの数字を足し合わせても、紙で計算したとおりの123456789012345.123456789012345とはならず、123456789012345.12になりました。ということは、d2の方の小数点第3位以下の数字がなくなっていますよね。, こうなる理由は、浮動小数点数での仮数には桁数の制限があるからです。doubleの仮数には、この例での紙で計算した場合の30桁におよぶ有効数字を表せる桁数がありません。ですから、1.2345678901234512までが、この計算結果をdoubleの仮数で表現できる限界だったということですね。, 情報落ちが問題になるのは、大きな数字と小さな数字を連続して計算する時です。以下の例では、前者では0.001×10=0.01が計算結果に(誤差は出つつも)反映されていますが、後者では未反映です。基本的には、前者のように小さな値をまとめて先に計算して、その後に大きな値と計算して回避します。, 正確な数字の表現や計算を行うなら、Javaではjava.math.BigDecimalを使います。ここまでに例として挙げてきた誤差が出る計算も、正確に計算できます。ただ、計算速度はdouble/floatを使う場合よりもどうしても遅くなりますので、要件に応じて使い分けましょう。, 正確な計算に必要なスケール(小数点以下の桁数)は自動的に判断されますが、任意のスケールや丸め方法を指定することもできます。特に、割り算をする時はどこまでのスケールが必要か指定しないと、割り切ることが出来ない場合などに計算を終えられず、エラーになります。, なお、doubleやfloatなどの浮動小数点のプリミティブ型を使ってBigDecimalを生成すると、以下のように浮動小数点数が実際に持っている数字になってしまいます。BigDecimalで正確に数字を表現したいなら、Stringのコンストラクタを使うのが無難です。, この記事では、Javaのdoubleをお伝えしてきました。Javaのdoubleは64ビットの浮動小数点数で、大きな整数から小さな小数点以下の数字まで、大変広い範囲の値を表現できます。doubleはJavaで小数点以下の数字を使う時の標準ともいえるデータ型で、詳細は国際規格のIEEE 754で決められているものです。, Javaでは、doubleとして扱えるものにはプリミティブ型のdoubleと、クラス(参照型)としてのDoubleの二種類があり、それらは違うものであることには注意しましょう。ただ、オートボクシングにより違いが見えにくくはなっています。, doubleは、コンピュータで2進数を扱うことの限界・注意点がよくわかるデータ型でもあります。それらの注意点はどのプログラミング言語でも同じですので、Javaでdoubleの使い方をしっかり学んでおけば、他のプログラミング言語でもそう大きな違いなく使えるでしょう。, 特に有効数字や誤差の概念、計算上で発生する問題への対応方法を身に着けておけば、いざという時に役に立つかもしれません。計算は苦手だなぁという方も、考え方だけはしっかり覚えておくと、違いの分かるプログラマとして一目置かれるかもしれませんよ。, 私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。, まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。, この道一筋20年。情報システムについてなら、構築・運用・保守、なんでもござれなエンジニア。システムやデータベースの設計、ソースコードの品質には一家言あり。気持ちはまだまだ若いので、若い世代のエンジニアと一緒に成長していきたい。, 次回のコメントで使用するためブラウザーに自分の名前、メールアドレス、サイトを保存する。.