将double常量定义为十六进制?

时间:2010-10-16 00:53:56

标签: c++ floating-point floating-accuracy ieee-754 notation

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

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

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

使用起来相当麻烦。

有没有更好的方法来定义这个双号,如果可能的话,作为常量?

7 个答案:

答案 0 :(得分:7)

确实存在十六进制浮点数和双重文字。 语法为0x1。(尾数)p(十进制指数) 在您的情况下,语法将是

double x = 0x1.fffffffffffffp-1

答案 1 :(得分:3)

这不安全,但有点像:

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

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

相反,只需将DBL_EPSILON放入<cfloat>(或在另一个答案std::numeric_limits<double>::epsilon()中指出)就可以充分利用。

答案 2 :(得分: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;
}

答案 3 :(得分:1)

如果您制作bit_cast并使用fixed-width integer types,则可以安全地完成:

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);

虽然你可能只是subtract epsilon from it

答案 4 :(得分:0)

这有点陈旧,但你可以使用union。 假设您的系统上long longdouble都是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的位表示是什么。

答案 5 :(得分: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营救!

答案 6 :(得分:0)

最直接的解决方案是使用nextafter()中的math.h,而不是千篇一律。因此:

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

读为:1.00.0方向的下一个浮点值;原始问题的“ 1.0以下最近的数字”几乎是直接编码。