6

我希望将最接近的低于 1.0 的数字作为浮点数。通过阅读维基百科关于IEEE-754的文章,我设法发现 1.0 的二进制表示是3FF0000000000000,因此最接近的双精度值实际上是0x3FEFFFFFFFFFFFFF

我知道用这个二进制数据初始化双精度的唯一方法是:

double a;
*((unsigned*)(&a) + 1) = 0x3FEFFFFF;
*((unsigned*)(&a) + 0) = 0xFFFFFFFF;

使用起来相当麻烦。

如果可能的话,有没有更好的方法来定义这个双数?

4

7 回答 7

8

确实存在十六进制浮点数和双精度字面值。语法是 0x1.(mantissa)p(exponent in decimal) 在你的情况下,语法是

double x = 0x1.fffffffffffffp-1
于 2010-10-16T04:49:08.230 回答
3

这不安全,但类似于:

double a;
*(reinterpret_cast<uint64_t *>(&a)) = 0x3FEFFFFFFFFFFFFFL;

但是,这依赖于系统上浮点数的特定字节顺序,所以不要这样做!

相反,只需放入DBL_EPSILON<cfloat>或如另一个答案中所指出的那样std::numeric_limits<double>::epsilon())以充分利用。

于 2010-10-16T00:59:01.713 回答
3
#include <iostream>
#include <iomanip>
#include <limits>
using namespace std;

int main()
{
    double const    x   = 1.0 - numeric_limits< double >::epsilon();

    cout
        << setprecision( numeric_limits< double >::digits10 + 1 ) << fixed << x
        << endl;
}
于 2010-10-16T01:04:08.613 回答
1

如果您制作bit_cast并使用固定宽度整数类型,则可以安全地完成:

template <typename R, typename T>
R bit_cast(const T& pValue)
{
    // static assert R and T are POD types

    // reinterpret_cast is implementation defined,
    // but likely does what you expect
    return reinterpret_cast<const R&>(pValue);
}

const uint64_t target = 0x3FEFFFFFFFFFFFFFL;
double result = bit_cast<double>(target);

虽然你可能只是从中减去epsilon

于 2010-10-16T01:05:46.333 回答
0

这有点过时,但您可以使用union. 假设 along long和 adouble在您的系统上都是 8 个字节长:

typedef union { long long a; double b } my_union;

int main()
{
    my_union c;
    c.b = 1.0;
    c.a--;
    std::cout << "Double value is " << c.b << std::endl;
    std::cout << "Long long value is " << c.a << std::endl;
}

这里不需要提前知道 1.0 的位表示是什么。

于 2010-10-16T03:07:32.757 回答
0

这种0x1.fffffffffffffp-1语法很棒,但仅限于 C99 或 C++17。

但是有一个解决方法,没有(指针)转换,没有 UB/IB,只是简单的数学。

double x = (double)0x1fffffffffffff / (1LL << 53);

如果我需要一个 Pi,并且 Pi(double) 是十六进制的 0x1.921fb54442d18p1,只需写

const double PI = (double)0x1921fb54442d18 / (1LL << 51);

如果你的常数有大或小指数,你可以使用函数exp2而不是移位,但是exp2是 C99/C++11 ...pow用于救援!

于 2018-05-09T15:21:18.247 回答
0

nextafter()最直接的解决方案是使用from ,而不是所有的杂耍math.h。因此:

#include <math.h>
double a = nextafter(1.0, 0.0); 

1.0将其读作:方向之后的下一个浮点值0.0;原始问题中“低于 1.0 的最接近数字”的几乎直接编码。

于 2019-12-09T17:47:19.990 回答