检测将整数转换为浮点类型时的溢出情况。根据C规范,FLT_MAX和DBL_MAX至少为1E+37,因此所有值的|值|小于122位的整数在所有符合条件的平台上都可以转换为float而不会溢出。双精度浮点数也是如此。
要解决128/256等位数的整数的一般情况,需要同时减小FLT_MAX和some_big_integer_MAX。可以通过对两个数取对数来实现(bit_count()是一个待定用户代码)。
if(bit_count(unsigned_big_integer_MAX) > logbf(FLT_MAX)) problem();
如果整数没有填充,则可以这样做。
if(sizeof(unsigned_big_integer_MAX)*CHAR_BIT > logbf(FLT_MAX)) problem();
注意:使用类似
logbf()
的FP函数可能会在精确整数计算中产生边缘情况,导致比较错误。
宏魔法可以使用像下面这样的晦涩测试,利用
BIGINT_MAX
肯定是2的幂减1和
FLT_MAX
除以2的幂肯定是精确的(除非
FLT_RADIX == 10
)。
如果从大整数类型到
float
的转换对于
某些大整数不精确,则此预处理器代码将
抱怨。
#define POW2_61 0x2000000000000000u
#if BIGINT_MAX/POW2_61 > POW2_61
#define BIGINT_MAX_PLUS1_div_POW2_61 ((BIGINT_MAX/2 + 1)/(POW2_61/2))
#if BIGINT_MAX_PLUS1_div_POW2_61 > POW2_61
#warning TBD code for an integer wider than 183 bits
#else
_Static_assert(BIGINT_MAX_PLUS1_div_POW2_61 <= FLT_MAX/POW2_61,
"bigint too big for float");
#endif
#endif
[编辑2]
有没有办法检查最后一种情况?
如果从大整数类型转换为float
在选定的大整数中是不精确的,则此代码将报错。
当然,在尝试转换之前需要进行测试。鉴于各种舍入模式或FLT_RADIX == 10
很少出现,现在可以轻松获得的是一个略有下降趋势的测试。当它为真时,转换将起作用。但是,只有非常小范围的大整数在以下测试中报告错误才能正确转换。
以下是我需要再考虑一下的更完善的想法,但我希望它提供了一些关于测试 OP所寻找的编码思路。
#define POW2_60 0x1000000000000000u
#define POW2_62 0x4000000000000000u
#define MAX_FLT_MIN 1e37
#define MAX_FLT_MIN_LOG2 (122 )
bool intmax_to_float_OK(intmax_t x) {
#if INTMAX_MAX/POW2_60 < POW2_62
(void) x;
return true;
#elif INTMAX_MAX/POW2_60/POW2_60 < POW2_62
return x/POW2_60 < (FLT_MAX/POW2_60)
#elif INTMAX_MAX/POW2_60/POW2_60/POW2_60 < POW2_62
return x/POW2_60/POW2_60 < (FLT_MAX/POW2_60/POW2_60)
#else
#error TBD code
#endif
}
uintmax_t
作为一个128位类型,其值仅略大于FLT_MAX
(溢出),这是一种真实的可能性,并且对于OP来说是一个合理的关注点。 - chux - Reinstate Monica