Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
RG-Arch 輪講資料: Binary Hacks Rebooted 数値演算など
Search
kota-yata
October 20, 2025
Programming
0
20
RG-Arch 輪講資料: Binary Hacks Rebooted 数値演算など
kota-yata
October 20, 2025
Tweet
Share
More Decks by kota-yata
See All by kota-yata
結局QUICで通信は速くなるの?
kota_yata
10
7.8k
RG-Arch輪考資料: QUIC is not Quick Enough over Fast Internet
kota_yata
0
110
RG-Arch輪考資料: Implementation and Performance Evaluation of the QUIC Protocol in Linux Kernel
kota_yata
0
120
2024年秋 中村研 WIP発表資料
kota_yata
0
64
パタヘネ輪読: 第五章
kota_yata
0
30
パタヘネ輪読: 第一章
kota_yata
0
210
2023年秋 中村研 WIP発表資料
kota_yata
0
110
2023年春 中澤大越研 WIP発表資料
kota_yata
0
65
BigIntの良いとこ悪いとこ
kota_yata
0
100
Other Decks in Programming
See All in Programming
Verilator + Rust + gRPC と Efinix の RISC-V でAIアクセラレータをAIで作ってる話 RTLを語る会(18) 2025/11/08
ryuz88
0
320
マイベストのシンプルなデータ基盤の話 - Googleスイートとのつき合い方 / mybest-simple-data-architecture-google-nized
snhryt
0
130
AkarengaLT vol.38
hashimoto_kei
1
140
Amazon Bedrock Knowledge Bases Hands-on
konny0311
0
130
組織もソフトウェアも難しく考えない、もっとシンプルな考え方で設計する #phpconfuk
o0h
PRO
10
3.4k
AIを駆使して新しい技術を効率的に理解する方法
nogu66
0
270
マンガアプリViewerの大画面対応を考える
kk__777
0
460
Pythonに漸進的に型をつける
nealle
1
160
ネストしたdata classの面倒な更新にさようなら!Lensを作って理解するArrowのOpticsの世界
shiita0903
1
290
問題の見方を変える「システム思考」超入門
panda_program
0
170
ビルドプロセスをデバッグしよう!
yt8492
0
270
Kotlin + Power-Assert 言語組み込みならではのAssertion Library採用と運用ベストプラクティス by Kazuki Matsuda/Gen-AX
kazukima
0
100
Featured
See All Featured
Side Projects
sachag
455
43k
Raft: Consensus for Rubyists
vanstee
140
7.2k
BBQ
matthewcrist
89
9.9k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
31
2.7k
4 Signs Your Business is Dying
shpigford
186
22k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
36
6.1k
A Modern Web Designer's Workflow
chriscoyier
697
190k
Git: the NoSQL Database
bkeepers
PRO
431
66k
Music & Morning Musume
bryan
46
6.9k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.5k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
For a Future-Friendly Web
brad_frost
180
10k
Transcript
Binary Hacks Rebooted イントロ, 数値演算 RG Arch輪講第1回 Presenter: Arch B3
Kota
⽬次 • 1章: イントロダクション ◦ fileコマンドを使わずにファイルの種類を調べる ◦ libcのwrite()を使った標準出⼒ • 7章:
数値表現とデータ処理Hack ◦ 符号付き整数 ◦ エンディアン ◦ 固定⼩数点数 ◦ 可変⻑表現(Zig-zag, UTF-8) ◦ 浮動⼩数点数 ◦ NaN 2
1章-fileコマンドを使わずにファイルの種類を調べる 3 • fileコマンドは特定のファイルの形式,属性を調べるUnixコマンド ◦ 拡張⼦がなくても調べられる • 多くのファイルにはマジックナンバーがあり,最初の数バイトを⾒ると種類が 分かる ◦
e.g. jpgはffd8ffe0,gzipは1f8b ◦ https://en.wikipedia.org/wiki/List_of_file_signatures • コマンド⾃体のhexdumpをするとELFのマジックナンバーが⾒えたりする ◦ Unixにおいて「全てはファイル」 • 古い.tarなどはマジックナンバーを持たず,独⾃の判定ロジックがある
1章-libcのwrite()を使った標準出⼒ 4 • Unix系のOS(Mac OSやLinux OS)においてはファイルディスクリプタの1番 は標準出⼒にアサインされている ◦ ちなみに0番は標準⼊⼒,2番は標準エラー出⼒ ◦
ターミナルが標準出⼒”ファイル”を開いているというイメージ • print(“Hello world!”)は実質標準出⼒ファイルに書き込みしているのと⼀緒 • つまりwrite()でもprintと同じことができる!
7章 数値表現とデータ処理Hack 5
符号なし整数と符号付き整数 • 整数の表現⽅法として符号なし整数と符号付き整数がある(uint, int) • 符号なし整数は2進整数をそのまま表現する ◦ 7 = 00000111(uint8の場合)
• 符号あり整数の場合,表現できる最⼤値の下半分は正の値に使い,上半分は補 数を⽤いて負の値を表現する 6
符号付き整数(int8の例) 7 • 00000000~01111111までは正の値の表現に使う ◦ 符号なし整数と同様の表現⽅法(7=00000111) • 10000000~11111111までは負の値の表現に使う ◦ 「その値の絶対値を⾜したらちょうど桁上がりする値」を負の値とする
◦ 7の2進数表現は00000111なので11111001を⾜せば桁上がりする ◦ これを2の補数表現という • 結果的に8ビットで-128~127を表現できる
補数表現を使うことのメリット 例:-7 -> 0b10000111 とすれば下位7ビットは符号なし整数と同じ.. • 減算を加算で表現できる ◦ 例:7-8を7+(-8)とする ◦
0b00000111 + 0b11111000 = 0b11111111 = -1 ◦ 負の値同⼠の加算もオーバーフローを無視すれば同様に演算が可能 • 0が⼀意に決まる ◦ ⼀番上の例だと+0と-0という⼆つの0が誕⽣する ◦ 0が⼀意に決まる(0b0)補数表現の⽅が楽 8 「MSBを符号ビットとすればそのあとは値をそのまま格納できて直感的では?」
符号拡張 9 • CPUアーキテクチャによっては8ビットや16ビットの変数に対応する幅の命令 がない場合がある ◦ x86-64では切り離せなかった後⽅互換性により8, 16, 32, 64ビット全ての幅に対す
る整数演算命令がある ◦ Arm64など⽐較的新しいアーキテクチャでは32ビットと64ビット幅の整数演算命令 しかない • 演算の前後でレジスタのビット幅に合致するように値を拡張する必要がある ◦ 上位に挿⼊する各桁を符号ビットと同じ値にすれば良い ◦ e.g. 11111001 -> 1111111111111001
エンディアン 10 • 値の上位,下位桁をメモリの上位,下位バイトのどちらと対応させるか ◦ ビッグエンディアン:値の上位がメモリの下位 ◦ リトルエンディアン:値の上位がメモリの上位 例:0xABCDEF01という値を格納する時 メモリ下位
メモリ上位
エンディアン 11 • ネットワークパケットのヘッダー情報はビッグエンディアンと定められている ◦ これはネットワークバイトオーダーと呼ばれる ◦ 各プロトコルで明確に定められているというよりはRFC1700などで慣習として記さ れている •
⼀⽅エンド端末では⼀般にリトルエンディアンが⽤いられる ◦ 幅が異なる変数にキャストした時とかに下位ビットが保持されるメリットがある ◦ ネットワークパケットを作る際はhton関数で変換するのが⼀般的 ◦ x86_64にはbswapやmovbe(拡張命令セット)などの変換命令がある
固定⼩数点数 12 • ⼩数点以下のビット数が固定されている数値型 • 整数部分を8ビット,⼩数部分を8ビットとする符号付き固定⼩数点がある時分 解能は1/256になる(最⼤値は127.996くらい) ◦ 精度がある程度分かっている値を扱う際は固定⼩数点で⼗分なケースがある •
ハードウェア的には整数演算と同じユニットを使えるため,浮動⼩数点と⽐較 して演算の効率が良い
可変⻑表現 13
可変⻑表現 14 • 整数を表現するビット列から冗⻑な部分を取り除いて必要最⼩限のビット数に 圧縮する技術 ◦ WebAssemblyの整数値の格納にはLEB128が使われている ▪ 各バイトについてMSBを継続ビットとし,下位7ビットを実際の数値とする ▪
5 -> 00000101, 300 -> 10101100 00000010 ◦ Protocol BufferではZig-zagエンコーディングが使われている
可変⻑表現-Zig-zagエンコーディング 15 • 2の補数を⽤いる符号付き整数とは対照的に,LSBを符号ビットとする ◦ 0b00000000: 0 ◦ 0b00000001: -1
◦ 0b00000010: 1 ◦ 0b00000011: -2 ◦ 0b00000100: 2 ◦ … ◦ 0b01111111: -127 ◦ 0b11111110: 127 ◦ 0b11111111: -128 例:-1を符号付き整数で表現したい時 • 2の補数表現の場合LEB128で10バイト • Zig-zagを使えばLEB128で1バイト! ⼩さな値は必ず少ないバイト数で表現できる
UTF-8 • LEB128とかなり似ている ◦ 継続ビットを⽤いる点では同じ 16 漢字は⼤体hex4桁なので3バイト必要🥺
おまけ:UTF-16 17 • Unicodeコードポイント U+0000〜U+FFFFはそのまま2バイトで表現 ◦ ⽇本語の常⽤漢字も2バイト! • U+10000〜U+10FFFFは「サロゲート」に分割される ◦
UnicodeにおいてU+D800〜U+DBFFは上位サロゲート,U+DC00〜U+DFFFは下位 サロゲートという予約領域になっている ◦ コードポイント-0x10000をして,結果の上位10ビットを上位,下位10ビットを下 位サロゲートに格納
UTF-16エンコードの例 18 • 0x1F97A - 0x10000 = 0xF97A = 0b00001111100101111010(20ビット)
• 上位10桁と0xD800(上位サロゲートのベース値)と⾜す -> 0xD83E • 残りの桁と0xDC00(下位サロゲートのベース値)と⾜す -> 0xDD7A 🥺はD8 3E DD 7Aの4バイトにエンコードされる 🥺 (U+1F97A)
浮動⼩数点 19
浮動⼩数点数 20 • ⼩数を含む値を仮数部,指数部分に分けて表現する ◦ sが符号ビット,mが仮数部,eが指数部 ◦ b(基数)は⼀般には2(IEEE 754).IEEE754-2008で基数10の仕様が追加された ◦
基数10の例:125.5 = 1.255 * 10^2 ◦ 基数2の例:0.01(10進数で0.25)= 1.0 * 2^-2
浮動⼩数点の正規化 21 • IEEE754では,浮動⼩数点の仮数部は常に”正規化”される ◦ 仮数部のMSBが0でない数になる(e.g. 0.034 -> 3.4, 0.254
-> 2.54) ◦ つまり2進数で表現する時,整数部分は必ず1になるように指数が調整される ▪ e.g. 0.00101 -> 1.01 * 2^-3 ▪ 必ず1なので,実際には仮数部は⼩数点以下から格納される(ケチ表現) • 指数部は”バイアス”をかけて符号なし整数にする ◦ 例えば指数部が8ビットだった場合,実際の値+127をする ◦ 本来-126~127の値が,1~254になる(0は0.0, 255はNaNとinfiniteの表現に使う)
浮動⼩数点のデータ構造 22 • 指数部はバイアスがかかっているので符号なし整数 • 仮数部は⼩数点以下の値を格納
浮動⼩数点の加算 23 • 加算対象の⼆つの値の内指数が⼤きい⽅に合わせる ◦ 1.111 * 2^2 + 1.011
* 2^3の場合指数3に合わせる ◦ 1.111 * 2^2 -> 0.1111 * 2^3 ◦ この段階で⽚⽅の精度が落ちる • 指数を合わせたら仮数部を⾜す ◦ 0.1111 + 1.011 = 10.0101 • 正規化する ◦ 1.00101 * 2^4
丸め 24 • 多くの演算では加算時に桁上がりが発⽣し,値を丸める必要が出てくる • 最もよく使われる丸めかたは”roundTiesToEven” ◦ 最も近い浮動⼩数点数に丸める.ちょうど中間ならLSBが0の⽅に丸める ◦ 例:1.10001₂(=1.53125₁₀)はちょうど1.1000₂
(=1.5₁₀)と1.1001₂ (=1.5625₁₀)の間 ▪ この場合LSBが0の1.1000₂に合わせる • この丸めによってfloat同⼠の等価演算がfalseになったりする ◦ 0.1 + 0.2 !== 0.3 とか
25 NaNの種類
NaNは2種類ある Signaling NaN 26 • 演算の⼊⼒に含まれているとinvalid operation例外を発⽣させる • 未初期化変数を誤って演算に使った際などの検出に使う Quiet
NaN • 主に数値演算の結果として⽣成されるNaN • 演算時のinvalid operationの結果はデフォルトでquite NaN 表現としては,仮数部のMSBが1ならquiet NaN,0ならsignaling NaN…
実はそうとも限らない 27 • IEEE754-1985の時点では⼆種類のNaNの区別はされていなかった • 前述のような区別がなされたのはIEEE754-2008から • MIPSやPA-RISCなど古のアーキテクチャではquite NaNでもMSBが⽴っていな い場合がある
• とはいえ現代的なアーキテクチャであればほとんどIEEE754-2008の仕様通り の実装になっている
Signaling NaNを作ってみよう! 28 • 実際に⼿動でSignaling NaNを作って,演算の⼊⼒に含めてみる • 演算結果がQuite NaNになり,Invalid Operationフラグが⽴つかどうかを確か
めてよう! できたコードがこちら→
学べたこと 29 • 符号付き,符号なしの整数表現と2の補数表現 • 符号拡張,エンディアン,固定⼩数点 • 浮動⼩数点の表現⽅法と演算 • NaNの種類