convert from float-point to custom numeric typeという質問に基づいて、浮動小数点型を整数の配列に変換するポータブルで安全な方法を見つけました。コードは正常に動作しますが、 から に変換するときの値によってdouble
はunsigned long long
、unsigned long long
signed long long
Visual C++ 2008、intel xe 2013、および gcc 4.7.2 では、コンパイル時のエラーではなく、表現可能な最小値またはゼロである無効な値で変換によって安全に表現されますが失敗します。
ここにコードがあります:(関数内のwhile
ループ内の最初のステートメントに注意してくださいmain
)
#ifndef CHAR_BIT
#include <limits.h>
#endif
#include <float.h>
#include <math.h>
typedef signed int int32;
typedef signed long long int64;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef float float32;
typedef double float64;
// get size of type in bits corresponding to CHAR_BIT.
template<typename t>
struct sizeof_ex
{
static const uint32 value = sizeof(t) * CHAR_BIT;
};
// factorial function
float64 fct(int32 i)
{
float64 r = 1;
do r *= i; while(--i > 1);
return r;
}
int main()
{
// maximum 2 to power that can be stored in uint32
const uint32 power_2 = uint32(~0);
// number of binary digits in power_2
const uint32 digit_cnt = sizeof_ex<uint32>::value;
// number of array elements that will store expanded value
const uint32 comp_count = DBL_MAX_EXP / digit_cnt + uint32((DBL_MAX_EXP / digit_cnt) * digit_cnt < DBL_MAX_EXP);
// array elements
uint32 value[comp_count];
// get factorial for 23
float64 f = fct<float64>(23);
// save sign for later correction
bool sign = f < 0;
// remove sign from float-point if exists
if (sign) f *= -1;
// get number of binary digits in f
uint32 actual_digits = 0;
frexp(f, (int32*)&actual_digits);
// get start index in array for little-endian format
uint32 start_index = (actual_digits / digit_cnt) + uint32((actual_digits / digit_cnt) * digit_cnt < actual_digits) - 1;
// get all parts but the last
while (start_index > 0)
{
// store current part
// in this line the compiler fails
value[start_index] = uint64(f / power_2);
// exclude it from f
f -= power_2 * float64(value[start_index]);
// decrement index
--start_index;
}
// get last part
value[0] = uint32(f);
}
上記の変換コードは、コンパイラごとに異なる結果を返します。つまり、factorial 関数のパラメータが 20 の場合、すべてのコンパイラが有効な結果を返し、値が 20 を超える場合、一部のコンパイラは結果の一部を取得し、他のコンパイラは取得しない場合があります。大きくなる、例えば35
ゼロになる。
これらのエラーが発生する理由を教えてください。
ありがとうございました。