re: 10 なら 10、 11 なら 20 になる関数を作りたい
10 なら 10、 11 なら 20 になる関数を作りたいをやってみよう。暇だし。
その1: Math.ceilを使う
まずは先に報告があるMath.ceilを使う方法。
function round(x, a){
return Math.ceil(x/a)*a;
}
多分、これが正解。
その2: Math.ceil
を使わない
xとaが整数であることを前提に、Math.ceil
をMath.floor
に書き換える。
function round(x, a){
return (Math.floor((x - 1)/a) + 1)*a;
}
その3: Math.floor
も使わない (そしてxが0以下の場合、非対応になる)
Math.ceil
を使わないんだから、Math.floor
も使うのやめてみる。
function round(x, a){
return (((x - 1) - (x - 1)%a)/a + 1)*a;
}
読みにくいので展開。
function round(x, a){
return x + a - (x - 1)%a - 1;
}
でも、この書き換えはxが0以下の場合に対応していない。
その4: 0以下の場合にも対応させる
xが0以上なら大丈夫なんだから、xの絶対値 (|x|) より大きいaの倍数、"a*n" をxに足しておいて、後で引けばいい。
function round(x, a){
return ((x + a*n) + a - ((x + a*n) - 1)%a - 1) - a*n;
}
展開。
function round(x, a){
return x + a - (x + a*n - 1)%a - 1;
}
nは十分大きい数字なら何だって良いが、桁あふれが起きないようにできるだけ小さい数字を狙ってみる。
a*n > |x|
なのでa*n > x
n > |x|/a
。aとnは1以上の整数、xは0以下の整数なので、最小のnはn > x/a
Math.floor((x - 1)/a)*-1
。
xが負の整数であることを前提にMath.floorを展開して、nは(-x + x%a)/a + 1
。
このとき、xがaの2倍以上の正の整数になると(-x + x%a)/a + 1
が負の値になってしまうが、a*((-x + x%a)/a + 1)
はxより小さく、また剰余計算の割られる数なので、式の結果には影響しない。
という訳で、nに(-x + x%a)/a + 1
を代入する。
function round(x, a){
return x + a - (x + a*((-x + x%a)/a + 1) - 1)%a - 1;
}
展開。
function round(x, a){
return x + a - (x%a + a - 1)%a - 1;
}
ところで、これ (x + a - (x%a + a - 1)%a - 1
) をみてくれ。コイツをどう思う
全く意味がわかりません。
っていうか、自分で書いておいてなんだけど、何でこの式で答えが得られるのか良くわからないし (おい)。
本気で間違っていても気づかないので、読者各位の検算希望。
今日の結論
素直にMath.ceil
を使うのが正解 (ここまでやっておいて、それかよ)。