質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

Java電卓の小数の計算がズレます

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,915

score 47

電卓をつくっています。
少数の計算が微妙にズレて正しく結果が表示されません。

例えば、
5.3 + 2.3 = 5.9999999...
7.3 + 2.5 = 9.80000000...
このように、微妙にズレて結果がだされてしまい困っています。

希に、
6.3 + 2.3 = 8.5
など、ちゃんと結果を出してくれることもあります・・・。

プラスするところのコードはこんな感じです

  if (kigou1.equals("+")) {//プラスが押された場合ここに入る
     suuji1 = mae + Double.valueOf(textView.getText().toString()); //前回入力した数値に、今テキストビューにある数字を足す。結果をsuuji1に入れる。
     bbb = new BigDecimal(suuji1); //suuji1をBigDecimalに変換
     textView.setText(String.valueOf(bbb)); //結果をテキストビューに表示
     mae = suuji1; //結果を「前回入力した数値」にいれる

よろしくお願いします。

-----------------------追記-------------------------------
(返信コメントのコピペですが失礼します)

ご回答、ありがとうございます。
BigDecimalは使い方がDoubleにくらべ難しいのでDoubleからBigDecimalに変換する。
という形で使ったのですが、すべてBigDecimalにしないとよろしくないみたいですね。

BigDecimalを使って新しく書き直してみたのですが、
比較の仕方がイマイチわからないのでつまっています。よろしければそちらも教えていただけないでしょうか。
BigDecimal mae = BigDecimal.ZERO
if (mae == 0){   //ビッグデシマルのmaeが0の時、ここに入る
}
上記のようなことをやりたいのですが、うまくいきません。
他にも
if(mae.equals(0))
もやってみましたがうまくいきません。
BigDecimalの比較方法に、compareToというのもあるようですが
型同士で比較するモノみたいですので、ここで使うのは違う気がする・・・
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

浮動小数点形式では10進数の小数を正確に表現できません。BigDecimalを使って計算してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/11/19 11:42

    ご回答、ありがとうございます。
    BigDecimalは使い方がDoubleにくらべ難しいのでDoubleからBigDecimalに変換する。
    という形で使ったのですが、すべてBigDecimalにしないとよろしくないみたいですね。

    BigDecimalを使って新しく書き直してみたのですが、
    比較の仕方がイマイチわからないのでつまっています。よろしければそちらも教えていただけないでしょうか。
    --------------------------------------------------------

    BigDecimal mae = BigDecimal.ZERO
    if (mae == 0){ //ビッグデシマルのmaeが0の時、ここに入る
    }

    --------------------------------------------------------
    上記のようなことをやりたいのですが、うまくいきません。
    他にも
    if(mae.equals(0))
    もやってみましたがうまくいきません。
    BigDecimalの比較方法に、compareToというのもあるようですが
    型同士で比較するモノみたいですので、ここで使うのは違う気がする・・・

    お返事いただけたら幸いです。

    キャンセル

  • 2015/11/19 11:49 編集

    数値を、オブジェクトを要求する場所に入れた場合、オートボクシングによりIntegerなどに変換されます。
    BigDecimalのequalsは同じ値・スケールを持つBigDecimalが引数に渡った場合のみtrueを返すので、Integerなどが相手では比較できません。
    0と比較したいのならintValue()でintを引き出して比較するという方法が考えられますが、長すぎる場合は下位32ビットが返ってくる仕様なので、2^32以上の2の累乗の場合は上手く行かないでしょう。
    他にはBigDecimal.valueOfで数値をBigDecimalに変換してequals比較するくらいでしょうか。つまりご提示の例なら
    if(mae.equals(BigDecimal.valueOf(0)){
    }

    キャンセル

  • 2015/11/19 14:00

    解説付きでありがとうございます!
    ふつうにValueOfでやればよかったですね・・・
    慣れないクラスでうっかりしていたようです。
    無事解決できました!ありがとうございます!

    キャンセル

+2

10 / 3 * 3 は bigdecimal を使っても 10 にはならないと思います (多分)
10/3 は無限桁の小数だからです。
分数として計算をすれば、 10 になります。
ruby には Ratinal クラスとして、分数を扱えるクラスがあります。
java にあるかは知りません。
私は Scala で 分数で計算できるクラスを作ったことがあります。
https://github.com/katoy/scala_rational
https://github.com/katoy/node-rational (←はnode.js 版)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/11/18 22:08

    それは熱いですね!
    却下されてしまったのは残念です。。

    キャンセル

  • 2015/11/19 11:49

    ご返信ありがとうございます。
    BigDecimalを使うだけでなく、丸めるという動作も必要なんですね。
    ひとまず、正常な動きが作れたら試してみたいと思います!

    BigDecimalについてなのですが、使っていて比較の仕方もわからなくなってしまいました。
    質問内容は、記事を編集して追記しましたのでよろしければそちらの回答もお願いしたいです。
    よろしくお願い致します。

    キャンセル

  • 2015/11/19 13:58

    丸める動作も正常にできました!
    気付かずスルーするとこでした。ありがとうございます!

    キャンセル

checkベストアンサー

0

floatやdoubleのような浮動小数点形式は2進数の組み合わせで数値ができています。
なので、小数によっては無限小数になることもあります。
その値を組み合わせると、誤差が生じるのです。

BigDecimalは、整数と10の-n乗で成り立っていて、整数で計算するので誤差が生じないという仕組みです。
floatやdoubleに比べれば処理性能は遅いですが、精度を求めるのであればBigDecimalを使うしかないのです。


追記の回答試したコード
public class Aa {

    public static void main(String[] args) {
        BigDecimal mae = new BigDecimal(1.0);
        mae.setScale(4, BigDecimal.ROUND_HALF_UP);
        
        if (BigDecimal.ONE.compareTo(mae) == 0) {
            System.out.println("one");
        } else {
            System.out.println("not");
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/11/19 11:51

    ご返信、ありがとうございます。
    仕組みまで教えて頂き恐縮です。Doubleからの途中変換もあまりよろしくなかったみたいですね。

    キャンセル

  • 2015/11/19 12:08

    追記の答え

    if (BigDecimal.ZERO.compareTo(mae) == 0 ) {

    }
    これで比較はできます。

    キャンセル

  • 2015/11/19 13:59

    compareToでもできるんですね。
    ZEROと比較できるとは参考になります。
    ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る