小数の桁数と丸め方を制御する Sass 関数

Sass の数値で出力されるのは小数点以下 5 桁までで、6 桁めが四捨五入される (Sass 3.2 の デフォルト設定 の場合)。つまり、0.333333...0.33333 に、0.666666...0.66667 に丸められる。でもたとえば 16px/12px の結果として 1.33333 ではなく 1.34 がほしい、というような場面もある。数値を丸める関数として round()ceil()floor() が用意されてるけど、いずれも小数部分を丸めて整数を返すもので、任意の桁を操作するということはできない。というわけで、小数点以下の桁数と丸めを制御する round-decimal()ceil-decimal()floor-decimal() という関数を作ってみた。

// Round (四捨五入)
@function round-decimal ($number, $digits: 0) {
    @return to-fixed($number, $digits, 'round');
}

// Ceil (切り上げ)
@function ceil-decimal ($number, $digits: 0) {
    @return to-fixed($number, $digits, 'ceil');
}

// Floor (切り捨て)
@function floor-decimal ($number, $digits: 0) {
    @return to-fixed($number, $digits, 'floor');
}

@function to-fixed ($number, $digits: 0, $round: 'round') {
    $n: 1;
    // $number must be a number
    @if type-of($number) != number {
        @warn '#{ $number } is not a number.';
        @return $number;
    }
    // $digits must be a unitless number
    @if type-of($digits) != number {
        @warn '#{ $digits } is not a number.';
        @return $number;
    } @else if not unitless($digits) {
        @warn '#{ $digits } has a unit.';
        @return $number;
    }
    @for $i from 1 through $digits {
        $n: $n * 10;
    }
    @if $round == 'round' {
        @return round($number * $n) / $n;
    } @else if $round == 'ceil' {
        @return ceil($number * $n) / $n;
    } @else if $round == 'floor' {
        @return floor($number * $n) / $n;
    } @else {
        @warn '#{ $round } is undefined keyword.';
        @return $number;
    }
}

// round-decimal(0.333)    => 0
// round-decimal(0.333, 1) => 0.3
// round-decimal(0.333, 2) => 0.33
// round-decimal(0.666)    => 1
// round-decimal(0.666, 1) => 0.7
// round-decimal(0.666, 2) => 0.67

// ceil-decimal(0.333)     => 1
// ceil-decimal(0.333, 1)  => 0.4
// ceil-decimal(0.333, 2)  => 0.34
// ceil-decimal(0.666)     => 1
// ceil-decimal(0.666, 1)  => 0.7
// ceil-decimal(0.666, 2)  => 0.67

// floor-decimal(0.333)    => 0
// floor-decimal(0.333, 1) => 0.3
// floor-decimal(0.333, 2) => 0.33
// floor-decimal(0.666)    => 0
// floor-decimal(0.666, 1) => 0.6
// floor-decimal(0.666, 2) => 0.66

いずれも引数は丸めたい数値と小数点以下の桁数 (デフォルトは 0)で、関数の実体は to-fixed() という、JavaScript の toFixed() をイメージした関数 (ちょっと違うけど)。たとえば ceil-decimal(0.3333, 2) なら、

@return ceil(0.3333 * 100) / 100

ということになるので、33.33 を切り上げた整数 34 の 1/100、つまり 0.34 が返る。

Gist にも上げときました。関数名が適切かどうかの添削を誰か。

Changes

January 12, 2013 – ソースコード中、to-fixed() 関数のエラー処理と条件分岐を修正