VIDEO LESSON

JavaScriptのMath.imul():32ビット整数の乗算で安定した振り分けを作るの解説動画

再生時間 8:02動画を別のタブで開く ↗
動画の字幕・文字起こしを読む

再生中の字幕を濃い黒で表示し、一番上に追従します。字幕の行を選ぶと、その位置から再生できます。

  1. 0:00こんにちは。
  2. 0:00今回はジャバスクリプトのマス・アイマルを紹介します。
  3. 0:04これは、二つの値を三十二ビットの整数として掛け算し、符号付き三十二ビット整数として結果を返す標準のメソッドです。
  4. 0:13名前ごとに表示色を決めたり、テストデータを複数の処理先へ割り当てたりと、
  5. 0:18同じ項目を毎回同じグループへ振り分けたい場面で役立ちます。
  6. 0:23普通の掛け算と何が違うのか、なぜ結果が負の数になることがあるのかを、基本から順に確かめていきます。
  7. 0:30この動画では、基本コード、文字列を四つのグループへ振り分ける実例、そして通常の掛け算で失敗する例までを解説します。
  8. 0:39まず動作環境です。
  9. 0:40マス・アイマルはジャバスクリプト標準の組み込みメソッドで、ブラウザーとノード・ジェイエスの両方で利用できます。
  10. 0:48二千十五年七月以降、主要ブラウザーで広く利用できる機能とされており、現行のクローム、
  11. 0:53エッジ、ファイアフォックス、サファリが対象です。
  12. 0:57記事のサンプルはノード・ジェイエス二十二系または二十四系を想定し、追加パッケージや実験的な設定は使いません。
  13. 1:05古いブラウザーや組み込みの表示部品では、使う前にタイプオブで関数かどうかを確認してください。
  14. 1:12対応していない環境では、コードをそのまま実行せず、対応する環境へ切り替えることが大切です。
  15. 1:18基本の書き方を見ましょう。
  16. 1:20呼び出し方はマス・アイマル、かっこ、エー、カンマ、ビーです。
  17. 1:25エーとビーが掛け算する二つの値で、戻り値はナンバー型の数値です。
  18. 1:30結果の範囲はマイナス二十一億四千七百四十八万三千六百四十八から、二十一億四千七百四十八万三千六百四十七までです。
  19. 1:40小さな値では通常の掛け算と変わりません。
  20. 1:43三かける四は十二、マイナス五かける十二はマイナス六十になります。
  21. 1:48マスはコンストラクターではないため、インスタンスを作らず直接呼び出してください。
  22. 1:55違いが表れるのは、積がこの範囲を超える大きな計算のときだけです。
  23. 2:00桁あふれの仕組みを押さえます。
  24. 2:03三十二ビットでは、すべての大きな整数を保持できません。
  25. 2:08マス・アイマルは積の下位三十二ビットだけを残し、その並びを符号付き整数として読み直して返します。
  26. 2:16範囲を超えたことを知らせる例外は発生しません。
  27. 2:20たとえば最大値の二十一億四千七百四十八万三千六百四十七を二倍すると、通常の計算では四十二億九千四百九十六万七千二百九十四ですが、
  28. 2:28三十二ビットとして読むとマイナス二になります。
  29. 2:36負の数になっても計算の失敗ではありません。
  30. 2:39この性質は一定の幅で値を更新する処理に向きますが、商品の合計金額や数量など、
  31. 2:45積の大きさをそのまま保ちたい計算には向きません。
  32. 2:50基本コードの期待出力を読みます。
  33. 2:53ポイントは、入力が三十二ビット整数へ変換されてから掛け算されることです。
  34. 2:59小数部分は整数への変換時に取り除かれるため、三点九と二の積は七点八ではなく、
  35. 3:02六になります。
  36. 3:06また、四十二億九千四百九十六万七千二百九十六は二の三十二乗なので、三十二ビットへの変換後はゼロとして扱われ、
  37. 3:11何を掛けても結果はゼロです。
  38. 3:17これらの出力はノード・ジェイエスの実機でも確認済みで、記事の期待出力と完全に一致しました。
  39. 3:24変換が先、掛け算が後、という順番を意識すると、予想外に見える結果も落ち着いて説明できます。
  40. 3:31ここからは活用例です。
  41. 3:33文字列を先頭から読み、途中の値を三十一倍して文字の値を足す処理を作ります。
  42. 3:39学習用の簡単なハッシュ計算として扱ってください。
  43. 3:43バケットフォーという関数は、引数が文字列でなければタイプエラーを投げ、空文字は受け入れてゼロを返す設計です。
  44. 3:51本体ではハッシュの初期値をゼロとし、文字ごとにマス・アイマルで三十一倍して文字コードを加え、
  45. 3:56最後にパイプゼロで三十二ビットへ収めます。
  46. 4:02仕上げに符号なしとして読み直してから四で割った余りを取るため、戻り値はゼロから三までの整数になります。
  47. 4:10掛け算にアイマルを使うことが、値の更新を安定させる要です。
  48. 4:14振り分け結果を確かめます。
  49. 4:16空文字はゼロ、エーは一、ビーは二になります。
  50. 4:20エービーシーは二で、同じ文字列をもう一度計算しても必ず二になり、再現性が保たれます。
  51. 4:27一方で、ビーとエービーシーのように、異なる文字列が同じグループに入ることもあります。
  52. 4:33これは欠陥ではなく、有限のグループへ振り分ける以上は避けられない性質です。
  53. 4:39数値でない値を渡した場合は、関数の入り口でタイプエラーとして報告され、計算には進みません。
  54. 4:46これらの結果もノード・ジェイエスの実機で確認済みです。
  55. 4:51同じ入力に同じ出力、という約束が、この仕組みの価値そのものです。
  56. 4:56エービーシーの計算を一歩ずつ追います。
  57. 4:59使われるのはユーティーエフ十六のコード単位の値で、エーが九十七、ビーが九十八、
  58. 5:03シーが九十九です。
  59. 5:07最初はゼロかける三十一に九十七を足して九十七。
  60. 5:11次に九十七かける三十一に九十八を足して三千百五。
  61. 5:15最後に三千百五かける三十一に九十九を足して九万六千三百五十四となり、四で割った余りが二になります。
  62. 5:23途中の足し算の後にも三十二ビットへ収めているため、長い文字列でも値が際限なく大きくなることはありません。
  63. 5:31最後の符号なしへの読み直しは、途中の値が負数でも振り分け番号を負にしないための補助です。
  64. 5:38失敗例として、通常の掛け算との違いを決定的な例で見ます。
  65. 5:43四十二億九千四百九十六万七千二百九十五同士を掛けると、数学的な積は非常に大きな整数になります。
  66. 5:52マス・アイマルで計算すれば結果は一です。
  67. 5:55ところが通常の掛け算をしてから三十二ビットへ変換すると、結果はゼロになってしまいます。
  68. 6:03通常の数値では、この大きな積を正確に保持できず、掛け算の時点で下位の情報が丸められてしまうためです。
  69. 6:11後から変換しても、失われた情報は戻りません。
  70. 6:15三十二ビットの積が必要な処理では、変換を後付けせず、掛け算そのものにマス・アイマルを使ってください。
  71. 6:24この結果も実機で確認済みです。
  72. 6:27注意点を二つ整理します。
  73. 6:29一つ目は入力の扱いです。
  74. 6:31マス・アイマルは、入力が業務上正しい整数かどうかを検証する関数ではありません。
  75. 6:38文字列の五は数値の五として変換され、小数も切り捨てられて計算が進んでしまいます。
  76. 6:45入力ミスを見逃したくない処理では、呼び出す前に型と許容範囲を自分で検証してください。
  77. 6:52ビッグイントを引数に渡すとタイプエラーになるため、桁あふれなしで大きな整数を計算したい場合は、
  78. 6:58ビッグイント同士の通常の乗算を検討します。
  79. 7:04二つ目は用途の限界です。
  80. 7:06今回の振り分け計算は暗号学的なハッシュではないため、パスワードの保存、改ざん検知、
  81. 7:11一意な識別子の生成には使えません。
  82. 7:16活用場面とまとめです。
  83. 7:18名前ごとの色分けでは、四色の配列を用意し、振り分け関数の戻り値を配列の位置として使うだけで、
  84. 7:24同じ名前には常に同じ色が割り当てられます。
  85. 7:29再現性のあるテストデータの割り当ても同様です。
  86. 7:33改善するなら、結果を保存する前に代表的な入力で分布を確認してください。
  87. 7:39四つのグループへ均等に分かれる保証はないためです。
  88. 7:43また、グループ数や計算規則を変えると既存の割り当ても変わってしまうので、
  89. 7:49永続的な割り当てが必要なら、計算結果を記録する設計も検討しましょう。
  90. 7:55まずは身近な文字列で試し、三十二ビットで掛ける感覚をつかんでみてください。
  91. 8:01お疲れさまでした。
日本語字幕をダウンロード(WebVTT)

この動画で学べること

Math.imul()で32ビット整数の乗算を行う方法を解説。通常の掛け算との違い、文字列を使った振り分け例、ブラウザーとNode.jsの実行手順、期待出力と入力の制約を学べます。

解説記事・サンプルコードを読む:JavaScriptのMath.imul():32ビット整数の乗算で安定した振り分けを作る →