セクション3.4のIEEE Std 754-2008(C規格ではIEC 60559と同じものを使用しています)に記載されているように、コードで想定しているフォーマットは「バイナリ交換浮動小数点フォーマット」であり、 )。それはイェンスGustedtが彼のコメントで説明したように、使用する労働組合がintとして使用しているフロートできるようにコンパイラを説得
bits: 0 1-9 10-32
sign bit exponent significant (or mantissa)
である32ビット浮動小数点の場合
(同じサイズのを!)、およびその逆。一度整数があれば、ビットで噛み砕くことができます。
符号ビットは左端のビットです.2^31で割るか、31で右にシフトすると得られます。
指数は以下の8ビットにあります。このコードは、仮数部のサイズの23ビットを右にシフトし、指数部をマスクする(符号ビットを除く)ことでそれを取得します。
これらは、右端の23ビットをマスクするだけで有効です。
指数自体に偏りがあります。どうして?数字が0の場合0 < n < 1に負の指数があり、数字> = 1の指数が正の値になります。符号に余分なビットを追加する代わりに、指数は半分になります。一定の限度(偏り)以下のものは全て負とみなし、上のすべてを正として取る必要があります。指数部の符号を正しい値で得るには、バイアスを減算するだけです。
規格によって定義されたいくつかの特別な値がありますInf
とNaN
(NaN
と静かNaN
シグナリング)
NaN
(IEEE STD 754-2008セクション6.2.1)としてエンコードされ
すべてのバイナリNaNビットストリングは、バイアスされた指数フィールドEのすべてのビットを1に設定します(3.4を参照)。静かなNaNビットストリングは、後続の仮数フィールドTの最初のビット(d1)を1にしてエンコードする必要があります。シグナリングNaNビットストリングは、後続の仮数フィールドの最初のビットを0にしてエンコードする必要があります。末尾の仮数フィールドが0である場合、後続の仮数フィールドの他のビットは、NaNを無限大と区別するために非ゼロでなければなりません。今説明した好ましい符号化では、シグナリングNaNは、d1を1に設定することによって静かにされ、Tの残りのビットは変更されない。
バイナリ形式の場合、ペイロードは末尾の有効なフィールドのp-2個の最小有効ビットでエンコードされます。Inf
ため
Inf
エンコーディングは、セクション3.5.2でのみ進エンコーディングのために、(または私はそれを見つけていない)IEEE-754で、そのような明示的に説明されていないが、通常最大であります指数(すべてのビットが1に設定されている)、プラスおよびマイナスの無限大を区別するための変更されていない符号ビット、および有限数と区別するために0に設定された仮数のすべてのビット。簡単にテストされています。
コードにおけるビットジャグリングは、非常に複雑であり、特定のエンディアンを想定しfloat
とuint32_t
が同じエンディアンを有しており、IEEE規格754-2008 /に記載されているように、そのfloat
が単精度フォーマットで符号化されますIEC 60559(C標準マクロ__STDC_IEC_559__
で確認する必要があります)、union
のトリックはコンパイラを使用して動作します。 frexp(3)
のようなものが必要な場合は、実際にビルドインを使用する必要があります。
frexp()
(それを書き換えることが怠惰にdouble
ため、。機能のほんの一握りが必要とメモリが疎であったので、それが書かれた、libmathの私自身のバージョンからである)浮いのみという、あまり多くのことを前提としていますポイント数は、IEC 60559に準拠しています。私は、複雑なインラインコムを置き換え
int isinf(double x){
// TODO: not every compiler might eat this check for Inf
// GCC-4.8.4 does
// TCC 0.9.25 does
// clang 3.4-1ubuntu3 (based on LLVM 3.4) does
return (x == 1.0/0.0 || x == -1.0/0.0);
}
int isnan(double x){
return (x != x);
}
を:
double frexp(double x, int *eptr)
{
int sign, exponent;
int i;
/*
* The exponent of an IEEE-754 double (binary64) is an 11-bit large integer
*/
double ap_2[11] = {
2.0000000000000000000000000000000000000,
4.0000000000000000000000000000000000000,
16.000000000000000000000000000000000000,
256.00000000000000000000000000000000000,
65536.000000000000000000000000000000000,
4294967296.0000000000000000000000000000,
18446744073709551616.000000000000000000,
3.4028236692093846346337460743176821146e38,
1.1579208923731619542357098500868790785e77,
1.3407807929942597099574024998205846128e154,
1.7976931348623157e308 // DBL_MAX
};
double ap_half[11] = {
0.50000000000000000000000000000000000000,
0.25000000000000000000000000000000000000,
0.062500000000000000000000000000000000000,
0.0039062500000000000000000000000000000000,
1.5258789062500000000000000000000000000e-5,
2.3283064365386962890625000000000000000e-10,
5.4210108624275221700372640043497085571e-20,
2.9387358770557187699218413430556141946e-39,
8.6361685550944446253863518628003995711e-78,
7.4583407312002067432909653154629338374e-155,
5.5626846462680034577255817933310101606e-309 // < DBL_MIN
};
if (isinf(x)) {
*eptr = 0;
return x;
}
if (isnan(x)) {
*eptr = 0;
return x;
}
if (x == 0.0) {
*eptr = 0;
return x;
}
exponent = 0.0;
/*
* Easier to work with positive values
*/
if (x < 0) {
x = -x;
sign = 1;
}
else {
sign = 0;
}
if (x >= 1.0) {
/*
* Big steps
*/
for (i = 0; x >= ap_2[i]; i++) {
exponent += (1 << i);
x *= ap_half[i];
}
/*
* Small steps
*/
if (x < 0.5) {
while (x < 0.5) {
x *= 2.0;
exponent--;
}
} else {
while (x > 1.0) {
x /= 2.0;
exponent++;
}
}
} else {
/*
* Same as above, but in the opposite direction
*/
for (i = 0; x < ap_half[i]; i++) {
exponent -= (1 << i);
x *= ap_2[i];
}
if (x < 0.5) {
while (x < 0.5) {
x *= 2.0;
exponent--;
}
} else {
while (x > 1.0) {
x /= 2.0;
exponent++;
}
}
}
if (sign) {
x = -x;
}
*eptr = exponent;
return x;
}
機能isinf()
は、すべてのコンパイラがそれをサポートする可能性があります、私はそれを置くものとどのように、ビットで大胆かつません2の倍数の2つの表の(先に述べたように:メモリは疎であった)putation。私はそれを行うことでコードの残りの部分を崩壊させないことを願っています。
Aaaaaand私はいつものように遅すぎました。この時間はAmin Negm-Awadが43分に迫った。
'frexp 'と呼ばれることができる関数がmath.hにあります。仮数部は[0.5,1 [ – rondino
の間にあります。*型打ち*には' union'があります。 2つの異なるタイプ。そうでなければ、 'float'だけを持っていれば、その' float'にアクセスすると、(浮動小数点型の)*値*が得られます。決してビットパターンはありません。 uint32_tとしての2番目の*ビュー*は、値(unsinged number)がそれを表すビットパターンとの移植可能な関係を持っているという利点があります。 –