c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud に公開中です。

考察は現在は主に Cosense で公表中です。

Programming は GitHub で開發中です。

巨大回数の繰り返し - JavaScript

アルゴリズム - 同じ文字列のn回繰り返しをlog n回で作る方法
 http://blog.livedoor.jp/dankogai/archives/51172176.html

function (str, n){
    var result = '';
    for(n *= 1; n > 0; n >>>= 1, str += str) if (n & 1) result += str;
    return result;
}


というコードが紹介されていた。なるほどね。
アルゴリズムの基は、以下。


冪乗 - Wikipedia
 http://ja.wikipedia.org/wiki/冪乗

  1. 指数 n を二進表記したものを n とし、n の最下位桁を n[0]、最上位桁を n[m]、最下位から数えて k 桁目を n[k] と表記する。
  2. 2乗していく値 p := a とし、結果値 v := 1 とする。
  3. k := 0 とする(最下位)。
  4. n[k] が 1 ならば v := v * p とする。
  5. p := p * p
  6. k := k + 1
  7. k ≦ m なら 4. に戻る。
  1. 指数 n を二進表記したものを n とし、n の最下位桁を n[0]、最上位桁を n[m]、最下位から数えて k 桁目を n[k] と表記する。
  2. 結果値 v := 1 とし、
  3. k := m とする(最上位)。
  4. v := v * v
  5. n[k] が 1 ならば v := v * a とする。
  6. k := k - 1
  7. k ≧ 0 なら 4. に戻る。


それぞれコードに落とすと、

Math_power_d = function(n, m){
  n = Number(n); m = Number(m);
  if(n == 0) return 0;
  if(m == 0) return n;
  var r = 1;
  for(; m>0; m>>>=1, n*=n)
    if(m & 1) r *= n;
  return r;
};
Math_power_u = function(n, m){
  n = Number(n); m = Number(m);
  if(n == 0) return 0;
  if(m == 0) return n;
  var r = n;
  for(; m>0; m<<=1, r*=r)
    if(m.toString(2)[0] == "1") r *= n;
  return r;
};

掛け算や二乗をチューニングすれば、もっとよい。
但し、JavaScriptだと、32bit整数までしかビット演算は扱えない。でも数の範囲は64bit浮動小数点数。除算を使えばまぁ矛盾は起こらないんだけど、bit演算のほうがずっと速い。


巨大な回数の同一な繰り返しが想定される場合には、ほとんど使える。
ビット演算に慣れないと……。