読者です 読者をやめる 読者になる 読者になる

kojiko-android’s blog

開発中にハマった時の解決策や、忘れがちなことを残しておきます。

【電卓アプリを作るvol.6】計算結果を成型する

Android Studio Androidアプリ 開発

前回まで・・・
とりあえず、必要最低限の電卓ができました。
今回は、計算結果を丸めて表示する機能を実装します。

現状の問題点

今の段階では、1+1=の結果が、

"2.0" (シンプルに "2" でいいんじゃない?)

また、10÷6のように割り切れない計算をすると
桁数が非常に多くなってしまううえ、

"1.6666666666666667"

というふうに、最後が謎の7になっています。
これはコンピューター上の仕様のようですが、
一般的には、「6が永遠と続く」という認識なので、
ユーザーからしたら不具合かと思われかねません。

そこで、一般的な電卓に習い、12桁までの表示にするとか、
小数点以下n位までの表示にする、
といった機能を実装していきます。

一般電卓の多くは、「小数点セレクター」「ラウンドセレクター」
という機能があり、
「小数点セレクター」は、小数点以下第何位まで表示するか、
「ラウンドセレクター」は、小数点セレクターで設定した位置に丸める際、
切り上げか、切捨てか、四捨五入するかなどを設定できる機能です。
カシオ計算機のサイトなどで使い方が詳しく載っています。
今回の実装ではこれらの機能をお手本にしているので、
理解度を高めるためにも、一度ご覧になることをオススメします。

自作のRoundSelectorクラス

Calcから送られてきた文字列を、成型した文字列に変換するクラスです。
引数に、計算結果のdouble、小数点の位置、丸めの方法を定数で指定します。
テキストビューにセットする前にフィルターを挟むように使います。
静的メソッドとして定義しました。

public class RoundSelector {

    public static final int POINT_5 = 5,POINT_4 = 4,POINT_3 = 3,POINT_2 = 2,POINT_1 = 1,POINT_0 = 0;
    public static final int ROUND_F = 10,ROUND_CUT = 11,ROUND_UP = 12,ROUND_5_4 = 14;

    public static String conversion(double value, int point, int round){
        String string;

        BigDecimal bd = new BigDecimal(value);

        int mode = 0;
        switch (round){
            case ROUND_F:
                return bd.toString();
            case ROUND_CUT:
                mode = BigDecimal.ROUND_DOWN;
                break;
            case ROUND_UP:
                mode = BigDecimal.ROUND_UP;
                break;
            case ROUND_5_4:
                mode = BigDecimal.ROUND_HALF_UP;
                break;
        }

        BigDecimal bigDecimal = bd.setScale(point,mode);
        string = bigDecimal.toString();
        Log.d("hogehoge","bd =" + bigDecimal.toString() );
        
        return string;
    }

    public static String conversion(String value,int point,int round){
        return conversion(Double.parseDouble(value),point,round);
    }

    public static String formatBasic(String string){

        DecimalFormat df1 = new DecimalFormat("#,##0.############");
        return df1.format(Double.valueOf(string));

    }

}

メインアクティビティの、Calcからのコールバックで送られてくる文字列に対して、
RoundSelectorを適用します。

calc = new Calc();
calc.setListener(new Calc.Callback() {
            @Override
            public void onTextChanged(String string) {
                displayView.setText(string);
                Log.d("hoge", RoundSelector.conversion(string,0,RoundSelector.ROUND_CUT));
                Log.d("hoge", RoundSelector.conversion(string,3,RoundSelector.ROUND_CUT));
                Log.d("hoge", RoundSelector.conversion(string,5,RoundSelector.ROUND_5_4));
                Log.d("hoge", RoundSelector.conversion(string,3,RoundSelector.ROUND_F));
            }
        });

10÷6は、以下のような結果となります。

D/hoge: 1
D/hoge: 1.666
D/hoge: 1.66667
D/hoge: 1.6666666666666667406815349750104360282421112060546875

ただし、現段階ではコールバックで送られてくるテキスト全てに適用しているので、
ユーザーが少数を入力した際も丸められてしまいます。
テキストが、入力中なのか、計算の答えとして送られてきたものなのか、
判別する処理が必要です。
私の場合は、State.getStateValue()で得られる定数がSTATE_D(答えを表示している状態)
であれば数値の文字列を成型するように修正しましたが、
もっといいやり方もあると思うので、
独自の実装をしてみてください。


端数処理方法の設定として、

・小数点以下の桁数
・丸める方法

の定数を、SharedPreferencesに保存しておくと、
ユーザーの使用環境に合わせた、
利便性の高い電卓にすることができます。