なぜ C には符号なし浮動小数点がないのでしょうか?
-
21-08-2019 - |
質問
わかりますが、その質問は奇妙に思えます。プログラマーは時々考えすぎることがあります。続きをお読みください...
Cでは私は使用します signed
そして unsigned
整数が多い。符号なし変数に符号付き整数を代入するなどの操作を行うとコンパイラが警告を発してくれるという事実が気に入っています。符号付き整数と符号なし整数などを比較すると、警告が表示されます。
私はこれらの警告が好きです。コードを正しく保つのに役立ちます。
フロートでも同じ贅沢をしてみませんか?平方根は絶対に負の数を返しません。負の float 値が意味を持たない場所は他にもあります。符号なし浮動小数点数の完璧な候補です。
ところで、私は浮動小数点数から符号ビットを削除することで得られる 1 ビットの余分な精度についてはあまり興味がありません。超満足です float
今のままです。ただそうしたいのです float を符号なしとしてマークする 場合によっては、整数の場合と同じ種類の警告が表示されます。
符号なし浮動小数点数をサポートするプログラミング言語を知りません。
なぜそれらが存在しないのかわかりますか?
編集:
x87 FPU には符号なし浮動小数点数を処理する命令がないことはわかっています。符号付き浮動小数点命令を使用してみましょう。誤用(例:ゼロ未満になる) は、符号付き整数のオーバーフローが未定義であるのと同様に、未定義の動作と見なされる可能性があります。
解決
C ++が持っていないのはなぜCPUが実行するための同等のマシンコード操作がないため、符号なし山車のサポートがあります。だから、それをサポートするのは非常に非効率的だろう。
C ++はそれをサポートしなかった場合は、、あなたは時々、符号なしfloatを使用して、あなたのパフォーマンスがちょうど殺されたことを実現していないことになります。 C ++は、それをサポートする場合は、すべての浮動小数点演算は、それが署名したかどうかを確認するためにチェックする必要があります。そして、浮動小数点演算数百万を行うプログラムに対して、これは受け入れられません。
ハードウェア実装がそれをサポートしていない理由は、そこで質問は次のようになります。そして、私はその答えは、もともと定義された符号なしフロート標準がなかったということだと思います。言語ので、それは言語がそれを利用することができませんでした追加された場合でも、以前のバージョンとの互換性が好きです。浮動小数点の仕様を参照するには、 IEEE標準754浮動小数点を見なければなりませんます。
あなたの周りのfloatまたはdoubleをカプセル化し、負の数を渡すしようとした場合、警告をスロー符号なしフロートクラスを作成することによって、しかし、符号なし浮動小数点型を持っていない得ることができます。これはあまり効率的ですが、あなたがそれらを使用していない場合は、おそらく強烈にあなたがそのわずかなパフォーマンスの低下を気にしません。
私は間違いなく、符号なしフロートを持っていることの有用性を参照してください。しかし、C / C ++は、安全性に対する皆のための最高の作品の効率を選びましたする傾向があります。
他のヒント
C / C ++での符号付きと符号なし整数の間に有意な差があります:
value >> shift
符号付きの値は、符号なしの値は先頭ビットをクリアし、(符号が延びる)先頭ビット不変のままにします。
何の符号なしフロートがない理由は、負の値が存在しない場合は、迅速に問題のすべての種類に実行することです。このことを考えてみます:
float a = 2.0f, b = 10.0f, c;
c = a - b;
どのような価値を持っているcのでしょうか? -8。しかし、それは負の数のないシステムでは何を意味するだろう。 FLOAT_MAX - おそらく8?実は、そのFLOAT_MAXとして動作しない - 物事がもっと変にしているので、8が原因精度の影響にFLOAT_MAXです。それは何だった場合は、より複雑な式の一部ます:
float a = 2.0f, b = 10.0f, c = 20.0f, d = 3.14159f, e;
e = (a - b) / d + c;
これは、2の補数システムの性質のために整数の問題ではありません。
標準的な数学関数を考えるまた:罪、COSや日焼けが半分だけ自分の入力値のために働くだろう、あなたは値<1のログを見つけることができなかった、あなたは二次方程式を解くことができませんでした:X =(-b + / - ルート(BB - 4.ac))/ 2.Aなど。これらはどこかに負の値を使用する多項式近似として実装される傾向にあるよう実際には、それはおそらく、任意の複雑な機能のために動作しません。
ですから、符号なしの浮動小数点数はかなり役に立たないです。
しかし、それはチェックが値をフロート範囲クラスが有用ではないと言うことを意味するものではありません、あなたはたとえばRGBの計算のために、与えられた範囲に値をクランプする場合があります。
(余談ですが、Perl 6のは、することができますとして、あなたが書いた
subset Nonnegative::Float of Float where { $_ >= 0 };
、その後、あなたはちょうどあなたが他のタイプのと同じようNonnegative::Float
を使用することができます。)
があり、符号なし浮動小数点演算のためのハードウェアサポートはませんので、Cはそれを提供していません。 Cは主にあなたが特定のプラットフォームに縛られることなくできるように、そのは、金属に近いです、「ポータブルアセンブリ」となるように設計されています。
[編集]
Cは、アセンブリのようなものです:あなたが得る正確に何であるあなたが何を参照してください。暗黙の「私はこのフロートがあなたのための非負であることを確認します」そのデザイン哲学に反します。あなたが本当にそれをしたい場合は、assert(x >= 0)
または類似を追加することができますが、明示的にそれを行う必要があります。
私はunsigned int型が原因で提供することができます署名int型よりも大きな値のマージンを必要とするために作られたと信じています。
フロートは、はるかに大きなマージンを持っているので、符号なしのフロートのための「物理的」必要はなかったです。あなたの質問で自分を指摘するように、追加の1ビット精度は、のために殺すことは何もありません。
の編集を ブライアンR.ボンディするで答えを読んだ後、私が持っています私の答えを変更します: 彼は、基礎となるCPUは、符号なしフロート操作を持っていなかったということは間違いなく正しいです。しかし、私はこれは私が上記の理由に基づいて設計上の決定だったというのが私の信念を維持; - )
私はTREBは正しい軌道に乗っていると思います。それはあなたが符号なしの対応する型を持っている整数の方が重要です。これらは、のビットシフトの中で使用し、のビットマップで使用されているもののです。符号ビットは、ちょうど道に入りました。例えば、負の値を右シフトし、結果の値は、C ++で定義された実装です。方法には、このようなビットがないので、その符号なし整数または、そのようなものを溢れ行うと完全にセマンティクスを定義しています。
少なくとも整数に対して、別々の符号なしタイプの必要性だけで警告を与えるよりも強いので。上記のすべての点は、フロートのために考慮される必要はありません。そう、私は考えて、それらのためのハードウェアサポートのための本当の必要がない、そしてCは、すでにその時点でそれらをサポートしていないだろう。
私はそれがIEEE浮動小数点の仕様のみが署名されていることに依存推測すると、ほとんどのプログラミング言語は、それらを使用すること。
編集:他の人が述べたようにまた、ほとんどのハードウェアは非負のフロートをサポートしていませんので、山車の通常の種類は、ハードウェアサポートがあるので、やる方が効率的です。
。平方根は間違いなく負の数を返すことはありません。負のfloat値が意味を持たないだけでなく、他の場所があります。符号なしフロートのための完璧な候補ます。
C99は複素数、およびSQRTの種類一般的な形式をサポートしていますので、sqrt( 1.0 * I)
はマイナスになります。
コメント主がその中で私は、マクロ型汎用sqrt
ではなく機能に言及し、それは、その実数成分に複合体のトランケーションによりスカラー浮動小数点値が返され、上記わずかな光沢を強調
#include <complex.h>
#include <tgmath.h>
int main ()
{
complex double a = 1.0 + 1.0 * I;
double f = sqrt(a);
return 0;
}
任意の複素数の平方根の実部が正であるか、またはゼロとしてまた、脳おならを含み、SQRT(1.0 * I)はIしない-1.0 * SQRT(0.5)+ SQRT(0.5)です。
私は、主な理由は、符号なしの山車が符号なし整数型に比べて、本当に限られた用途を持っているということだと思います。私は、ハードウェアがそれをサポートしていないからだと引数を購入しないでください。古いプロセッサは、それがすべてのソフトウェアでエミュレートされた、まったく浮動小数点性能を持っていました。符号なしの山車が有用であったならば、彼らは最初のソフトウェアで実装されていたであろうと、ハードウェアが追随しているだろう。
Cの符号なし整数型は、抽象代数リングのルールに従うように定義されています。例えば、任意の値XとYのために、YにXYを追加する符号なし整数型は、任意の他の数値型にまたはから変換を伴わないすべての場合において、これらの規則に従うことが保証されているXをもたらす[又は異なるサイズの符号なしのタイプ] 、及びその保証は、このようなタイプの最も重要な機能の一つです。いくつかのケースでは、それだけでunsigned型が提供できる余分な保証と引き換えに負の数を表現する能力を放棄する価値があります。浮動小数点型、署名されたか否か、代数環のすべての規則に従うことができない[例えばそれらは、X + Y-YがXに等しくなることを保証することができず、実際にはIEEEもそれら】特定の値は、それ自体に等しくない比較することを要求することにより、[同値クラスのルールを遵守することはできません。私は「符号なし」浮動小数点型は、通常の浮動小数点型は、ので、私はそれが提供しています何の利点はよく分からないことができませんでした任意の公理を遵守できないと思います。
私はCコンパイラの対象となる基礎となるプロセッサは、符号なしの浮動小数点数を扱うの良い方法を持っていないので、それはあると思います。
IHMO ハードウェアまたはソフトウェアのいずれかで符号付き浮動小数点型と符号なし浮動小数点型の両方をサポートするのは面倒すぎるためです
整数型の場合は利用できます の 同じ ロジックユニット 符号付き整数演算と符号なし整数演算の両方 ほとんどの状況では 2 の補数の nice プロパティを使用します。 それらの場合でも結果は同じです 加算、減算、非拡大乗算、およびほとんどのビット単位の演算に使用できます。署名付きバージョンと署名なしバージョンを区別する操作については、引き続き次のことが可能です。 ロジックの大部分を共有する. 。例えば
- 算術シフトと論理シフトでは、上位ビットのフィラーをわずかに変更するだけで済みます。
- 拡大乗算では、メイン部分に同じハードウェアを使用し、その後調整するために別のロジックを使用できます。 符号性を変更する結果. 。実際の乗算器で使用されるわけではありませんが、行うことは可能です
- 符号付き比較を符号なし比較に、またはその逆に変換するには、最上位ビットまたは 追加する
INT_MIN
. 。また、理論的には可能ですが、おそらくハードウェアでは使用されませんが、ハードウェアでは役立ちます。 1 種類の比較のみをサポートするシステム (8080 や 8051 など)
1 の補数を使用するシステムでも、キャリー ビットを最下位ビットにラップするだけなので、ロジックを少し変更するだけで済みます。符号絶対値システムについてはよくわかりませんが、どうやらそうであるようです。 内部で 1 の補数を使用する 同じことが当てはまります
残念ながら 浮動小数点型にはそんな贅沢はできません。 単に符号ビットを解放するだけで、符号なしバージョンが得られます。しかし、それではそのビットを何に使用すればよいのでしょうか?
- 指数に加算して範囲を拡大します
- 仮数に追加することで精度が向上します。一般に範囲よりも精度が必要なため、これは多くの場合より便利です。
ただし、どちらの選択にも必要なのは、 より大きな加算器 より広い値範囲に対応できるようになります。これによりロジックが複雑になり、加算器の最上位ビットはほとんどの場合未使用のままになります。乗算、除算、またはその他の複雑な演算を行うには、さらに多くの回路が必要になります。
ソフトウェア浮動小数点を使用するシステムでは、関数ごとに 2 つのバージョンが必要になります。これは、メモリが非常に高価だった時代には予想外でした。さもなければ、署名付き関数と署名なし関数の一部を共有する「トリッキーな」方法を見つける必要があります。
しかし 浮動小数点ハードウェアは C が発明されるずっと前から存在していました, したがって、C を選択したのは、上で述べた理由によりハードウェア サポートが不足していたためだと思います。
とは言え、いくつか存在します 専門化された 符号なし浮動小数点形式。主に画像処理目的で使用されます。 Khronos グループの 10 および 11 ビット浮動小数点型