web-dev-qa-db-ja.com

32ビットシステムで80ビット浮動小数点を使用するにはどうすればよいですか?

32ビットシステムは2 ^ 33の数値を管理できないため(明らかな32ビットの制限のため)、 80ビット浮動小数点 数値をどのように管理できますか?

「80ビット」が必要です...

13
markzzz

32ビットCPUの意味の1つは、そのレジスタが32ビット幅であることです。これは、たとえば64ビットの数値を処理できないことを意味するのではなく、最初に下位32ビットの半分を処理し、次に上位の32ビットの半分を処理する必要があるということです。 (CPUに キャリーフラグ があるのはそのためです。)CPUがより広い64ビットレジスタに値をロードできる場合よりも低速ですが、それでも可能です。

したがって、CPUレジスタに収まらない操作は常に複数の操作に分割できるため、システムの「ビット数」は、プログラムが処理できる数値のサイズを必ずしも制限しません。そのため、操作が遅くなり、より多くのメモリを消費し(メモリを「スクラッチパッド」として使用する必要がある場合)、プログラミングがより困難になりますが、操作は引き続き可能です。

ただし、CPUの浮動小数点部分には独自のレジスタがあり、それらは80ビット幅であるため、たとえばIntel32ビットプロセッサと浮動小数点では問題になりません。 (x86の歴史の初期には、浮動小数点機能は別のチップであり、80486DX以降のCPUに統合されていました。)


@Breakthroughの答えは、私にこれを追加するように促しました。

浮動小数点値は、FPUレジスタに格納されている限り、2進整数値とは大きく異なります。

浮動小数点値の80ビットは、仮数と指数に分割されます(浮動小数点数には、常に2である「基数」もあります)。仮数には有効数字が含まれ、指数はそれらの有効数字の大きさを決定します。したがって、別のレジスタへの「オーバーフロー」はありません。数値が大きくなりすぎて仮数に収まらない場合、指数が増加し、精度が失われます。つまり、整数に変換すると、右から小数点以下の桁数が失われます。これが、浮動小数点と呼ばれる理由です。

指数が大きすぎると、浮動小数点オーバーフローが発生しますが、指数と仮数が結合されているため、別のレジスタに簡単に拡張することはできません。

私はそのいくつかについて不正確で間違っている可能性がありますが、それがその要点だと思います。 (この ウィキペディアの記事 は、上記をもう少し簡潔に説明しています。)

CPUの「浮動小数点」部分全体が一種の独自の世界にあるため、これがまったく異なる動作をすることは問題ありません。特別なCPU命令を使用してアクセスするなどです。また、質問のポイントに向かって、それが分離しているため、FPUのビット数はネイティブCPUのビット数と緊密に結合されていません。

35
LawrenceC

32ビット、64ビット、および128ビットはすべて、プロセッサの Word length を参照します。これは、「基本的なデータ型」と考えることができます。多くの場合、これはシステムのRAMとの間で転送されるビット数、およびポインタの幅です(ただし、ソフトウェアを使用してより多くのRAM次に、単一のポインタがアクセスできるもの)。

一定のクロック速度(およびアーキテクチャの他のすべてが一定)を想定し、メモリの読み取り/書き込みが同じ速度(ここでは1クロックサイクルであると想定していますが、実際の状況とはかけ離れています)であると想定すると、 64ビットマシンの1つのクロックサイクルで2つの64ビット数値を追加します(RAMから数値をフェッチする場合は3つ):

ADDA [NUM1], [NUM2]
STAA [RESULT]

2ビットマシンでも同じ計算 ...ただし、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]

作成したAssembly構文を確認すると、Wordの長さが短いマシンで、高精度の操作に指数関数的に長い時間がかかることが簡単にわかります。これは、64ビットおよび128ビットプロセッサの真の鍵です。これらを使用すると、1回の操作でより多くのビットを処理できます。一部のマシンには、キャリーを使用して他の数量を追加するための命令が含まれています(たとえば、x86のADC)が、上記の例では任意の精度値を念頭に置いています。


これを問題に拡張するために、使用可能なレジスターよりも大きい数値を追加する方法を確認するのは簡単です。問題をレジスターのサイズのチャンクに分割し、そこから作業します。 @ MatteoItalia で述べたように、x87 FPUスタックは80ビットの数量をネイティブでサポートしていますが、このサポートがないシステム(または浮動小数点ユニットがまったくないプロセッサー)では、同等の計算/演算を行う必要があります。実行ソフトウェア内

したがって、80ビットの数値の場合、各32ビットセグメントを追加した後、81番目のビットへのオーバーフローもチェックし、オプションで上位ビットをゼロにします。これらのチェック/ゼロは、ソースと宛先のオペランドサイズが指定されている特定のx86およびx86-64命令に対して自動的に実行されます(ただし、これらは1バイト幅から始まる2の累乗でのみ指定されます)。

