切り下げ、切り上げ、四捨五入

floor 小数部の切り下げ - Perl入門〜サンプルコードによるPerl入門〜に Perl を用いた例が載っていますが、awk には切り下げ (floor)、切り上げ (ceil)、四捨五入 (round) という関数が用意されていません。 これらを awk で実装することは比較的簡単ですので、実装しています。

#! /usr/bin/gawk -f
# floor.awk

BEGIN {
    print "num  : floor: ceil : round";
    for (i = -20; i <= 20; i++) {
        j = i / 10;
        printf("%5.2f: %5d: %5d: %5d\n", j, floor(j), ceil(j), round(j));
    }
}

# 小数部の切り下げ
#   in:     数値 num
#   out:    数値 num の小数部を切り下げたもの
function floor(num) {
    if (int(num) == num) {
        return num;
    } else if (num > 0){
        return int(num);
    } else {
        return int(num) - 1;
    }
}

# 小数部の切り上げ
#   in:     数値 num
#   out:    数値 num の小数部を切り上げたもの
function ceil(num) {
    if (int(num) == num) {
        return num;
    } else if (num > 0) {
        return int(num) + 1;
    } else {
        return num;
    }
}

# 小数部の四捨五入
#   in:     数値 num
#   out:    数値 num の小数部を四捨五入したもの
function round(num) {
    if (num > 0) {
        return int(num + 0.5);
    } else {
        return int(num - 0.5);
    }
}

これらの関数は慣用句のようになっていますので、どうしてそのような実装になるのかを考えてみてください。

$ nawk -f floor.awk
num  : floor: ceil : round
-2.00:    -2:    -2:    -2
-1.90:    -2:    -1:    -2
-1.80:    -2:    -1:    -2
-1.70:    -2:    -1:    -2
-1.60:    -2:    -1:    -2
-1.50:    -2:    -1:    -2
-1.40:    -2:    -1:    -1
-1.30:    -2:    -1:    -1
-1.20:    -2:    -1:    -1
-1.10:    -2:    -1:    -1
-1.00:    -1:    -1:    -1
-0.90:    -1:     0:    -1
-0.80:    -1:     0:    -1
-0.70:    -1:     0:    -1
-0.60:    -1:     0:    -1
-0.50:    -1:     0:    -1
-0.40:    -1:     0:     0
-0.30:    -1:     0:     0
-0.20:    -1:     0:     0
-0.10:    -1:     0:     0
 0.00:     0:     0:     0
 0.10:     0:     1:     0
 0.20:     0:     1:     0
 0.30:     0:     1:     0
 0.40:     0:     1:     0
 0.50:     0:     1:     1
 0.60:     0:     1:     1
 0.70:     0:     1:     1
 0.80:     0:     1:     1
 0.90:     0:     1:     1
 1.00:     1:     1:     1
 1.10:     1:     2:     1
 1.20:     1:     2:     1
 1.30:     1:     2:     1
 1.40:     1:     2:     1
 1.50:     1:     2:     2
 1.60:     1:     2:     2
 1.70:     1:     2:     2
 1.80:     1:     2:     2
 1.90:     1:     2:     2
 2.00:     2:     2:     2

上記コードの for 文は小数点を用いないように、あらかじめ 10 倍していますが、このあたりもどうして 10 倍しているのかを含めて考えてみてください。 10 倍しない場合には以下のようになります。

#! /usr/bin/gawk -f
# floor_2.awk

BEGIN {
    print "num  : floor: ceil : round";
    for (j = -2; j <= 2; j = j + 0.1) {
        printf("%5.2f: %5d: %5d: %5d\n", j, floor(j), ceil(j), round(j));
    }
}

# 小数部の切り下げ
#   in:     数値 num
#   out:    数値 num の小数部を切り下げたもの
function floor(num) {
    if (int(num) == num) {
        return num;
    } else if (num > 0){
        return int(num);
    } else {
        return int(num) - 1;
    }
}

# 小数部の切り上げ
#   in:     数値 num
#   out:    数値 num の小数部を切り上げたもの
function ceil(num) {
    if (int(num) == num) {
        return num;
    } else if (num > 0) {
        return int(num) + 1;
    } else {
        return num;
    }
}

# 小数部の四捨五入
#   in:     数値 num
#   out:    数値 num の小数部を四捨五入したもの
function round(num) {
    if (num > 0) {
        return int(num + 0.5);
    } else {
        return int(num - 0.5);
    }
}

実行してみましょう。

$ nawk -f floor_2.awk
num  : floor: ceil : round
-2.00:    -2:    -2:    -2
-1.90:    -2:    -1:    -2
-1.80:    -2:    -1:    -2
-1.70:    -2:    -1:    -2
-1.60:    -2:    -1:    -2
-1.50:    -2:    -1:    -1
-1.40:    -2:    -1:    -1
-1.30:    -2:    -1:    -1
-1.20:    -2:    -1:    -1
-1.10:    -2:    -1:    -1
-1.00:    -1:     0:    -1
-0.90:    -1:     0:    -1
-0.80:    -1:     0:    -1
-0.70:    -1:     0:    -1
-0.60:    -1:     0:    -1
-0.50:    -1:     0:     0
-0.40:    -1:     0:     0
-0.30:    -1:     0:     0
-0.20:    -1:     0:     0
-0.10:    -1:     0:     0
 0.00:     0:     1:     0 <- ここの挙動がおかしい
 0.10:     0:     1:     0
 0.20:     0:     1:     0
 0.30:     0:     1:     0
 0.40:     0:     1:     0
 0.50:     0:     1:     1
 0.60:     0:     1:     1
 0.70:     0:     1:     1
 0.80:     0:     1:     1
 0.90:     0:     1:     1
 1.00:     1:     2:     1
 1.10:     1:     2:     1
 1.20:     1:     2:     1
 1.30:     1:     2:     1
 1.40:     1:     2:     1
 1.50:     1:     2:     2
 1.60:     1:     2:     2
 1.70:     1:     2:     2
 1.80:     1:     2:     2
 1.90:     1:     2:     2

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png