10進演算でVisiCalcの速度が低下したのはなぜですか?
何が起こったのか、そしてその理由についてのすべての詳細を説明するVisiCalcに関する優れた記事があります。コンピューティングの歴史のその部分に興味がある場合は、強くお勧めします。私はこのセクションを読んでいました:
本質的に、VisiCalcは数字に関するものです。私たちが行った初期の決定の1つは、10進算術を使用して、会計士が10進計算機を使用して表示するエラーと同じになるようにすることでした。振り返ってみると、これは悪い決定でした。なぜなら、人々は気にしないことが判明し、バイナリの場合よりも計算がはるかに遅くなったからです。
そして、うなずいて、はい、VisiCalcの後継者はこの点で後退しました。今日まで、インターネットは、Excelが0.1のような数値や、人々が期待するように丸められていない2進浮動小数点の異常を示す理由についての質問と回答でいっぱいです。VisiCalcは、その時点で実際に広告キャンペーンを開始すべきでした...
... ちょっと待って。冷蔵庫のロジック。
計算がはるかに遅くなりましたか?
VisiCalcは、BCD演算をサポートする6502で作成されました。10進モードをオンにするだけで、CPUはバイナリバイトを追加するのとまったく同じ速度でBCDバイトを追加します。
ただし、スプレッドシートのほとんどの数値は、10進数で表すと単純です。1234.56のような数値は、BCDでは3バイトを使用しますが、倍精度2進浮動小数点では8バイトを使用します。これはメモリを節約するだけでなく、計算ルーチン(ソフトウェアで実行する必要があります-マシンにはFPUがありません)が早期終了の機会を利用する場合、時間も節約します。したがって、スプレッドシートで通常発生する数値の計算は、10進数でより高速になるはずです。
また、小さなスプレッドシートは、表示の更新に多くの時間を費やしています。内部表現が10進数の場合、数値を内部表現からASCIIに変換して表示する方が、かなり高速です。
では、なぜ彼は小数が計算を遅くしたと言ったのですか?
回答
1234.56のような数値は、BCDでは3バイトを使用しますが、倍精度2進浮動小数点では8バイトを使用します。
一般的に言って、そうではありません。合計6桁、小数点の前に4桁、後の2桁の正の数のみのデータベースフィールド定義がある場合、はい、1234.56を3つの8ビットBCDバイトで表すことができます。しかし、より一般的な場合のように、次の場合:
- 任意の数にさらに多くの桁を含めることができます。たとえば、1セント硬貨に最大$ 1,000,000を指定できるようにするためだけに、8桁が最小です。より一般的なのは10または12以上です。
- さまざまなフィールドで小数点以下の桁数を変えることができます。たとえば、米国(および他の多くの)通貨値の場合は2ですが、単価の場合は6以上です(たとえば、光熱費のkWhのコスト)。
- 負の数を許可します。
次に、非常にすばやく3バイトを超えます。8バイトが妥当な最小値になります。
ストレージ(計算を無視)の場合でも、6桁の数値に対して3バイトは機能しません。これは、このセルに最後の2桁の前に小数点が付いた3バイトの正の数値があることをどこかで定義する必要があるためです。これには1バイトかかるので、現在は4バイトです。
さらに、追加の操作(さまざまな長さの数値形式のコード化/デコード)に必要なコードは、一般的な8ビットシステムで利用可能な非常に限られた64kコード+データに食い込みます。スプレッドシート内の数値セルのサイズを変更することによって(できれば平均してはるかに小さい)値のために節約されるスペースは、通常、それらの数値の表示、操作、および計算をサポートするためにメモリに必要な追加のコードよりも重要である可能性があります。 。
6502はSIMPLEBCD演算をサポートしていました。結局、VisiCalcの人たちはその機能さえ使用せず、すべてを最初から書いたに違いありません。足し算と引き算だけでなく、掛け算と割り算もあります。さらに、VisiCalcは浮動小数点(10進浮動小数点)でした。
10進数の計算が遅い理由は、「誰も」今日10進数の計算を使用していないのと同じ理由で、2進数の計算を使用しています。2進演算では、各ビットは数字です。10進数の計算では、4ビットは1桁です。精度を下げるためにメモリを増やすと、計算が遅くなり、コンピュータの作業が大幅に増えます。6502でさえ、初期のサポートがあります。
(そして、はい、小数の数学はさまざまな場所の至る所で使用されていますが、それは例外であり、規則ではありません。)
6502でも、10進演算が遅いためです。8ビットBCDの加算と減算はプロセッサでサポートされていますが、それだけです。
10進数の乗算、除算、シフト、浮動小数点の正規化、さらには比較のコードは、2進数よりもいくらか大きく、遅くなります。
たとえば、シフトと減算の除算ルーチンでは、値を半分にするためのサブルーチンが必要です。バイナリでは、これは簡単です。例として8ビット値を使用します。
LSR
10進モードでは、次のようになります(「10進モードでの乗算と除算」の礼儀):
ROR
N08 PHP
BPL HALF2
SEC
SBC #$30
HALF2 BIT N08
BEQ HALF3
SEC
SBC #3
HALF3 PLP
このようなコードは、10進除算ルーチンの内部ループにあります。速度のペナルティは重要です。