c++ 如何检查std::frexp的结果是否在当前编译器下指定?

mkh04yzy  于 2023-02-01  发布在  其他
关注(0)|答案(1)|浏览(129)

std::frexp是一个函数,它从浮点变量中移除指数,并将其放入int类型的变量exp中。它使用int,而不管指数实际需要多少位,并根据链接页:
如果要存储在*exp中的值超出int的范围,则行为未指定。
那么,如何检查"*exp是否在int的范围之外"?
我正在考虑在代码中添加一个static_assert来比较FLT_MIN_EXP & FLT_MAX_EXPINT_MIN & INT_MAX,但是,我担心会犯一个差一的错误,因为我没有完全理解这些常量的描述。
FLT_MIN_EXP
最小负整数,使FLT_RADIX乘以该整数的小1的幂等于规范化的float ...
FLT_MAX_EXP
最大正整数,使得FLT_RADIX乘以该整数的小1的幂等于可表示的有限float ...
(代码中已经有了static_assert(FLT_RADIX == 2);,所以基数等于10在我的例子中不是问题。)

eh57zj3b

eh57zj3b1#

Assert1:这个手术 * 通常效果很好 *,你不需要担心任何事情。
Assert二:为了让你安心,如果有任何一个系统不能正常工作,我们都想知道,当我们找到其中一个系统时,我们会重新审视解决方案。
Assert三:如果std::frexp的操作是 reversible 的,那么从std::frexp返回的最大和最小指数可以用系统的int类型表示。
std::frexp反转为它的补码std::ldexp
请注意,如果int不能保存浮点数的指数,则结果是 not undefined(只是未指定),因此我们可以相信测试是格式良好的。

编写一个单元测试,测试这是否可逆

TEST_CASE("The largest exponent returned by std::frexp can be represented by int") {
    long double largest_ld = std::numeric_limits<long double>::max();

    int exponent;
    long double fraction = std::frexp(largest_ld, &exponent);

    errno = 0;
    REQUIRE(std::ldexp(fraction, exponent) == largest_ld);
    REQUIRE(errno == 0); // just in case?
}

TEST_CASE("The smallest exponent returned by std::frexp can be represented by int") {
    long double smallest_ld = std::numeric_limits<long double>::min();

    int exponent;
    long double fraction = std::frexp(smallest_ld, &exponent);

    errno = 0;
    REQUIRE(std::ldexp(fraction, exponent) == smallest_ld);
    REQUIRE(errno == 0); // just in case?
}

编译时检查能做得更好吗?

也许吧,但是我在理解你遇到麻烦的语言的同一部分时遇到了麻烦,所以我在编译时检查上优化了开发速度。
作为一级近似,我建议:

static_assert(sizeof(int) >= 32);
static_assert(std::numeric_limits<long double>::is_eec559);

当然,当你遇到一个平台,这是不正确的。

相关问题