BigDecimalを用いても四捨五入されません。

投稿者: Anonymous

以下のコードをAndroid Studioで一応実行することはできるのですが、calorie に対して BigDecimal で setScale をしているにもかかわらず、四捨五入されずに小数点以下5桁くらいまで表示されてしまっています。

calorie を求めるにあたって weight, height, age は BigDecimal での計算はしていません。最終的に求まる calorie に対して BigDecimal で setScale をしたら四捨五入されるという認識でいました。

import android.os.Bundle;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.math.*;


public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

    // 決定ボタン
    public void onClickButton(android.view.View view) {
        TextView calorieForm = this.findViewById(R.id.calorieForm);
        TextView proteinForm = this.findViewById(R.id.proteinForm);
        TextView carbonForm = this.findViewById(R.id.carbonForm);
        TextView fatForm = this.findViewById(R.id.fatForm);
        EditText ageForm = this.findViewById(R.id.ageForm);
        EditText weightForm = this.findViewById(R.id.weightForm);
        EditText heightForm = this.findViewById(R.id.heightForm);

        // Spinnerオブジェクトを取得
        Spinner spinner = findViewById(R.id.spinnerSex);
        Spinner spinner1 = findViewById(R.id.活動レベルForm);

        // 選択されているアイテムを取得
        String item = (String)spinner.getSelectedItem();
        String item1 = (String)spinner1.getSelectedItem();


        String strAge;
        strAge = ageForm.getText().toString();
        String strWeight;
        strWeight = weightForm.getText().toString();
        String strHeight;
        strHeight = heightForm.getText().toString();

        double protein, carbon, fat, age, weight, height;
        age = Double.parseDouble(strAge);
        weight = Double.parseDouble(strWeight);
        height = Double.parseDouble(strHeight);

        // case文で処理したい
        double calorie = 0;
        BigDecimal bd = BigDecimal.valueOf(calorie);
        bd = bd.setScale(1, BigDecimal.ROUND_HALF_UP);      /* 左辺のbdが黒文字化?反映されていない */


        if (item.equals("男性") && item1.equals("ほぼ運動しない")) {
            calorie = (13.397 * weight + 4.799 * height - 5.677 * age + 88.362) * 1.2;
        } else if (item.equals("男性") && item1.equals("軽い運動をしている")) {
            calorie = (13.397 * weight + 4.799 * height - 5.677 * age + 88.362) * 1.375;
        } else if (item.equals("男性") && item1.equals("中程度の運動をしている")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.55;
        } else if (item.equals("男性") && item1.equals("激しい運動をしている")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.725;
        }  else if (item.equals("男性") && item1.equals("非常に激しい運動をしている")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.9;
        }  else if (item.equals("女性") && item1.equals("ほぼ運動しない")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.2;
        }  else if (item.equals("女性") && item1.equals("軽い運動をしている")) {
            calorie = (13.397 * weight + 4.799 * height - 5.677 * age + 88.362) * 1.375;
        } else if (item.equals("女性") && item1.equals("中程度の運動をしている")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.55;
        } else if (item.equals("女性") && item1.equals("激しい運動をしている")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.725;
        }  else if (item.equals("女性") && item1.equals("非常に激しい運動をしている")) {
            calorie = (9.247 * weight + 3.098 * height - 4.33 * age + 447.593) * 1.9;
        }
        protein = weight * 2.3;
        carbon = weight * 2.65;
        fat = weight * 0.9;


        String msg0 = calorie + "cal";
        String msg1 = protein + "g";
        String msg2 = carbon + "g";
        String msg3 = fat + "g";

        calorieForm.setText(msg0);
        proteinForm.setText(msg1);
        carbonForm.setText(msg2);
        fatForm.setText(msg3);
    }

解決

こんにちは、はじめまして。

BigDecimalは大きな数値を精度をコントロールして利用するためのクラスになり、通常の数値型に代替するものではありません。

https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html
https://techacademy.jp/magazine/18597

浮動小数点の精度により丸め誤差が生じるため存在します。僕の分野ではあまり使うことはないですが、精度を予測内に収めたい場合などには便利そうですね。

上のtechacademyからの引用ですが下記のように扱います。

BigDecimal b1 = new BigDecimal("3.1415");
BigDecimal b2 = new BigDecimal("9.9");
BigDecimal b3 = b1.multiply(b2);

すべての値をBigDecimalにして上記のようにメソッドで演算すれば目的の結果が得られるはずです。

ですがコードの目的は小数点1桁で四捨五入をして結果を表示したいという点ではないでしょうか?
weight,heightなどがdoubleと仮定して下記の式を小数点1桁で丸めるとすると下記の二つの例が考えられます。

calorie1. 10倍したものを四捨五入して、割りなおす。四捨五入にはMath.round命令を用います。
calorie2. 出力時に文字列にするのでその時点でString.formatする(仕様上、自動的に四捨五入されます)。

import java.lang.Math;

public class MyClass {
    public static void main(String args[]) {
      double weight = 65.23;
      double height = 171.15;
      double age = 28.45234;

      double calorie1 = (Math.round(((13.397 * weight + 4.799 * height - 5.677 * age + 88.362) * 1.2)*10))/10.0;
      System.out.println("calorie=" + calorie1);
      double calorie2 = (13.397 * weight + 4.799 * height - 5.677 * age + 88.362) * 1.2;
      System.out.println("calorie=" + String.format("%.1f",calorie2));
    }
}

参考 URL :
https://blog.apar.jp/program/8900/
http://hensa40.cutegirl.jp/archives/5620

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *