不,这是不可能的。
哦,我在开玩笑吧!只需编写一个 IEE745 数字的预处理器解析器,即可通过预处理该数字来生成浮点常量表达式。以下代码允许您执行以下操作:
const double invalid_double = HEX_TO_DOUBLE(0x7ff0000000000001);
请注意,EXPONENT_TO_DOUBLE_IN
宏大约缺少2000个案例,所以并不是所有的数字都被处理,但是很容易填满。或者也许有人会更好地了解如何将指数转换为 2^(exponent-1023)。
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <float.h>
#include <math.h>
#include <inttypes.h>
// Apply function f on argument x and number
#define FOREACH_52(f, x) \
f(x, 52) f(x, 51) f(x, 50) f(x, 49) f(x, 48) f(x, 47) f(x, 46) f(x, 45) \
f(x, 44) f(x, 43) f(x, 42) f(x, 41) f(x, 40) f(x, 39) f(x, 38) f(x, 37) \
f(x, 36) f(x, 35) f(x, 34) f(x, 33) f(x, 32) f(x, 31) f(x, 30) f(x, 29) \
f(x, 28) f(x, 27) f(x, 26) f(x, 25) f(x, 24) f(x, 23) f(x, 22) f(x, 21) \
f(x, 20) f(x, 19) f(x, 18) f(x, 17) f(x, 16) f(x, 15) f(x, 14) f(x, 13) \
f(x, 12) f(x, 11) f(x, 10) f(x, 9) f(x, 8) f(x, 7) f(x, 6) f(x, 5) \
f(x, 4) f(x, 3) f(x, 2) f(x, 1)
#define EXPONENT_TO_DOUBLE_CASE(x, y) \
x == (unsigned long long) y ? 0x1p ##y : \
x == (unsigned long long)-y ? 0x1p-##y :
#define EXPONENT_TO_DOUBLE_IN(x) ( \
EXPONENT_TO_DOUBLE_CASE(x, 1022) \
EXPONENT_TO_DOUBLE_CASE(x, 1021) \
EXPONENT_TO_DOUBLE_CASE(x, 127) \
EXPONENT_TO_DOUBLE_CASE(x, 2) \
EXPONENT_TO_DOUBLE_CASE(x, 1) \
EXPONENT_TO_DOUBLE_CASE(x, 0) \
/* TODO: add more cases*/ \
NAN )
// Convert EXPONENT number to 2^(x - 1023) number
#define EXPONENT_TO_DOUBLE(x) EXPONENT_TO_DOUBLE_IN(x - 1023)
#define FRACTION_TO_DOUBLE_CASE(x, n) \
( (x & (1ull << (52 - n))) ? 0x1p-##n : 0 ) +
// Convert FRACTION to 0.FRACTION_BITS(2) number.
#define FRACTION_TO_DOUBLE(x) ( \
FOREACH_52(FRACTION_TO_DOUBLE_CASE, x) \
0 )
// Convert sign, exponent and fraction into a hex number.
#define HEX_TO_DOUBLE_IN(SIGN, EXP, FRAC) \
EXP == 0x7FF ? \
FRAC == 0 ? \
SIGN * INFINITY : \
NAN : \
SIGN * EXPONENT_TO_DOUBLE(EXP) * ( \
EXP == 0 ? \
FRAC == 0 ? \
0 : \
(0.0 + FRACTION_TO_DOUBLE(FRAC)) : \
(1.0 + FRACTION_TO_DOUBLE(FRAC)) \
)
// The basic conversion utilities.
#define HEX_TO_DOUBLE_SIGN(x) (((x) & 0x8000000000000000ull) ? -1.0 : 1.0)
#define HEX_TO_DOUBLE_EXPONENT(x) (((x) & 0x7FF0000000000000ull) >> 52ull)
#define HEX_TO_DOUBLE_FRACTION(x) (((x) & 0x000fffffffffffffull))
#define HEX_TO_DOUBLE(x) \
HEX_TO_DOUBLE_IN( \
HEX_TO_DOUBLE_SIGN(x), \
HEX_TO_DOUBLE_EXPONENT(x), \
HEX_TO_DOUBLE_FRACTION(x) \
)
/* ----------------------------------------------------------------------- */
union conv { uint64_t i; double d; };
static int err = 0;
void test(const char *str, union conv u, double d) {
int equal = (isnan(d) && isnan(u.d)) || u.d == d;
fprintf(stderr,
"%s if %s is %#"PRIx64" = %g,%a =? %g,%a\n",
equal ? " OK" : "ERROR",
str, u.i, u.d, u.d, d, d
);
err += !equal;
}
// Test the conversion.
#define TEST(x) do { \
static const double mydouble = HEX_TO_DOUBLE(x); \
test(#x, (union conv){x}, mydouble); \
} while(0)
int main() {
assert(HEX_TO_DOUBLE_EXPONENT(0x3FF0000000000000) == 0x3FF);
assert(FRACTION_TO_DOUBLE(0) == 0);
assert(FRACTION_TO_DOUBLE(1) == 0x1p-52);
assert(FRACTION_TO_DOUBLE(0x2) == 0x1p-51);
assert(FRACTION_TO_DOUBLE(0x3) == 0x1p-51 + 0x1p-52);
TEST(0x3FF0000000000000);
TEST(0x3FF0000000000001);
TEST(0x3FF0000000000101);
TEST(0x3FFabcdef1234567);
TEST(0xFFF0000000000000);
TEST(0x7FF0000000000000);
TEST(0x7FF0000000000001);
// Finally, the test.
static const double invalid_double = HEX_TO_DOUBLE(0x7ff0000000000001);
assert(isnan(invalid_double));
return err;
}
当编译时gcc -Wall -Wextra -pedantic
输出代码test()
我用于单元测试的函数。
OK if 0x3FF0000000000000 is 0x3ff0000000000000 = 1,0x1p+0 =? 1,0x1p+0
OK if 0x3FF0000000000001 is 0x3ff0000000000001 = 1,0x1.0000000000001p+0 =? 1,0x1.0000000000001p+0
OK if 0x3FF0000000000101 is 0x3ff0000000000101 = 1,0x1.0000000000101p+0 =? 1,0x1.0000000000101p+0
OK if 0x3FFabcdef1234567 is 0x3ffabcdef1234567 = 1.67111,0x1.abcdef1234567p+0 =? 1.67111,0x1.abcdef1234567p+0
OK if 0xFFF0000000000000 is 0xfff0000000000000 = -inf,-inf =? -inf,-inf
OK if 0x7FF0000000000000 is 0x7ff0000000000000 = inf,inf =? inf,inf
OK if 0x7FF0000000000001 is 0x7ff0000000000001 = nan,nan =? nan,nan
其他案例NAN("1")
等等也可以用 if-case 来处理,比如#define FRACTION_TO_NAN(x) x == 0 ? __builtin_nan("0") : x == 1 ? __builtin_nan("1") ...
但是,我不认为这是可以编译的。
无论如何,不可能将十六进制转换为双精度static
。而对于NAN
对于特殊分数,无论如何您都必须使用编译器扩展,请参阅 user694733 的回答。