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

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

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

音樂は SoundCloud に公開中です。

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

Programming は GitHub で開發中です。

とくに反省は無い……

さっそくつっこまれてしまった。

Re:浮動小数点数を整数にする高速(?)な方法 - JavaScript比較
 http://javascript.g.hatena.ne.jp/edvakf/20090203/1233678994

ちょっと、いや、かなりひやりとしたが、今は突っ込まれてうれしいレベルなのである。つっこみ自体始めてなのだから。
まぁ自分は、素人の目の前でコードを動かしてびっくりさせることが専門だとまだ自認しているし(自慢してるわけじゃないぞ)、プログラムよりはiTunesでの楽曲管理のほうが幾分も得意だという状態だ。
根本的に、専門は哲学、社会・文芸評論なのは、忘れてはいない。そちらの鍛錬を欠かしたことはない。

反省会

さて、内容に関して、題名に反して反省してみる。修正といった方が正しいかもしれない。

3つの理由から、この記事はちょっとアレゲかなと思ってしまう。

  1. Math 関数を呼ぶのは気持ち悪い。
  2. floor と abs の順番が違うと結果が変わる。
  3. Math.floor は意図しない結果を返すかもしれない。

致命傷になるのは2と3。
〈効率より精度〉、は原則だから。

しかし、関数呼び出しである Math.floor よりも、プリミティブ演算を使うほうが格段に早い。
例えば、0以上2147483648未満の少数に限られるが、「その数を越えない最大の整数 (の正部分)」を求めるなら、amachang さんの書いている ~~ 演算が使え、速度は以下のようになる。

そう。「~」はnot、否定演算子、ビット演算子の一種。正しい。
オペランド32bit整数に強制変換される。めでたしめでたし。――ではダメなのだ。〈効率より精度〉。(私の説明が不足していたのだが。)


「floor と abs の順番が違うと結果が変わる」はしまった、と思った。
(parseInt()は符号を揃えないのでダメ。気付くのが遅い。)

Math.floor(3.1);
 // -> 3
Math.floor(3.0);
 // -> 3
Math.floor(-3.1);
 // -> -4
Math.floor(-3.0);
 // -> -3

(ミスった……。)失態の原因は、Math.floor()の定義は「切り落とし」だと思っていたから。
ではなく、「超えない最大の整数」だったのか。信じきってて試したことはなかった。

Math.ceil(3.1);
 // -> 4
Math.ceil(3.0);
 // -> 3
Math.ceil(-3.1);
 // -> -3
Math.ceil(-3.0);
 // -> -3

ということで、好みと目的次第で、調節するしかなさそうだ。


「Math.floor は意図しない結果を返すかもしれない」
はて?
おぉっとぅ。二進誤差か。失念していた。
なるほど。Number#toFixed()か。

n = Math.abs(parseInt(Number(n).toFixed(5)));

(長い。効率はすごく悪そうだ。10進Objectをつくるよりはましな気もする。)
おぉ、こわいこわい。
でも精度で言えば、十進数で処理すれば絶対(いちおう)。


1番について。

1つ目は、何度も書いているように、Math.floor が関数呼び出しであることと、Math がグローバルオブジェクトであること。

いくら素人だからって、これは知ってる。(喜ばしいことだ。)
確かに、Math.floor()だけを繰り返し使うのなら、

(function(){
for(var i=0; i<100000; ++i) Math.floor(n);
})();

より

(function(){
var Mf = Math.floor;
for(var i=0; i<100000; ++i) Mf(n);
})();

が効率がいい。突っ込み記事に書いてあるように、スコープチェーンの辿り方が原因だ。
だがこのような使い方は、想定できない。少なくとも、僕が想定したのはこれではない。
関数の入り口で、引数を整形するためのコードだ。(また明らかに僕の説明不足だが。)
つまり。
自然数しか許されないところに。ユーザーは配列をつっこむかもしれない。負数? 実数? 文字列を突っ込みやがるかもしれない。Nodeオブジェクトがやってくる可能性もある。
そういう想定での、整形。
つまり、

var f = function(n){
  n = toNatural(n);
  
  // something usefull
  
};
/* toNatural()は想像上の処理 */

のような。この場合、

var fun = function(n){
  n = Math.floor(n);
};

の繰り返しより

var fun = function(n){
  var Mf = Math.floor;
  n = Mf(n);
  // 以後Mfは使われない。
};

の繰り返しが効率がよいというのは、ないだろう。
まぁライブラリ全体をクロージャで囲って、そこでローカル変数宣言しておく、というのも無いじゃないが。好みにあわないだけだ。


前言を翻すようだけど、まぁここまで書きながら、専用の関数つくった方がいいんじゃないか、と思えてきたが……。

許せ

断定的な口調やタイトルなのは、ほら、あれだ、釣りだ。
文章は先ず、タイトル命だと思っている。手にとってもらえなければ、読まれることはないからだ。そして、古き良き読者だけをかためてゆくつもりはない。

3つの理由から、この記事はちょっとアレゲかなと思ってしまう。

いや、アレゲLunaticです。まぁアレゲなことするためにこのブログを始めたんだ。許せ。
アレゲでないものは
 http://c4se.sakura.ne.jp/ne_index.html
本サイトへ。更新遅いけど。
一部、本サイト掲載前に、こっちに文章を載せている。このブログも無意味ではない。
(と云うか、始めは更新情報のブログにするつもりだったんだ……。)