読者です 読者をやめる 読者になる 読者になる

ビット演算で小数点切り捨て

JavaScript

ライセンスで話題のモバゲーDeNAのJavaScriptライブラリですけど、プログラマならライセンスよりソース読んでみようぜ。え、おまえもTwitterでライセンスpgrしてただろうって?なんの事すか?

コードはかなり奇麗に書かれているので、読みやすいですよ。

arctic.js at 2891ac9d764df401c4b5087f5fb0d660a30cd58e from DeNADev/Arctic.js - GitHub

if(arc.ua.isAndroid2_1 && getScreenWidth() != SCREEN_NORMAL_WIDTH){
    var scale = SCREEN_NORMAL_WIDTH /getScreenWidth();

    x = ~~(x * scale);
    y = ~~(y * scale);
    width = ~~(width * scale);
    height = ~~(height * scale);
    nwidth = ~~(nwidth * scale);
    nheight = ~~(nheight * scale);
}

これは何? ~~ ビット反転2回??

var a = 12.34;
console.log(~a)   // -13
console.log(~~a)  // 12

お?

ECMA262 5thの仕様書によると

11.4.8 Bitwise NOT Operator ( ~ )

The production UnaryExpression : ~ UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.
  2. Let oldValue be ToInt32(GetValue(expr)).
  3. Return the result of applying bitwise complement to oldValue. The result is a signed 32-bit integer.

だそうで32bit integer型にされるので小数点以下が切り捨てられるんすね。他にもいろいろ方法があるようです。さすが変態言語

var a = Math.random() * 10;
console.log(a);

console.log(~~a);
console.log(a | 0);
console.log(a >> 0);

これらは単純に小数点以下を捨てるだけなので、値が正と負で丸めの方向が変わります。値が負になる可能性がある場合は、素直に Math.floor や Math.ceil を使用した方がいいと思います。

var a = 2.1;
console.log(~~a);            // 2
console.log(Math.floor(a));  // 2
console.log(Math.ceil(a));   // 3

var b = -2.1;
console.log(~~b);            // -2
console.log(Math.floor(b));  // -3
console.log(Math.ceil(b));   // -2