From bc980288d80345d2ee74197ad576de44864357fe Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Mon, 11 Nov 2024 01:02:48 +0900 Subject: [PATCH] =?UTF-8?q?2024/08/08=20=E6=99=82=E7=82=B9=E3=81=AE?= =?UTF-8?q?=E8=8B=B1=E8=AA=9E=E7=89=88=E3=81=AB=E5=9F=BA=E3=81=A5=E3=81=8D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global_objects/math/clz32/index.md | 179 ++++++++---------- 1 file changed, 76 insertions(+), 103 deletions(-) diff --git a/files/ja/web/javascript/reference/global_objects/math/clz32/index.md b/files/ja/web/javascript/reference/global_objects/math/clz32/index.md index 5725509f05e50b..3392c0efd2d2e0 100644 --- a/files/ja/web/javascript/reference/global_objects/math/clz32/index.md +++ b/files/ja/web/javascript/reference/global_objects/math/clz32/index.md @@ -1,38 +1,68 @@ --- title: Math.clz32() slug: Web/JavaScript/Reference/Global_Objects/Math/clz32 +l10n: + sourceCommit: d71da812ee94c20658cb1916a123a42254ea545c --- {{JSRef}} -**`Math.clz32()`** 関数は、引数として与えられた数値の 32 ビットバイナリ表現での先頭の 0 の個数を返します。 +**`Math.clz32()`** は静的メソッドで、引数として与えられた数値の 32 ビットバイナリー表現での先頭の 0 の個数を返します。 {{EmbedInteractiveExample("pages/js/math-clz32.html")}} ## 構文 -``` +```js-nolint Math.clz32(x) ``` ### 引数 - `x` - - : 数値。 + - : 数値です。 ### 返値 -与えられた数値の 32 ビットバイナリ表現での先頭の 0 の個数。 +`x` の 32 ビットバイナリー表現での先頭の 0 の個数。 ## 解説 -"`clz32`" は **CountLeadingZeroes32** の省略形です。 +`clz32` は **C**ount**L**eading**Z**eros**32** の省略形です。 `x` が数値でない場合、まず数値に変換され、32 ビット符号なし整数値に変換されます。 -変換された 32 ビット符号なし整数値が `0` の場合、すべてのビットが `0` であるため、`32` を返します。 +変換された 32 ビット符号なし整数が `0` の場合、 `32` が返されます。これは、すべてのビットが `0` であるためです。最上位ビットが `1` の場合(すなわち、数値が 231 以上の数値である場合)、 `0` が返されます。 + +この関数は [Emscripten](https://emscripten.org/) のような JS にコンパイルするシステムに対して特に役に立ちます。 + +## 例 + +### Math.clz32() の使用 + +```js +Math.clz32(1); // 31 +Math.clz32(1000); // 22 +Math.clz32(); // 32 + +const stuff = [ + NaN, + Infinity, + -Infinity, + 0, + -0, + false, + null, + undefined, + "foo", + {}, + [], +]; +stuff.every((n) => Math.clz32(n) === 32); // true -この関数は [Emscripten](/ja/docs/Emscripten) のような JS にコンパイルするシステムに対して特に役に立ちます。 +Math.clz32(true); // 31 +Math.clz32(3.5); // 30 +``` ### 先頭の 1 を数える @@ -41,133 +71,75 @@ Math.clz32(x) 以下の 32 ビットワード値を想定してみます。 ```js -var a = 32776; // 00000000000000001000000000001000 (16 leading zeros) +const a = 32776; // 00000000000000001000000000001000 (先頭のゼロは 16 個) Math.clz32(a); // 16 -var b = ~32776; // 11111111111111110111111111110111 (32776 inversed, 0 leading zeros) -Math.clz32(b); // 0 (this is equal to how many leading one's there are in a) +const b = ~32776; // 11111111111111110111111111110111 (32776 の逆、先頭のゼロは 0 個) +Math.clz32(b); // 0 (これは、 a にある先頭の 1 の数に等しい) ``` この論理を使用すると、 `clon` 関数は次のように作成することができます。 ```js -var clz = Math.clz32; +const clz = Math.clz32; + function clon(integer) { return clz(~integer); } ``` -さらに、この技術を拡張して、以下に示すようなジャンプレスの「Count Trailing Zeros」と「Count Trailing Ones」関数を作成することができます。以下の `ctrz` 関数は、すべての上位ビットを最も低いビットで埋め、そのビットを否定して上位のセットビットをすべて消去するので、clz が使用できます。 +さらに、このテクニックを拡張して、下記のようなジャンプのない "Count Trailing Zeros" 関数を作成することもできます。 `ctrz` 関数は、 2 の補数を持つ整数のビット単位の AND 演算を行います。 2 の補数にすることで、すべての末尾のゼロが 1 に変換され、 1 を加算すると、最初の 0 (元々は 1)に達するまで引き継がれます。それより上位のビットはすべてそのまま維持され、元の整数のビットの逆数となります。したがって、元の整数とビット単位の論理積を計算すると、上位のビットはすべて 0 となり、 `clz` でカウントできます。末尾のゼロの数に最初の 1 ビット、 `clz` でカウントされた上位ビットを足した合計は 32 です。 ```js -var clz = Math.clz32; function ctrz(integer) { - // count trailing zeros - // 1. fill in all the higher bits after the first one - integer |= integer << 16; - integer |= integer << 8; - integer |= integer << 4; - integer |= integer << 2; - integer |= integer << 1; - // 2. Now, inversing the bits reveals the lowest bits - return (32 - clz(~integer)) | 0; // `|0` ensures integer coercion + integer >>>= 0; // Uint32 へ変換 + if (integer === 0) { + // このステップを飛ばすと -1 を返すことになる + return 32; } + integer &= -integer; // `int = int & (~int + 1)` と同等 + return 31 - clz(integer); +} +``` + +次に、 "Count Trailing Ones" 関数を次のように定義します。 + +```js function ctron(integer) { - // count trailing ones - // No shift-filling-in-with-ones operator is available in - // JavaScript, so the below code is the fastest return ctrz(~integer); - /* Alternate implementation for demonstrational purposes: - // 1. erase all the higher bits after the first zero - integer &= (integer << 16) | 0xffff; - integer &= (integer << 8 ) | 0x00ff; - integer &= (integer << 4 ) | 0x000f; - integer &= (integer << 2 ) | 0x0003; - integer &= (integer << 1 ) | 0x0001; - // 2. Now, inversing the bits reveals the lowest zeros - return 32 - clon(~integer) |0; - */ } ``` -これらのヘルパー関数を ASM.JS モジュールに入れます。そして、そうすれば、真のパフォーマンスの傑作ができあがります。このような状況は、まさに ASM.JS のために設計されたものです。 +これらのヘルパー関数は、パフォーマンスの向上を目的として、 [asm.js](/ja/docs/Games/Tools/asm.js) モジュールにすることができます。 ```js -var countTrailsMethods = (function (stdlib, foreign, heap) { +const countTrailsMethods = (function (stdlib, foreign, heap) { "use asm"; - var clz = stdlib.Math.clz32; + const clz = stdlib.Math.clz32; + + // 先頭のゼロを数える function ctrz(integer) { - // count trailing zeros - integer = integer | 0; // coerce to an integer - // 1. fill in all the higher bits after the first one - // ASMjs for some reason does not allow ^=,&=, or |= - integer = integer | (integer << 16); - integer = integer | (integer << 8); - integer = integer | (integer << 4); - integer = integer | (integer << 2); - integer = integer | (integer << 1); - // 2. Now, inversing the bits reveals the lowest bits - return (32 - clz(~integer)) | 0; + integer = integer | 0; // 整数に変換 + if ((integer | 0) == 0) { + // このステップを飛ばすと -1 を返すことになる + return 32; } + // メモ: asm.js には &= のような複合代入演算子がない + integer = integer & -integer; // equivalent to `int = int & (~int + 1)` + return (31 - clz(integer)) | 0; + } + + // 最後の 1 を数える function ctron(integer) { - // count trailing ones - integer = integer | 0; // coerce to an integer + integer = integer | 0; // 整数に変換 return ctrz(~integer) | 0; } - // unfourtunately, ASM.JS demands slow crummy objects: - return { a: ctrz, b: ctron }; -})(window, null, null); -var ctrz = countTrailsMethods.a; -var ctron = countTrailsMethods.b; -``` -## 例 - -### Math.clz32() の使用 - -```js -Math.clz32(1); // 31 -Math.clz32(1000); // 22 -Math.clz32(); // 32 - -var stuff = [ - NaN, - Infinity, - -Infinity, - 0, - -0, - false, - null, - undefined, - "foo", - {}, - [], -]; -stuff.every((n) => Math.clz32(n) == 32); // true - -Math.clz32(true); // 31 -Math.clz32(3.5); // 30 -``` - -## ポリフィル - -以下のポリフィルが最も効果的です。 + // asm.js はプレーンオブジェクトを要求する + return { ctrz: ctrz, ctron: ctron }; +})(window, null, null); -```js -if (!Math.clz32) - Math.clz32 = (function (log, LN2) { - return function (x) { - // Let n be ToUint32(x). - // Let p be the number of leading zero bits in - // the 32-bit binary representation of n. - // Return p. - var asUint = x >>> 0; - if (asUint === 0) { - return 32; - } - return (31 - ((log(asUint) / LN2) | 0)) | 0; // the "| 0" acts like math.floor - }; - })(Math.log, Math.LN2); +const { ctrz, ctron } = countTrailsMethods; ``` ## 仕様書 @@ -180,5 +152,6 @@ if (!Math.clz32) ## 関連情報 +- [`Math.clz32` のポリフィル (`core-js`)](https://github.com/zloirock/core-js#ecmascript-math) - {{jsxref("Math")}} - {{jsxref("Math.imul")}}