固定小数点数を扱う DecimalAmount型 の試作
Closed this issue · 7 comments
これは、ひとつのissueでやるには、たぶん大きすぎるテーマです。
考えることがたくさんありそう。
もしやっていただける場合は、いくつかのissueに分解して、進めていただければと思います。
概要:小数点以下2桁の金額(円の場合は、銭単位まで)の四則演算
試作仕様は、
- 小数点以下2桁固定
- 乗算、除算の引数は、整数(int)
- 除算の場合、小数点三桁を四捨五入する
- 小数点以下を四捨五入して、Amount型(整数の金額)を返すメソッドを用意する
- Amount型から、long値を取り出すメソッドが必要かもしれない。
- それ以外は、Amount型は、この型の実装のために、変更はしないことが望ましい
実装のアイデアとしては、
- Amount型を non-scale value として持つ、あるいは、long値をもち、適宜、Amount型を使用する
- int で、小数点以下の scale値を持つ( 試作版では、2桁固定)
- つまり、最大金額は、Amount型の最大金額 (LONG_MAX)の 100分の1である
- コンストラクタは、文字列表現( "12.34")のみ、取り込む
- toString() は、コンストラクタに渡せる文字列表現を出力する
留意点としては、
- BigDecimalのAPI ドキュメントとソースコードを参考に試作する
- 将来的には、小数点以下の桁数は、1~4の4種類を持つことを想定
- 将来的には、四捨五入以外に、切捨て、切り上げ、「銀行家の丸め」も対応したい
- まずは、今回の試作仕様で、割り切りバージョンで動かしてから、段階的に進化させていく
money パッケージに追加する
【参考】実装方法の他のアイデア
コードを書いて、どれがよさそうか、考えてみたい。
- インスタンス変数にBigDecimalを持つ
- インスタンス変数に long nonScaleValue と int scale(小数点以下の桁数)を持つ
- インスタンス変数に long beforePointValue(整数部)と int afterPointValue を持つ
BigDecimal
- 最初のBigDecimalを持つ方法がいちばん実装が簡単か?
- ただし、実質無限の最大・最小ではなく、longの最大最小以下の制限したい
long 値+ scale
- long の値+int sacle という方法は、BigDecimalの(longに収まる場合の)実装を、そのままという感じになる
- 技術的な勉強にはなるが、低レベルの実装すぎるか?
整数部+小数部
- 整数部(long)と小数部(int)を分けてもつのが、固定小数点数のモデルの直接的な写像に思える
- 実装が以外と面倒くさいかも
<参考> 大人の学びなおし教室
小数の足し算・引き算は、小数点を揃えることがポイント
https://keisan.otona-juku.com/01021decimal-plus/
https://keisan.otona-juku.com/01022decimal-minus/
※小数点以下の桁数が違う場合、多いほうにそろえる(少ないほうは後ろに0がつく)
小数の掛け算は、整数のように計算して、小数点をずらす
https://keisan.otona-juku.com/01023decimal-multiply/
https://keisan.otona-juku.com/01024decimal-multiply/
(少数×整数と少数×小数は、別の説明)
小数÷整数は、整数のように計算して、小数点をずらす
https://keisan.otona-juku.com/01025decimal-division-integer/
小数÷小数は、まず小数点をずらして小数÷整数にしてから計算する
https://keisan.otona-juku.com/01026decimal-division/
BigDecimal で仮実装してみました。
やはり、他の2案よりも、実装が簡単だと思いました。
現在は小数点以下2桁で実装していますが、
小数点以下の桁数を1〜4にの4種類にする実装の際に、
異なる桁数の加算減算は可能とするか、
可能な場合は計算結果の桁数はどうするかなどが気になりました。
確認ありがとうございます。
引数を修正し、プルリクエストしました。
桁数に関する仕様について、Issue の追加ありがとうございます。