web-dev-qa-db-ja.com

Cに符号なしの浮動小数点数がないのはなぜですか?

質問は奇妙に思えます。プログラマーは時々考えすぎます。読んでください...

Cでは、signedおよびunsigned整数を多く使用します。符号なし整数に符号なし整数を割り当てるようなことをするとコンパイラーが警告を出すという事実が気に入っています。符号付き整数と符号なし整数などを比較すると、警告が表示されます。

これらの警告が好きです。彼らは私のコードを正確に保つのに役立ちます。

なぜフロートにも同じ贅沢はないのですか?平方根は絶対に負の数を返すことはありません。負の浮動小数点値に意味がない他の場所もあります。符号なしフロートの完璧な候補。

ところで-私は、浮動小数点数から符号ビットを削除することで得られる精度の単一の余分なビットについてはあまり熱心ではありません。 floatsは今のところとても嬉しいです。 フロートを符号なしとしてマークする時々、整数で得られるのと同じ種類の警告を受け取りたいです。

私は、符号なしの浮動小数点数をサポートするプログラミング言語を知りません。

なぜ存在しないのか考えていますか?


編集:

X87 FPUには符号なしの浮動小数点数を処理する命令がないことを知っています。符号付きフロート命令のみを使用できます。符号付き整数のオーバーフローが未定義であるのと同じように、誤用(たとえば、ゼロ以下になる)は未定義の動作と見なすことができます。

115

C++が符号なしフロートをサポートしていないのは、CPUが実行する同等のマシンコード操作がないためです。したがって、それをサポートすることは非常に非効率的です。

C++がそれをサポートしていた場合、符号なしのフロートを使用することがありますが、パフォーマンスが低下したことを認識していません。 C++でサポートされている場合、すべての浮動小数点演算をチェックして、署名されているかどうかを確認する必要があります。そして、何百万もの浮動小数点演算を行うプログラムの場合、これは受け入れられません。

したがって、問題は、ハードウェア実装者がそれをサポートしない理由です。そして、その答えは、元々定義された符号なしフロート標準がなかったということだと思います。言語には後方互換性が必要なため、追加された言語でも使用できませんでした。浮動小数点の仕様を確認するには、 IEEE規格754浮動小数点 をご覧ください。

負の数を渡そうとすると、floatまたはdoubleをカプセル化し、警告をスローする符号なしのfloatクラスを作成することで、符号なしの浮動小数点型がなくても回避できます。これはあまり効率的ではありませんが、おそらくそれらを激しく使用していなければ、わずかなパフォーマンスの低下は気にしません。

符号なしフロートを持つことの有用性は間違いなくわかります。しかし、C/C++は、安全性よりも誰にとっても最適な効率を選択する傾向があります。

103
Brian R. Bondy

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の補数システムの性質による整数の問題ではありません。

また、標準の数学関数を検討してください:sin、cos、およびtanは入力値の半分に対してのみ機能し、値の対数<1を見つけることができませんでした。二次方程式を解くことができませんでした:x =(-b +/- root( bb-4.ac))/ 2.aなど。実際、これらはどこかで負の値を使用する多項式近似として実装される傾向があるため、おそらく複雑な関数では機能しません。

そのため、符号なしのfloatはほとんど役に立ちません。

しかし、それは、浮動小数点値を範囲チェックするクラスが役に立たないと言うことを意味するものではありません。たとえば、RGB計算など、値を特定の範囲に固定することができます。

13
Skizz

(余談ですが、Perl 6では次のように記述できます。

_subset Nonnegative::Float of Float where { $_ >= 0 };
_

そして、他のタイプと同じように_Nonnegative::Float_を使用できます。

符号なしの浮動小数点演算のハードウェアサポートがないため、Cは提供しません。 Cは、「ポータブルアセンブリ」、つまり、特定のプラットフォームに縛られることなく、できるだけ金属に近いように設計されています。

[編集]

Cはアセンブリのようなものです。表示されるのは、まさに取得するものです。暗黙の「このフロートがあなたにとって負でないことを確認します」は、その設計哲学に反します。本当に必要な場合は、assert(x >= 0)などを追加できますが、明示的に行う必要があります。

8
ephemient

署名されたintが提供できるよりも大きな値のマージンが必要なため、unsigned intが作成されたと思います。

フロートのマージンははるかに大きいため、符号なしフロートの「物理的な」必要性はありませんでした。そして、あなたがあなたの質問で自分自身を指摘しているように、追加の1ビットの精度は何も殺すものではありません。

編集:Brian R. Bondyによる回答 を読んだ後、答えを修正する必要があります。基礎となるCPUには符号なしの浮動小数点演算がありませんでした。ただし、これは上記の理由に基づいた設計上の決定であるという信念を維持します;-)

7
Treb

Trebは正しい軌道に乗っていると思います。整数の場合、対応する符号なし型があることがより重要です。これらはbit-shiftingで使用され、bit-mapsで使用されます。符号ビットが邪魔になります。たとえば、負の値を右にシフトすると、結果の値はC++で定義された実装になります。符号なし整数でそれを行うか、そのようなものをオーバーフローさせることは、そのようなビットが途中にないため、セマンティクスを完全に定義しています。

