This commit is contained in:
krahets
2026-03-30 08:17:41 +08:00
parent 68cafe99dd
commit 46bccf0065
484 changed files with 60193 additions and 20315 deletions
@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="アニメーション図解ワンクリック実行データ構造とアルゴリズムチュートリアル">
<meta name="description" content="アニメーション図解ワンクリック実行コードで学べるデータ構造とアルゴリズムの入門書">
<meta name="author" content="krahets">
@@ -117,7 +117,7 @@
<path
d="M480 32c0-12.9-7.8-24.6-19.8-29.6s-25.7-2.2-34.9 6.9L381.7 53c-48 48-113.1 75-181 75H192 160 64c-35.3 0-64 28.7-64 64v96c0 35.3 28.7 64 64 64l0 128c0 17.7 14.3 32 32 32h64c17.7 0 32-14.3 32-32V352l8.7 0c67.9 0 133 27 181 75l43.6 43.6c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6V300.4c18.6-8.8 32-32.5 32-60.4s-13.4-51.6-32-60.4V32zm-64 76.7V240 371.3C357.2 317.8 280.5 288 200.7 288H192V192h8.7c79.8 0 156.5-29.8 215.3-83.3z" />
</svg>
<span>日本語版審閱者を募集しています!詳細<a href="https://github.com/krahets/hello-algo/blob/main/ja/CONTRIBUTING.md">CONTRIBUTING.md</a>参照してください。</span>
<span>日本語版のレビュアーを募集しています。詳しく<a href="/ja/chapter_appendix/contribution/">こちら</a>ご覧ください。</span>
</div>
</div>
@@ -341,7 +341,7 @@
<span class="md-ellipsis">
はじめに
@@ -358,7 +358,7 @@
<span class="md-nav__icon md-icon"></span>
はじめに
</label>
@@ -618,7 +618,7 @@
<span class="md-ellipsis">
1.1 &nbsp; アルゴリズムはどこにでもある
1.1 &nbsp; アルゴリズムは至るところにある
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 &nbsp; アルゴリズムとは何か
1.2 &nbsp; アルゴリズムとは
@@ -783,7 +783,7 @@
<span class="md-ellipsis">
2.1 &nbsp; アルゴリズム効率評価
2.1 &nbsp; アルゴリズム効率評価
@@ -1071,7 +1071,7 @@
<span class="md-ellipsis">
3.3 &nbsp; 数値の符号化 *
3.3 &nbsp; 数値エンコーディング *
@@ -1089,7 +1089,7 @@
<span class="md-ellipsis">
3.3 &nbsp; 数値の符号化 *
3.3 &nbsp; 数値エンコーディング *
@@ -1116,10 +1116,10 @@
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#331" class="md-nav__link">
<a href="#331-1-2" class="md-nav__link">
<span class="md-ellipsis">
3.3.1 &nbsp; 整数エンコーディング
3.3.1 &nbsp; 符号付き絶対値表現、1 の補数、2 の補数
</span>
</a>
@@ -1130,7 +1130,7 @@
<a href="#332" class="md-nav__link">
<span class="md-ellipsis">
3.3.2 &nbsp; 浮動小数点数エンコーディング
3.3.2 &nbsp; 浮動小数点数エンコーディング
</span>
</a>
@@ -1160,7 +1160,7 @@
<span class="md-ellipsis">
3.4 &nbsp; 文字の符号化 *
3.4 &nbsp; 文字エンコーディング *
@@ -1663,7 +1663,7 @@
<span class="md-ellipsis">
第 6 章 &nbsp; ハッシュ
第 6 章 &nbsp; ハッシュテーブル
@@ -1685,7 +1685,7 @@
<span class="md-nav__icon md-icon"></span>
第 6 章 &nbsp; ハッシュ
第 6 章 &nbsp; ハッシュテーブル
</label>
@@ -1707,7 +1707,7 @@
<span class="md-ellipsis">
6.1 &nbsp; ハッシュ
6.1 &nbsp; ハッシュテーブル
@@ -2014,7 +2014,7 @@
<span class="md-ellipsis">
7.5 &nbsp; AVL木 *
7.5 &nbsp; AVL 木 *
@@ -2177,7 +2177,7 @@
<span class="md-ellipsis">
8.2 &nbsp; ヒープ構築操作
8.2 &nbsp; ヒープ構築
@@ -2563,7 +2563,7 @@
<span class="md-ellipsis">
10.2 &nbsp; 二分探索の挿入
10.2 &nbsp; 二分探索の挿入位置
@@ -2619,7 +2619,7 @@
<span class="md-ellipsis">
10.4 &nbsp; ハッシュ最適化戦略
10.4 &nbsp; ハッシュによる最適化戦略
@@ -2647,7 +2647,7 @@
<span class="md-ellipsis">
10.5 &nbsp; 探索アルゴリズムの再認識
10.5 &nbsp; 探索アルゴリズム再考
@@ -3185,7 +3185,7 @@
<span class="md-ellipsis">
12.1 &nbsp; 分割統治アルゴリズム
12.1 &nbsp; 分割統治
@@ -3241,7 +3241,7 @@
<span class="md-ellipsis">
12.3 &nbsp; 木の構築問題
12.3 &nbsp; 二分木の構築問題
@@ -3269,7 +3269,7 @@
<span class="md-ellipsis">
12.4 &nbsp; ハノイの塔問題
12.4 &nbsp; ハノイの塔問題
@@ -3462,7 +3462,7 @@
<span class="md-ellipsis">
13.3 &nbsp; 部分集合和問題
13.3 &nbsp; 部分和問題
@@ -3490,7 +3490,7 @@
<span class="md-ellipsis">
13.4 &nbsp; Nクイーン問題
13.4 &nbsp; n クイーン問題
@@ -3631,7 +3631,7 @@
<span class="md-ellipsis">
14.1 &nbsp; 動的計画法の初歩
14.1 &nbsp; 動的計画法入門
@@ -3659,7 +3659,7 @@
<span class="md-ellipsis">
14.2 &nbsp; DP 問題特性
14.2 &nbsp; 動的計画法の問題特性
@@ -3687,7 +3687,7 @@
<span class="md-ellipsis">
14.3 &nbsp; DP の解法の考え方
14.3 &nbsp; 動的計画法の問題解決の考え方
@@ -3715,7 +3715,7 @@
<span class="md-ellipsis">
14.4 &nbsp; 0-1ナップサック問題
14.4 &nbsp; 0-1 ナップサック問題
@@ -3908,7 +3908,7 @@
<span class="md-ellipsis">
15.1 &nbsp; 貪欲アルゴリズム
15.1 &nbsp; 貪欲
@@ -4153,7 +4153,7 @@
<span class="md-ellipsis">
16.2 &nbsp; 一緒に作に参加する
16.2 &nbsp; 一緒に作に参加しましょう
@@ -4296,10 +4296,10 @@
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#331" class="md-nav__link">
<a href="#331-1-2" class="md-nav__link">
<span class="md-ellipsis">
3.3.1 &nbsp; 整数エンコーディング
3.3.1 &nbsp; 符号付き絶対値表現、1 の補数、2 の補数
</span>
</a>
@@ -4310,7 +4310,7 @@
<a href="#332" class="md-nav__link">
<span class="md-ellipsis">
3.3.2 &nbsp; 浮動小数点数エンコーディング
3.3.2 &nbsp; 浮動小数点数エンコーディング
</span>
</a>
@@ -4357,21 +4357,21 @@
<h1 id="33">3.3 &nbsp; 数値エンコーディング *<a class="headerlink" href="#33" title="Permanent link">&para;</a></h1>
<div class="admonition tip">
<p class="admonition-title">Tip</p>
<p>本書では、アスタリスク「*」が付いた章は任意読書です。時間が不足している場合や難しいと感じる場合は、最初はこれらをスキップして、必須の章を完了した後に戻ることができます</p>
<p>本書では、タイトルに * 記号が付いている章は選読です。時間が限られている場合や理解が難しいと感じる場合は、いったん読み飛ばし、必読章を終えてから個別に取り組んでください</p>
</div>
<h2 id="331">3.3.1 &nbsp; 整数エンコーディング<a class="headerlink" href="#331" title="Permanent link">&para;</a></h2>
<p>節の表、すべての整数型は正数よりも1つ多い負の数を表現できることを観察しました。例えば<code>byte</code>の範囲は<span class="arithmatex">\([-128, 127]\)</span>です。この現象は直感に反するように見え、その根本的な理由には符号絶対値、1の補数、2の補数エンコーディングの知識が関与しています。</p>
<p>まず重要なことは、**数値はコンピュータ内で2の補数形式で格納される**ということです。なぜそうなのかを分析する前に、これら3つのエンコーディング方法を定義しましょう:</p>
<h2 id="331-1-2">3.3.1 &nbsp; 符号付き絶対値表現、1 の補数、2 の補数<a class="headerlink" href="#331-1-2" title="Permanent link">&para;</a></h2>
<p>前節の表を見ると、すべての整数型で表せる負数の個数は正数より 1 つ多く、たとえば <code>byte</code> の値域は <span class="arithmatex">\([-128, 127]\)</span> です。この現象は直感に反するように見えますが、その背景には符号付き絶対値表現、1 の補数、2 の補数に関する知識があります。</p>
<p>まず押さえておくべきなのは、**数値はコンピュータ内で「2 の補数」の形で保存される**ということです。その理由を説明する前に、まずはこの 3 つの定義を示します。</p>
<ul>
<li><strong>符号絶対値</strong>:数値の二進表現の最上位ビットを符号ビットとし、<span class="arithmatex">\(0\)</span>は正数、<span class="arithmatex">\(1\)</span>は負数を表します。残りのビット数値の値を表します。</li>
<li><strong>1の補数</strong>:正数の1の補数は符号絶対値と同じです。負の数の場合、符号ビット以外のすべてのビットを反転して得られます。</li>
<li><strong>2の補数</strong>:正数の2の補数は符号絶対値と同じです。負の数の場合、その1の補数に<span class="arithmatex">\(1\)</span>を加えて得られます。</li>
<li><strong>符号付き絶対値表現</strong>:数値の二進表現の最上位ビットを符号ビットとみなし、<span class="arithmatex">\(0\)</span> は正数、<span class="arithmatex">\(1\)</span> は負数を表し残りのビット数値の値を表します。</li>
<li><strong>1 の補数</strong>:正数の 1 の補数は符号付き絶対値表現と同じで、負数の 1 の補数は符号ビットを除くすべてのビットを反転したものです。</li>
<li><strong>2 の補数</strong>:正数の 2 の補数は符号付き絶対値表現と同じで、負数の 2 の補数は 1 の補数に <span class="arithmatex">\(1\)</span> を加えたものです。</li>
</ul>
<p>以下の図は、符号絶対値、1の補数、2の補数の変換を示しています</p>
<p><img alt="符号絶対値、1の補数、2の補数の変換" class="animation-figure" src="../number_encoding.assets/1s_2s_complement.png" /></p>
<p align="center"> 図 3-4 &nbsp; 符号絶対値、1の補数、2の補数の変換 </p>
<p>図は、符号付き絶対値表現、1 の補数、2 の補数の変換方法を示しています</p>
<p><img alt="符号付き絶対値表現、1 の補数、2 の補数の相互変換" class="animation-figure" src="../number_encoding.assets/1s_2s_complement.png" /></p>
<p align="center"> 図 3-4 &nbsp; 符号付き絶対値表現、1 の補数、2 の補数の相互変換 </p>
<p><u>符号絶対値</u>は最も直感的ですが、制限があります。一つには<strong>符号絶対値の負の数は計算で直接使用できません</strong>えば符号絶対値<span class="arithmatex">\(1 + (-2)\)</span>を計算すると<span class="arithmatex">\(-3\)</span>になり、これは正しくありません</p>
<p><u>符号付き絶対値表現(sign-magnitude</u>は最も直感的ですが、いくつかの制約があります。まず<strong>負数の符号付き絶対値表現はそのまま演算に使えません</strong>たとえば符号付き絶対値表現で <span class="arithmatex">\(1 + (-2)\)</span> を計算すると、結果は <span class="arithmatex">\(-3\)</span> になってしまい、これは明らかに誤りです</p>
<div class="arithmatex">\[
\begin{aligned}
&amp; 1 + (-2) \newline
@@ -4380,96 +4380,96 @@
&amp; \rightarrow -3
\end{aligned}
\]</div>
<p>この問題に対処するため、コンピュータは<u>1の補数</u>導入ました。1の補数に変換して<span class="arithmatex">\(1 + (-2)\)</span>を計算し、結果を符号絶対値に戻すと、正しい結果<span class="arithmatex">\(-1\)</span>が得られます。</p>
<p>この問題を解決するため、コンピュータ<u>1 の補数1's complement</u>導入されました。まず符号付き絶対値表現を 1 の補数に変換し、1 の補数で <span class="arithmatex">\(1 + (-2)\)</span> を計算してから、結果を 1 の補数から符号付き絶対値表現へ戻すと、正しい結果 <span class="arithmatex">\(-1\)</span> が得られます。</p>
<div class="arithmatex">\[
\begin{aligned}
&amp; 1 + (-2) \newline
&amp; \rightarrow 0000 \; 0001 \; \text{(符号絶対値)} + 1000 \; 0010 \; \text{(符号絶対値)} \newline
&amp; = 0000 \; 0001 \; \text{(1の補数)} + 1111 \; 1101 \; \text{(1の補数)} \newline
&amp; = 1111 \; 1110 \; \text{(1の補数)} \newline
&amp; = 1000 \; 0001 \; \text{(符号絶対値)} \newline
&amp; \rightarrow 0000 \; 0001 \; \text{(符号付き絶対値表現)} + 1000 \; 0010 \; \text{(符号付き絶対値表現)} \newline
&amp; = 0000 \; 0001 \; \text{(1 の補数)} + 1111 \; 1101 \; \text{(1 の補数)} \newline
&amp; = 1111 \; 1110 \; \text{(1 の補数)} \newline
&amp; = 1000 \; 0001 \; \text{(符号付き絶対値表現)} \newline
&amp; \rightarrow -1
\end{aligned}
\]</div>
<p>また<strong>符号絶対値では0に2つの表現があります</strong><span class="arithmatex">\(+0\)</span><span class="arithmatex">\(-0\)</span>です。これは0に対して2つの異なる二進エンコーディングがあることを意味し、曖昧さを引き起こす可能性があります。えば条件チェックで正と負の0を区別しないと、正しくない結果になる可能性があります。この曖昧さに対処するには追加のチェックが必要で、計算効率が低下する可能性があります。</p>
<p>一方<strong>数値 0 の符号付き絶対値表現には <span class="arithmatex">\(+0\)</span><span class="arithmatex">\(-0\)</span> の 2 つの表し方があります</strong>。つまり、数値 0 に対して異なる 2 つの二進コードが対応しており、これは曖昧さの原因になります。たとえば条件判定で正のゼロと負のゼロを区別しないと、誤った判定結果になる可能性があります。また、この曖昧さを解消しようとすると追加の判定処理が必要になり、計算効率が下がるおそれがあります。</p>
<div class="arithmatex">\[
\begin{aligned}
+0 &amp; \rightarrow 0000 \; 0000 \newline
-0 &amp; \rightarrow 1000 \; 0000
\end{aligned}
\]</div>
<p>符号絶対値と同様に、1の補数も正負の0の曖昧さに悩まされます。そのため、コンピュータはさらに<u>2の補数</u>を導入しました。符号絶対値、1の補数、2の補数における負の0の変換過程を観察してみましょう</p>
<p>符号付き絶対値表現と同様に、1 の補数も正負のゼロの曖昧さがあります。そこでコンピュータはさらに<u>2 の補数2's complement</u>を導入しました。まずは負のゼロについて、符号付き絶対値表現、1 の補数、2 の補数の変換を見てみましょう</p>
<div class="arithmatex">\[
\begin{aligned}
-0 \rightarrow \; &amp; 1000 \; 0000 \; \text{(符号絶対値)} \newline
= \; &amp; 1111 \; 1111 \; \text{(1の補数)} \newline
= 1 \; &amp; 0000 \; 0000 \; \text{(2の補数)} \newline
-0 \rightarrow \; &amp; 1000 \; 0000 \; \text{(符号付き絶対値表現)} \newline
= \; &amp; 1111 \; 1111 \; \text{(1 の補数)} \newline
= 1 \; &amp; 0000 \; 0000 \; \text{(2 の補数)} \newline
\end{aligned}
\]</div>
<p>負の0の1の補数に<span class="arithmatex">\(1\)</span>を加えると桁上がりが発生しますが、<code>byte</code>の長さは8ビットのみのため、9番目のビットへの桁上がり<span class="arithmatex">\(1\)</span>は破棄されます。したがって、**負の0の2の補数は<span class="arithmatex">\(0000 \; 0000\)</span>**で、正の0と同じになり、曖昧さが解決されます。</p>
<p>最後の謎は、<code>byte</code><span class="arithmatex">\([-128, 127]\)</span>の範囲で、追加の負の数<span class="arithmatex">\(-128\)</span>があることです。<span class="arithmatex">\([-127, +127]\)</span>の区間では、すべての整数に対応する符号絶対値、1の補数、2の補数があり、相互変換が可能であることを観察します。</p>
<p>しかし、<strong>2の補数<span class="arithmatex">\(1000 \; 0000\)</span>対応する符号絶対値を持たない例外です</strong>。変換方法によると、その符号絶対値は<span class="arithmatex">\(0000 \; 0000\)</span>で、0を示します。これは矛盾を示しています。なぜなら、その2の補数は自分自身を表すべきだからです。コンピュータは、この特別な2の補数<span class="arithmatex">\(1000 \; 0000\)</span><span class="arithmatex">\(-128\)</span>を表すものとして指定しています。実際、2の補数での<span class="arithmatex">\((-1) + (-127)\)</span>の計算結果は<span class="arithmatex">\(-128\)</span>になります。</p>
<p>負のゼロの 1 の補数に <span class="arithmatex">\(1\)</span> を加えると桁上がりが発生しますが、<code>byte</code>の長さは 8 ビットしかないため、第 9 ビットへあふれた <span class="arithmatex">\(1\)</span> は捨てられます。つまり、<strong>負のゼロの 2 の補数は <span class="arithmatex">\(0000 \; 0000\)</span> であり、正のゼロの 2 の補数と同じです</strong>。そのため、2 の補数表現ではゼロは 1 つしか存在せず、正負のゼロの曖昧さは解消されます。</p>
<p>最後にもう 1 つ疑問が残ります。<code>byte</code> 型の値域は <span class="arithmatex">\([-128, 127]\)</span> ですが、余分にある負数 <span class="arithmatex">\(-128\)</span> はどのように得られるのでしょうか。区間 <span class="arithmatex">\([-127, +127]\)</span> にあるすべての整数には、それぞれ対応する符号付き絶対値表現、1 の補数、2 の補数があり、符号付き絶対値表現と 2 の補数の間は相互変換できます。</p>
<p>しかし、<strong>2 の補数 <span class="arithmatex">\(1000 \; 0000\)</span> だけは例外で、対応する符号付き絶対値表現を持ちません</strong>。変換規則に従うと、この 2 の補数に対応する符号付き絶対値表現は <span class="arithmatex">\(0000 \; 0000\)</span> になります。これは明らかに矛盾しています。なぜなら、この符号付き絶対値表現は数値 <span class="arithmatex">\(0\)</span> を表し、その 2 の補数は自分自身であるはずだからです。コンピュータは、この特別な 2 の補数 <span class="arithmatex">\(1000 \; 0000\)</span><span class="arithmatex">\(-128\)</span> と定めています。実際、2 の補数での <span class="arithmatex">\((-1) + (-127)\)</span> の計算結果はちょうど <span class="arithmatex">\(-128\)</span> になります。</p>
<div class="arithmatex">\[
\begin{aligned}
&amp; (-127) + (-1) \newline
&amp; \rightarrow 1111 \; 1111 \; \text{(符号絶対値)} + 1000 \; 0001 \; \text{(符号絶対値)} \newline
&amp; = 1000 \; 0000 \; \text{(1の補数)} + 1111 \; 1110 \; \text{(1の補数)} \newline
&amp; = 1000 \; 0001 \; \text{(2の補数)} + 1111 \; 1111 \; \text{(2の補数)} \newline
&amp; = 1000 \; 0000 \; \text{(2の補数)} \newline
&amp; \rightarrow 1111 \; 1111 \; \text{(符号付き絶対値表現)} + 1000 \; 0001 \; \text{(符号付き絶対値表現)} \newline
&amp; = 1000 \; 0000 \; \text{(1 の補数)} + 1111 \; 1110 \; \text{(1 の補数)} \newline
&amp; = 1000 \; 0001 \; \text{(2 の補数)} + 1111 \; 1111 \; \text{(2 の補数)} \newline
&amp; = 1000 \; 0000 \; \text{(2 の補数)} \newline
&amp; \rightarrow -128
\end{aligned}
\]</div>
<p>お気づきかもしれませんが、これらの計算はすべて加算であり、重要な事実を示しています<strong>コンピュータ内部ハードウェア回路は主に加算演算を中心に設計されています</strong>。これは、加算が乗算、除算、減算などの他の演算と比較してハードウェアで実装しやすく、並列化が容易で高速計算が可能だからです。</p>
<p>これはコンピュータが加算のみを実行できることを意味するものではありません。<strong>加算と基本的な論理演算を組み合わせることで、コンピュータは様々な他の数学演算を実できます</strong>えば減算<span class="arithmatex">\(a - b\)</span><span class="arithmatex">\(a + (-b)\)</span>に変換でき、乗算除算は複数の加算または減算に変換できます。</p>
<p>コンピュータで2の補数を使用する理由をまとめることができます:2の補数表現により、コンピュータは同じ回路と演算を使用して正と負数の加算を処理でき、減算用の特別なハードウェア回路の必要性を排除し、正負の0の曖昧さを回避できます。これによりハードウェア設計大幅に簡化され、算効率向上します。</p>
<p>2の補数の設計は非常に巧妙で、スペースの制約により、ここで停止します。興味のある読者はさらに探求することを奨励します</p>
<h2 id="332">3.3.2 &nbsp; 浮動小数点数エンコーディング<a class="headerlink" href="#332" title="Permanent link">&para;</a></h2>
<p>興味深いことに気づいたかもしれません:同じ4バイトの長さにもかかわらず、なぜ<code>float</code><code>int</code>と比較してはるかに大きい値の範囲を持つのでしょうかこれは直感に反するように見えます。<code>float</code>は分数を表現する必要があるため、範囲が縮小すると予想されるからです。</p>
<p>実際、<strong>これは浮動小数点数<code>float</code>)で使用される異なる表現方法によるものです</strong>。32ビットの二進数を次のように考えてみましょう:</p>
<p>すでにお気づきかもしれませんが、の計算はすべて加算です。これは重要な事実を示しています。**コンピュータ内部ハードウェア回路は、主として加算を基準に設計されている**のです。なぜなら、加算はほかの演算(乗算、除算、減算など)に比べてハードウェアで実装しやすく、並列化もしやすく、演算速度も速いからです。</p>
<p>ただし、これはコンピュータが加算しかできないという意味ではありません。<strong>加算といくつかの基本的な論理演算を組み合わせることで、コンピュータはさまざまな数学演算を実できます</strong>たとえば減算 <span class="arithmatex">\(a - b\)</span> は加算 <span class="arithmatex">\(a + (-b)\)</span> に変換できますし、乗算除算も繰り返しの加算または減算に変換できます。</p>
<p>これで、コンピュータが 2 の補数を使理由をまとめられます。2 の補数表現に基づけば、コンピュータは同じ回路と操作で正数と負数の加算を扱うことができ、減算用の特別なハードウェア回路を設計する必要がなく、正負のゼロの曖昧さも特別に処理しなくて済みます。これによりハードウェア設計大幅に簡化され、算効率向上します。</p>
<p>2 の補数の設計は非常に巧妙ですが、紙幅の都合上ここまでにします。興味のある読者はさらに深く調べてみてください</p>
<h2 id="332">3.3.2 &nbsp; 浮動小数点数エンコーディング<a class="headerlink" href="#332" title="Permanent link">&para;</a></h2>
<p>注意深い人なら気づくかもしれません。<code>int</code><code>float</code> はどちらも長さが 4 バイトで同じなのに、なぜ <code>float</code> の値域は <code>int</code> よりはるかに広いのでしょうかこれはかなり直感に反します。というのも、<code>float</code> は小数を表す必要があるので、本来なら値域は狭くなるはずだからです。</p>
<p>実際には<strong>これは浮動小数点数 <code>float</code> が異なる表現方法を採用しているためです</strong>。32 ビットの二進数を次のように表します。</p>
<div class="arithmatex">\[
b_{31} b_{30} b_{29} \ldots b_2 b_1 b_0
\]</div>
<p>IEEE 754標準によると、32ビットの<code>float</code>は次の3つの部分構成されます</p>
<p>IEEE 754 標準によれば、32-bit 長の <code>float</code> は次の 3 つの部分から構成されます</p>
<ul>
<li>符号ビット<span class="arithmatex">\(\mathrm{S}\)</span>1ビットを占有し<span class="arithmatex">\(b_{31}\)</span>に対応します。</li>
<li>指数ビット<span class="arithmatex">\(\mathrm{E}\)</span>8ビットを占有し<span class="arithmatex">\(b_{30} b_{29} \ldots b_{23}\)</span>に対応します。</li>
<li>仮数ビット<span class="arithmatex">\(\mathrm{N}\)</span>23ビットを占有し<span class="arithmatex">\(b_{22} b_{21} \ldots b_0\)</span>に対応します。</li>
<li>符号<span class="arithmatex">\(\mathrm{S}\)</span> 1 ビットを占<span class="arithmatex">\(b_{31}\)</span> に対応します。</li>
<li>指数<span class="arithmatex">\(\mathrm{E}\)</span> 8 ビットを占<span class="arithmatex">\(b_{30} b_{29} \ldots b_{23}\)</span> に対応します。</li>
<li>仮数<span class="arithmatex">\(\mathrm{N}\)</span> 23 ビットを占<span class="arithmatex">\(b_{22} b_{21} \ldots b_0\)</span> に対応します。</li>
</ul>
<p>二進<code>float</code>数の値は次のように計算されます</p>
<p>二進<code>float</code> に対応する値は次式で計算されます</p>
<div class="arithmatex">\[
\text{val} = (-1)^{b_{31}} \times 2^{\left(b_{30} b_{29} \ldots b_{23}\right)_2 - 127} \times \left(1 . b_{22} b_{21} \ldots b_0\right)_2
\text {val} = (-1)^{b_{31}} \times 2^{\left(b_{30} b_{29} \ldots b_{23}\right)_2-127} \times\left(1 . b_{22} b_{21} \ldots b_0\right)_2
\]</div>
<p>十進公式に変換すると、次のようになります</p>
<p>十進数に直すと、計算式は次のようになります</p>
<div class="arithmatex">\[
\text{val} = (-1)^{\mathrm{S}} \times 2^{\mathrm{E} - 127} \times (1 + \mathrm{N})
\text {val}=(-1)^{\mathrm{S}} \times 2^{\mathrm{E} -127} \times (1 + \mathrm{N})
\]</div>
<p>成分の範囲は:</p>
<p>項の取り得る範囲は次のとおりです。</p>
<div class="arithmatex">\[
\begin{aligned}
\mathrm{S} \in &amp; \{ 0, 1\}, \quad \mathrm{E} \in \{ 1, 2, \dots, 254 \} \newline
(1 + \mathrm{N}) = &amp; (1 + \sum_{i=1}^{23} b_{23-i} \times 2^{-i}) \subset [1, 2 - 2^{-23}]
(1 + \mathrm{N}) = &amp; (1 + \sum_{i=1}^{23} b_{23-i} 2^{-i}) \subset [1, 2 - 2^{-23}]
\end{aligned}
\]</div>
<p><img alt="IEEE 754標準での浮動小数点数の計算例" class="animation-figure" src="../number_encoding.assets/ieee_754_float.png" /></p>
<p align="center"> 図 3-5 &nbsp; IEEE 754標準での浮動小数点数の計算例 </p>
<p><img alt="IEEE 754 標準における float の計算例" class="animation-figure" src="../number_encoding.assets/ieee_754_float.png" /></p>
<p align="center"> 図 3-5 &nbsp; IEEE 754 標準における float の計算例 </p>
<p>図を観察すると、例のデータ<span class="arithmatex">\(\mathrm{S} = 0\)</span><span class="arithmatex">\(\mathrm{E} = 124\)</span><span class="arithmatex">\(\mathrm{N} = 2^{-2} + 2^{-3} = 0.375\)</span>が与えられた場合</p>
<p>上図をると、例として <span class="arithmatex">\(\mathrm{S} = 0\)</span><span class="arithmatex">\(\mathrm{E} = 124\)</span> <span class="arithmatex">\(\mathrm{N} = 2^{-2} + 2^{-3} = 0.375\)</span> が与えられた場合、次のようになります。</p>
<div class="arithmatex">\[
\text{val} = (-1)^0 \times 2^{124 - 127} \times (1 + 0.375) = 0.171875
\text { val } = (-1)^0 \times 2^{124 - 127} \times (1 + 0.375) = 0.171875
\]</div>
<p>これで最初の問に答えることができます:<strong><code>float</code>の表現には指数ビットが含まれているため、<code>int</code>よりはるかに大きい範囲を持ちます</strong>。上の計算に基づくと<code>float</code>で表現可能な最大正の数は<span class="arithmatex">\(2^{254 - 127} \times (2 - 2^{-23}) \approx 3.4 \times 10^{38}\)</span>で、最小負の数は符号ビットを切り替えることで得られます。</p>
<p><strong>しかし、<code>float</code>の拡張された範囲のトレードオフは精度犠牲</strong>。整数型<code>int</code>32ビットすべてを数値表現に使用し、値は均等に分布していますが、指数ビットのため、<code>float</code>値が大きほど、隣接する数値間の差大きくなります。</p>
<p>以下の表に示すように、指数ビット<span class="arithmatex">\(\mathrm{E} = 0\)</span><span class="arithmatex">\(\mathrm{E} = 255\)</span>は特別な意味を持ち<strong>0、無限大、<span class="arithmatex">\(\mathrm{NaN}\)</span>などを表現するために使用されます</strong></p>
<p align="center"> 表 3-2 &nbsp; 指数ビットの意味 </p>
<p>これで最初の問に答えられます。**<code>float</code> の表現方法には指数が含まれているため、その値域は <code>int</code> よりはるかに広い**のです。上の計算より<code>float</code> が表せる最大の正数は <span class="arithmatex">\(2^{254 - 127} \times (2 - 2^{-23}) \approx 3.4 \times 10^{38}\)</span> であり、符号ビットを切り替えれば最小の負数が得られます。</p>
<p><strong>浮動小数点数 <code>float</code> は値域を広げる一方で、その代償として精度犠牲にしていま</strong>。整数型 <code>int</code>32 ビットすべてを数値表現に使うため、数値は一様に分布します。しかし指数部があるため、浮動小数点数 <code>float</code>値が大きくなるほど、隣り合う 2 つの数の差大きくなる傾向があります。</p>
<p>次の表のとおり、指数部 <span class="arithmatex">\(\mathrm{E} = 0\)</span><span class="arithmatex">\(\mathrm{E} = 255\)</span>は特別な意味があり<strong>ゼロ、無限大、<span class="arithmatex">\(\mathrm{NaN}\)</span> などを表ために使れます</strong></p>
<p align="center"> 表 3-2 &nbsp; 指数の意味 </p>
<div class="center-table">
<table>
<thead>
<tr>
<th>指数ビットE</th>
<th>仮数ビット<span class="arithmatex">\(\mathrm{N} = 0\)</span></th>
<th>仮数ビット<span class="arithmatex">\(\mathrm{N} \ne 0\)</span></th>
<th>計算</th>
<th>指数E</th>
<th>仮数<span class="arithmatex">\(\mathrm{N} = 0\)</span></th>
<th>仮数<span class="arithmatex">\(\mathrm{N} \ne 0\)</span></th>
<th>計算式</th>
</tr>
</thead>
<tbody>
@@ -4494,8 +4494,8 @@ b_{31} b_{30} b_{29} \ldots b_2 b_1 b_0
</tbody>
</table>
</div>
<p>非正規化数浮動小数点数の精度を大幅に向上させることは注目に値します。最小の正の正規化数は<span class="arithmatex">\(2^{-126}\)</span>、最小の正の非正規化数は<span class="arithmatex">\(2^{-126} \times 2^{-23}\)</span>です。</p>
<p>倍精度<code>double</code><code>float</code>と同様の表現方法を使用しますが、簡潔さのためここでは詳述しません。</p>
<p>なお、非正規化数によって浮動小数点数の精度は大きく向上します。最小の正の正規化数は <span class="arithmatex">\(2^{-126}\)</span> であり、最小の正の非正規化数は <span class="arithmatex">\(2^{-126} \times 2^{-23}\)</span> です。</p>
<p>倍精度 <code>double</code><code>float</code> と同様の表現方法を用しているためここでは詳述しません。</p>
<!-- Source file information -->
@@ -4542,7 +4542,7 @@ aria-label="フッター"
<a
href="../character_encoding/"
class="md-footer__link md-footer__link--next"
aria-label="次: 3.4 &amp;nbsp; 文字の符号化 *"
aria-label="次: 3.4 &amp;nbsp; 文字エンコーディング *"
rel="next"
>
<div class="md-footer__title">
@@ -4550,7 +4550,7 @@ aria-label="フッター"
</span>
<div class="md-ellipsis">
3.4 &nbsp; 文字の符号化 *
3.4 &nbsp; 文字エンコーディング *
</div>
</div>
<div class="md-footer__button md-icon">