もちろん、浮動小数点数では、仮数と有効数字がオフセット形式でパックされるため、単純に2進加算を実行することはできません。 x86プロセッサのALUには、IEEE32ビットおよび64ビットフロートに対してこれを実行するためのハードウェア回路があります。 ただし、浮動小数点ユニット(FPU)がない場合でも、同じ計算をソフトウェアで実行できます(例:- GNU Scientific Library 、浮動小数点ハードウェアが利用できない場合はソフトウェアアルゴリズムにフォールバックし、アーキテクチャでコンパイルするときにFPUを使用します[たとえば、FPUがない組み込みマイクロウェアの場合])。

十分なメモリがあれば、より多くのメモリが必要になるため、より多くのメモリを使用して、任意(または「無限」-現実的な範囲内)の精度で計算を実行することもできます。これの1つの実装は GNU Multiple Precisionライブラリ に存在し、整数、有理数、および浮動小数点演算で無制限の精度を可能にします(もちろん、RAMがいっぱいになるまで) 。

13
Breakthrough

システムのメモリアーキテクチャでは、一度に32ビットしか移動できない場合があります。

乗算について考えてください。あなたは10x10までの九九を知っているかもしれませんが、おそらく一枚の紙で123x321を実行するのに問題はありません。それを多くの小さな問題に分割し、個々の桁を乗算し、キャリーなどを処理します。

プロセッサは同じことを行うことができます。 「昔」には、浮動小数点演算を実行できる8ビットプロセッサがありました。しかし、彼らはとてもすごいです。

5
Floris

「32ビット」は、実際にはプロセッサを分類する方法であり、決まった判断ではありません。 「32ビット」プロセッサには、通常、使用する32ビットの汎用レジスタがあります。

ただし、プロセッサのすべてを32ビットで実行するという基本的な要件はありません。たとえば、「32ビット」コンピュータに28ビットアドレスバスがあることは、ハードウェアの製造コストが安いため、前代未聞ではありませんでした。同じ理由で、64ビットコンピュータには40ビットまたは48ビットのメモリバスしかないことがよくあります。

浮動小数点演算は、サイズが異なる別の場所です。多くの32ビットプロセッサは64ビット浮動小数点数をサポートしていました。これは、浮動小数点値を汎用レジスタよりも幅の広い特殊レジスタに格納することによって行われました。これらの大きな浮動小数点数の1つを特殊レジスターに格納するには、最初に数値を2つの汎用レジスターに分割し、次にそれらを特殊レジスターの浮動小数点数に結合する命令を発行します。これらの浮動小数点レジスタに入ると、値は32ビットの半分のペアとしてではなく、64ビットの浮動小数点として操作されます。

あなたが言及する80ビットの算術はこれの特別な場合です。浮動小数点数を扱ったことがある場合は、浮動小数点の四捨五入の問題から生じる不正確さに精通しています。丸めの1つの解決策は、より多くのビットの精度を持たせることですが、その場合は、より大きな数値を格納し、開発者にメモリ内で異常に大きな浮動小数点値を使用するように強制する必要があります。

Intelのソリューションでは、浮動小数点レジスタはすべて80ビットですが、これらのレジスタとの間で値を移動する命令は、主に64ビットの数値で機能します。完全にIntelのx87浮動小数点スタック内で操作する限り、すべての操作は80ビットの精度で実行されます。コードでこれらの値の1つを浮動小数点レジスターから引き出してどこかに格納する必要がある場合は、64ビットに切り捨てます。

話の教訓:「32ビット」のような分類は、物事を深く理解すると常に曖昧になります。

3
Cort Ammon

「32ビット」CPUは、ほとんどのデータレジスタが32ビットレジスタであり、ほとんどの命令がそれらの32ビットレジスタのデータを操作するCPUです。 32ビットCPUは、一度に32ビットのメモリとの間でデータを転送する可能性もあります。ほとんどのレジスタが32ビットであることは、すべてのレジスタが32ビットであることを意味しません。簡単に言うと、32ビットCPUには、80ビット浮動小数点レジスタや対応する命令など、他のビットカウントを使用するいくつかの機能があります。

@spudoneが@ultrasawbladeの回答に対するコメントで述べたように、フローティングポイント操作を統合した最初のx86CPUはInteli486(具体的には80486DXであり、80486SXではない)でした。 i486マイクロプロセッサプログラマリファレンスマニュアルのページ15-1 には、数値レジスタに「個別にアドレス可能な8つの80ビット数値レジスタ」が含まれています。 i486には32ビットのメモリバスがあるため、80ビットの値を転送するには3回のメモリ操作が必要です。

486世代の前身であるi386には、統合された浮動小数点演算がありませんでした。代わりに、外部浮動小数点「コプロセッサー」である80387の使用をサポートしていました。このコプロセッサーは、 ページ2-1からわかるように、i486に統合されたものとほぼ同じ機能を備えていました。 80387プログラマーズリファレンスマニュアル の。

80ビット浮動小数点形式は、8086および8088の数値演算コプロセッサである8087に由来しているようです。8086および8088は16ビットCPU(16ビットおよび8ビットのメモリバス)であり、依然としてコプロセッサの80ビットレジスタを利用して、80ビット浮動小数点形式を使用します。

2
ShadSterling