◆PROCESSING 逆引きリファレンス
カテゴリー:演算処理
四捨五入、切り捨て、切り上げ
【概要】
プログラムで値の集計や計算処理を行わせる時、四捨五入や切り捨て、切り上げを行いたくなる事があります。
え、Excelでパッと計算すればいいじゃん・・・ですか?。・・・それはそうなのですが、ここではPROCESSINGでこれらの計算を行う方法を紹介したいと思います。
PROCESSINGはJavaをベースにした言語ですので、JavaのMathクラスが持つ各メソッドを利用して、これらの計算を行う事ができます。
また四捨五入や切り捨て、切り上げであれば、PROCESSINGが用意している命令でも計算可能です。
【詳細】
全般的な注意
以下に説明する各種命令は引数に float 型の値を与えますが、float (や double)は、計算誤差が生じる事に注意してください。
例えば、round() は四捨五入を行う命令ですが
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * PROCESSING round Sample * @auther MSLABO * @version 2018/06 1.0 */ void setup(){ println( round(10.4) ); //(1) -> 10 println( round(10.4999999) ); //(2) -> 11 noLoop(); } void draw(){ } |
上記の(2)では、10ではなく11が戻されます。
このような計算誤差を発生させたくない場合は、以下で説明する命令は使用せずに、JavaのBigDecimalクラスを利用します。
BigDecimalクラスについては、「誤差がない計算を行うには」記事を参照してください
ただしJavaのBigDecimalクラスは、処理スピードが犠牲となります。多少の計算誤差が許される場合は、以下に説明する命令の方が便利でしょう。
切り上げ処理
切り上げ処理int n = ceil( float val ) ;
n : 切り上げた結果
val : 処理対象の値
val を切り上げた結果を n に戻します。
小数点以下が0でない場合、数字が正の方向へ大きくなるように切り上げられます。たとえば val = 12.3 なら、n は 13 になります。
注意としては、val が負の値の場合です。切り上げは「数字が正の方向へ大きくなるよう」に行われますので、val = -12.9 なら n は -12 になります。
元の値 | ceil後 | |
---|---|---|
1 | 10.0 | 10 |
2 | 10.4 | 11 |
3 | 10.5 | 11 |
4 | -10.0 | -10 |
5 | -10.4 | -10 |
6 | -10.5 | -10 |
切り捨て処理
切り捨て処理int n = floor( float val ) ;
n : 切り捨てた結果
val : 処理対象の値
小数点以下が0でない場合、数字が負の方向へ小さくなるように切り捨てられます。たとえば val = 12.3 なら、n は 12 になります。
注意としては、val が負の値の場合です。切り捨ては「数字が負の方向へ小さくなるよう」に行われますので、val = -12.9 なら n は -13 になります。
元の値 | floor後 | |
---|---|---|
1 | 10.0 | 10 |
2 | 10.4 | 10 |
3 | 10.5 | 10 |
4 | -10.0 | -10 |
5 | -10.4 | -11 |
6 | -10.5 | -11 |
四捨五入処理
四捨五入処理int n = round( float val ) ;
n : 四捨五入した結果
val : 処理対象の値
小数点以下が0でない場合、四捨五入された値を戻します。たとえば val = 12.5 なら、n は 13 になります。
注意としては、val が負の値の場合です。四捨五入は、以下の計算式で求められます。
n = floor( val + 0.5f ) ;
したがって、val = -10.5 の場合、-10.5 + 0.5 = -10.0 を切り上げて -10 が戻されます。
これは Java の Math.round() メソッドの仕様です。
-10.5 の場合、四捨五入した結果として -11 を戻してほしい(感覚的にはこうですよね:汗)なら、round() ではなくBigDecimalクラスを使って四捨五入します。
元の値 | round後 | BigDecimalで四捨五入 | |
---|---|---|---|
1 | 10.0 | 10 | 10 |
2 | 10.4 | 10 | 10 |
3 | 10.5 | 11 | 11 |
4 | -10.0 | -10 | -10 |
5 | -10.4 | -10 | -10 |
6 | -10.5 | -10 | -11 |
7 | -10.6 | -11 | -11 |
【関連記事】
サンプルプログラム
切り上げ処理例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** * PROCESSING ceil Sample * @auther MSLABO * @version 2018/06 1.0 */ void setup(){ float val[] = new float[] {0.1, 1.02, 10.0, 10.001, -9.4, -0.3}; println( "PROCESSING ceil TEST"); for( float data : val ){ println( data + "\t=>\t" + ceil(data) ); } noLoop(); } void draw(){ } |
いろいろな float の値を切り上げています。負の値の切り上げ結果に注意してください。
切り捨て処理例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** * PROCESSING floor Sample * @auther MSLABO * @version 2018/06 1.0 */ void setup(){ float val[] = new float[] {0.1, 1.02, 10.0, 10.001, -9.4, -0.3}; println( "PROCESSING floor TEST"); for( float data : val ){ println( data + "\t=>\t" + floor(data) ); } noLoop(); } void draw(){ } |
いろいろな float の値を切り捨てています。負の値の切り捨て結果に注意してください。
四捨五入処理例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/** * PROCESSING round Sample * @auther MSLABO * @version 2018/06 1.1 */ void setup(){ float val[] = new float[] {10.4, 10.5, 0.4, -9.4, -9.5, -9.6}; println( "PROCESSING round TEST"); for( float data : val ){ println( data + "\t=>\t" + round(data) ); } noLoop(); } void draw(){ } |
いろいろな float の値を四捨五入しています。負の値の四捨五入結果に注意してください
BigDecimalとの速度比較例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import java.math.BigDecimal; import java.math.RoundingMode; /** * PROCESSING 標準命令 vs BigDecimal Sample * @auther MSLABO * @version 2018/07 1.0 */ void setup(){ int start = millis(); float val = 1.5; //BigDecimal val = new BigDecimal("1.5"); for( int i = 0; i < 30000000; i++){ floor(val); //val.setScale(0,RoundingMode.HALF_UP); } int end = millis() - start; println( end ); } void draw(){ } |
BigDecimalは本当に遅いのか?・・・という事で、PROCESSINGの標準命令とBigDecimalで四捨五入を行い、簡易速度比較を行いました。
コメント箇所がBigDecimalの命令です。四捨五入を3000万回(笑)回しています。
標準命令の場合、平均 16ms・・・。最適化が走るためか異常に早いです。一方でBigDecimalの方は約610ms。やはり遅いですね(汗)。
正確さを取るか速度を取るか・・・という事になりそうです。
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。