そのため、少なくとも整数の場合、個別の符号なし型の必要性は、単に警告を与えることよりも強力です。上記のすべての点をフロートで考慮する必要はありません。そのため、ハードウェアのサポートは実際には必要ないと思いますが、Cはその時点では既にサポートしていません。

IEEE浮動小数点の仕様のみが署名されており、ほとんどのプログラミング言語がそれらを使用していることによると思います。

ieee浮動小数点数のウィキペディアアーティクラ

編集:また、他の人が述べたように、ほとんどのハードウェアは非負のフロートをサポートしていないため、ハードウェアがサポートされているため、通常のフロートの方が効率的です。

5
Tobias Wärre

平方根は絶対に負の数を返すことはありません。負の浮動小数点値に意味がない他の場所もあります。符号なしフロートの完璧な候補。

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の実部は正またはゼロであり、sqrt(1.0 * I)は-1.0ではなくsqrt(0.5)+ sqrt(0.5)* Iであるため、脳みそも含まれています。

4
Pete Kirkham

主な理由は、符号なしのfloatが符号なしのintに比べて実際に使用が制限されるためだと思います。ハードウェアがそれをサポートしていないからだという主張は買わない。古いプロセッサには浮動小数点機能がまったくなく、すべてソフトウェアでエミュレートされていました。符号なしのフロートが有用であれば、それらは最初にソフトウェアで実装され、ハードウェアはそれに続きます。

3
Ferruccio

Cの符号なし整数型は、抽象代数リングの規則に従うような方法で定義されます。たとえば、任意の値XおよびYに対して、XYをYに追加するとXが生成されます。符号なし整数型は、他の数値型[または異なるサイズの符号なし型]への変換を伴わないすべての場合、これらの規則に従うことが保証されます、およびその保証は、そのようなタイプの最も重要な機能の1つです。場合によっては、符号なしの型のみが提供できる追加の保証と引き換えに、負の数を表す機能を放棄する価値があります。浮動小数点型は、符号付きであるかどうかにかかわらず、代数リングのすべての規則を順守することはできません[例: X + Y-YがXと等しいことを保証することはできません。実際、IEEEは(特定の値が自分自身と等しくないことを要求することで)等価クラスの規則に従うことさえ許可していません。 「符号なし」浮動小数点型は、通常の浮動小数点型ではできない公理に従うことができるとは思わないため、どのような利点が得られるのかわかりません。

2
supercat

これは、Cコンパイラのターゲットとなる基礎となるプロセッサが、符号なしの浮動小数点数を処理する良い方法を持っていないためだと思います。

1
Brian Ensink

IHMOは、ハードウェアまたはソフトウェアのいずれかで符号付きおよび符号なしの両方の浮動小数点型をサポートするのが面倒だからです。

整数型の場合、 same論理ユニット符号付き整数演算と符号なし整数演算 ほとんどの場合、2の補数のNiceプロパティを使用します。これは、 これらの場合、結果は同じです 加算、サブ、非拡大mul、およびほとんどのビット演算であるためです。署名付きバージョンと署名なしバージョンを区別する操作では、ロジックの大部分を共有できます。例えば

  • 算術シフトと論理シフトでは、上位ビットのフィラーを少し変更するだけで済みます。
  • 拡張乗算では、メインパーツに同じハードウェアを使用してから、調整するためにいくつかの個別のロジックを使用できます 符号を変更する結果 。実際の乗算器で使用されているわけではありませんが、実行することは可能です
  • 最上位ビットを切り替えるか、 INT_MIN を切り替えることにより、符号付き比較を符号なし比較に、またはその逆に簡単に変換できます。また、理論的には、おそらくハードウェアでは使用されませんが、 1種類の比較のみをサポートするシステム (8080または8051など)で有用です。

1の補数を使用するシステムも、ロジックを少し変更するだけで済みます。これは、キャリービットが最下位ビットにラップされるためです。符号マグニチュードシステムについてはわかりませんが、 内部で1の補数を使用 のように見えるため、同じことが当てはまります

残念ながら浮動小数点型についてはそれほど贅沢ではありません。単に符号ビットを解放するだけで、符号なしバージョンになります。しかし、そのビットを何に使うべきでしょうか?

  • 指数に追加して範囲を広げます
  • 仮数に追加して精度を上げます。通常、これは範囲よりも精度が必要なため、より便利です。

ただし、両方の選択肢には、より広い値範囲に対応するために、より大きな加算器が必要です。これにより、ロジックの複雑さが増しますが、加算器の最上位ビットはほとんどの場合未使用のままです。乗算、除算、またはその他の複雑な演算にはさらに多くの回路が必要になります

ソフトウェアの浮動小数点を使用するシステムでは、メモリが非常に高価だったときに予期されていなかった各関数に2つのバージョンが必要です。

しかし、 Cが発明されるずっと前に浮動小数点ハードウェアが存在していました ですから、Cでの選択は、上記の理由によるハードウェアサポートの欠如によるものだと思います

とはいえ、いくつかのspecialized符号なし浮動小数点形式があり、主に Khronosグループの10ビットと11ビットの浮動小数点型

0
phuclv