32ビットシステムでは2 ^ 33の数値を管理できないため(明らかな32ビットの制限のため)、80ビットの浮動小数点数を管理するにはどうすればよいですか?
「80ビット」が必要です...
32ビットシステムでは2 ^ 33の数値を管理できないため(明らかな32ビットの制限のため)、80ビットの浮動小数点数を管理するにはどうすればよいですか?
「80ビット」が必要です...
回答:
32ビットCPUの意味の1つは、レジスタが32ビット幅であることです。これは、たとえば64ビットの数値を処理できないことを意味するのではなく、下位32ビットの半分を最初に処理し、次に上位32ビットの半分を処理する必要があるだけです。(これがCPUにキャリーフラグがある理由です。)CPUがより広い64ビットレジスタに値をロードできる場合よりも遅くなりますが、それでも可能です。
したがって、システムの「ビットネス」は、プログラムが処理できる数値のサイズを必ずしも制限しません。これは、CPUレジスタに収まらない操作を複数の操作にいつでも分割できるためです。そのため、操作が遅くなり、より多くのメモリを消費し(「スクラッチパッド」としてメモリを使用する必要がある場合)、プログラミングがより困難になりますが、操作は可能です。
ただし、CPUの浮動小数点部分には独自のレジスタがあり、それらは80ビット幅なので、たとえばIntel 32ビットプロセッサや浮動小数点では問題になりません。(x86の歴史の初期では、浮動小数点機能は別個のチップであり、80486DX以降のCPUに統合されていました。)
@Breakthroughの答えは私にこれを追加するように促しました。
浮動小数点値は、FPUレジスタに格納されている限り、バイナリ整数値とは大きく異なります。
浮動小数点値の80ビットは、仮数と指数の間で分割されます(常に2である浮動小数点数の「ベース」もあります)。仮数には有効数字が含まれ、指数はそれらの有効数字の大きさを決定します。したがって、別のレジスタへの「オーバーフロー」はありません。仮数に収まらないほど数値が大きくなり、指数が増加して精度が失われます。つまり、整数に変換すると、小数点以下の桁が失われます。これが浮動小数点と呼ばれる理由です。
指数が大きすぎる場合、浮動小数点オーバーフローが発生しますが、指数と仮数が結び付けられているため、簡単に別のレジスタに拡張することはできません。
私はそのいくつかについて不正確で間違っているかもしれませんが、それがその要点だと思います。(このウィキペディアの記事は、上記をもう少し簡潔に示しています。)
CPUの「浮動小数点」部分全体が独自の世界にあるため、これがまったく異なる動作をすることは問題ありません-特別なCPU命令を使用してそれにアクセスします。また、質問のポイントに向かって、それは分離されているため、FPUのビット数はネイティブCPUのビット数と密接に結びついていません。
-fomit-frame-pointer
と、その登録を取り戻すことができます。
32ビット、64ビット、および128ビットはすべて、プロセッサのワード長を指し、これは「基本的なデータ型」と考えることができます。多くの場合、これはシステムのRAMとの間で転送されるビット数、およびポインターの幅です(ただし、1つのポインターがアクセスできる以上のRAMにソフトウェアを使用することを妨げるものはありません)。
一定のクロック速度(およびアーキテクチャ内の他のすべてが一定)を想定し、メモリの読み取り/書き込みが同じ速度であると想定します(ここでは1クロックサイクルを想定していますが、これは現実の場合とは異なります)。 64ビットマシンの1クロックサイクルで2つの64ビット数を追加します(RAMから数をフェッチする場合は3つ):
ADDA [NUM1], [NUM2]
STAA [RESULT]
32ビットマシンでも同じ計算を行うことができます...しかし、32ビットマシンでは、下位32ビットを最初に追加し、オーバーフローを補正してから追加する必要があるため、ソフトウェアでこれを行う必要があります上位64ビット:
ADDA [NUM1_LOWER], [NUM2_LOWER]
STAA [RESULT_LOWER]
CLRA ; I'm assuming the condition flags are not modified by this.
BRNO CMPS ; Branch to CMPS if there was no overflow.
ADDA #1 ; If there was overflow, compensate the value of A.
CMPS ADDA [NUM1_UPPER], [NUM2_UPPER]
STAA [RESULT_UPPER]
作成したアセンブリ構文を確認すると、高精度の演算が、語長の短いマシンで指数関数的に長い時間を要することが簡単にわかります。これは、64ビットプロセッサと128ビットプロセッサの本当の鍵です。1回の操作でより多くのビットを処理できます。一部のマシンには、キャリーを使用して他の数量を追加するための命令が含まれています(ADC
x86など)が、上記の例では任意の精度値が考慮されています。
これを質問に拡張するために、使用可能なレジスタよりも大きな数を追加する方法を簡単に確認できます。問題をレジスタのサイズのチャンクに分割し、そこから作業するだけです。@MatteoItaliaで述べたように、x87 FPUスタックは80ビット量をネイティブにサポートしていますが、このサポートを欠いているシステム(または浮動小数点ユニットを完全に欠いているプロセッサー!)では、同等の計算/操作をソフトウェアで実行する必要があります。
したがって、80ビットの数値の場合、各32ビットセグメントを追加した後、81番目のビットへのオーバーフローもチェックし、オプションで上位ビットをゼロにします。これらのチェック/ゼロは、ソースとデスティネーションのオペランドサイズが指定されている特定のx86およびx86-64命令に対して自動的に実行されます(ただし、これらは1バイト幅から始まる2の累乗でのみ指定されます)。
もちろん、浮動小数点数では、仮数と有効数字がオフセット形式で一緒にパックされるため、単純にバイナリ加算を実行することはできません。x86プロセッサのALUには、IEEE 32ビットおよび64ビットの浮動小数点に対してこれを実行するハードウェア回路があります。ただし、浮動小数点ユニット(FPU)がない場合でも、ソフトウェアで同じ計算を実行できます(たとえば、GNU Scientific Libraryを使用することにより、アーキテクチャでコンパイルされたときにFPUを使用し、ソフトウェアアルゴリズムにフォールバックします)浮動小数点ハードウェアが使用できない場合(たとえば、FPUを備えていない組み込みマイクロコントローラーの場合)。
十分なメモリがあれば、任意の(または「無限」-現実的な範囲内)精度の数値で計算を実行できます。精度が必要になるほど、より多くのメモリを使用します。これの1つの実装は、GNU Multiple Precisionライブラリにあり、整数、有理数、および浮動小数点演算で無制限の精度(もちろん、RAMがいっぱいになるまで)を許可します。
システムのメモリアーキテクチャでは、一度に32ビットしか移動できない場合がありますが、それ以上の数を使用することを妨げません。
乗算を考えてください。最大10x10の乗算テーブルを知っているかもしれませんが、おそらく紙の上で123x321を実行するのに問題はありません:それを多くの小さな問題に分割し、個々の数字を乗算し、キャリーなどを処理します。
プロセッサでも同じことができます。「昔」には、浮動小数点演算を実行できる8ビットプロセッサがありました。しかし、彼らはすごかった。
「32ビット」は、実際にはプロセッサを分類する方法であり、固定されたルールではありません。「32ビット」プロセッサには通常、32ビットの汎用レジスタがあります。
ただし、プロセッサ内のすべてを32ビットで実行する必要はありません。たとえば、「32ビット」コンピューターで28ビットのアドレスバスを使用することは、ハードウェアを作成する方が安価だったため、前代未聞ではありませんでした。多くの場合、64ビットコンピューターには、同じ理由で40ビットまたは48ビットのメモリバスしかありません。
浮動小数点演算は、サイズが異なる別の場所です。多くの32ビットプロセッサが64ビット浮動小数点数をサポートしていました。彼らは、汎用レジスターよりも広い特殊レジスターに浮動小数点値を格納することでそうしました。これらの大きな浮動小数点数のいずれかを特殊レジスターに格納するには、まず数値を2つの汎用レジスターに分割し、次にそれらを結合して特殊レジスターの浮動小数点数にする命令を発行します。これらの浮動小数点レジスターでは、値は一対の32ビットの半分としてではなく、64ビットの浮動小数点として操作されます。
あなたが言及する80ビットの算術はこの特別な場合です。浮動小数点数を使用したことがある場合は、浮動小数点の丸めの問題から生じる不正確さに精通しています。四捨五入の解決策の1つは、ビットの精度を上げることですが、その場合、より大きな数値を格納し、開発者にメモリ内で異常に大きな浮動小数点値を使用するように強制する必要があります。
Intelのソリューションでは、浮動小数点レジスタはすべて80ビットですが、これらのレジスタとの間で値を移動する命令は、主に64ビットの数値で機能します。Intelのx87浮動小数点スタック内で完全に操作する限り、すべての操作は80ビットの精度で行われます。コードがこれらの値の1つを浮動小数点レジスターから取り出してどこかに保存する必要がある場合、64ビットに切り捨てます。
物語の教訓:「32ビット」のような分類は、物事を深く掘り下げると、常に混乱します!
「32ビット」CPUとは、ほとんどのデータレジスタが32ビットレジスタであり、ほとんどの命令がこれらの32ビットレジスタのデータを操作するCPUです。また、32ビットCPUは、一度に32ビットのメモリとの間でデータを転送する可能性があります。ほとんどのレジスタが32ビットであることは、すべてのレジスタが32ビットであることを意味しません。簡単な答えは、32ビットCPUには、80ビット浮動小数点レジスターや対応する命令など、他のビットカウントを使用する機能があることです。
@sprasoneが@ultrasawbladeの答えのコメントで述べたように、浮動小数点演算を統合した最初のx86 CPUはIntel i486(具体的には80486SXではなく80486DX)であり、i486 Microprocessor Programmersの15-1リファレンスマニュアルには、数値レジスタに「8つの個別にアドレス指定可能な80ビット数値レジスタ」が含まれています。i486には32ビットのメモリバスがあるため、80ビットの値を転送するには3つのメモリ操作が必要です。
486世代の前身であるi386には、浮動小数点演算が統合されていませんでした。代わりに、外部浮動小数点「コプロセッサ」80387の使用をサポートしていました。このコプロセッサは、80387プログラマーズリファレンスマニュアルのページ2-1からわかるように、i486に統合された機能とほぼ同じでした。
80ビットの浮動小数点形式は、8086および8088の数学コプロセッサである8087を起源とするようです。8086および8088は16ビットCPU(16ビットおよび8ビットのメモリバス)であり、コプロセッサの80ビットレジスタを活用して、80ビット浮動小数点形式を使用する。