C++ 将双常量定义为十六进制?

C++ 将双常量定义为十六进制?,c++,floating-point,floating-accuracy,ieee-754,notation,C++,Floating Point,Floating Accuracy,Ieee 754,Notation,我希望将小于1.0的最接近数字作为浮点。通过阅读维基百科关于的文章,我发现1.0的二进制表示形式是3FF0000000000000,因此最接近的双精度值实际上是0x3fefffffffffff 据我所知,使用此二进制数据初始化double的唯一方法是: double a; *((unsigned*)(&a) + 1) = 0x3FEFFFFF; *((unsigned*)(&a) + 0) = 0xFFFFFFFF; 使用起来相当麻烦 如果可能的话,有没有更好的方法将这个双倍数

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

据我所知,使用此二进制数据初始化double的唯一方法是:

double a;
*((unsigned*)(&a) + 1) = 0x3FEFFFFF;
*((unsigned*)(&a) + 0) = 0xFFFFFFFF;
使用起来相当麻烦


如果可能的话,有没有更好的方法将这个双倍数定义为一个常数?

它不安全,但类似于:

double a;
*(reinterpret_cast<uint64_t *>(&a)) = 0x3FEFFFFFFFFFFFFFL;
双a;
*(重新解释类型(&a))=0x3FEFFFFFFFFFFFL;
但是,这取决于系统中浮点数的特定尾数,所以不要这样做

相反,只需在
中使用
DBL\u EPSILON
(或者正如另一个答案中指出的,
std::numeric\u limits::EPSILON()
)即可
#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;
}
#包括 #包括 使用名称空间std; int main() { 双常数x=1.0-数值限制::epsilon(); 库特
::digits10+1)如果您进行
位转换并使用,则可以安全地完成:

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);
模板
R位强制转换(常数T和P值)
{
//静态断言R和T是POD类型
//reinterpret_cast由实现定义,
//但很可能是你所期待的
返回重新解释(pValue);
}
const uint64_t target=0x3fefffffffffffl;
双结果=位_转换(目标);

虽然您可能只是。

这有点过时,但您可以使用
联合。
假设系统上的
long
double
都是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;
}
typedef并集{long long a;double b}my_并集;
int main()
{
我的工会c;
c、 b=1.0;
c、 a——;

十六进制浮点和双字面值确实存在。 语法为0x1。(尾数)p(十进制指数) 在您的例子中,语法是

double x = 0x1.fffffffffffffp-1

这个
0x1.ffffffffffffp-1
语法很棒,但仅在C99或C++17中使用

但是有一个解决办法,没有(指针)投射,没有UB/IB,只有简单的数学

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

double x=(double)0x1ffffffffffffff/(1LL不是所有的位杂耍,最直接的解决方案是使用
nextafter()
from
math.h
。因此:

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

将此视为:在代码< >代码> 0 >代码下的下一个浮点值;对原始问题的“最接近数1以下”的几乎直接编码。

唯一的方法是…除非你的C++实现有64位整数支持。这只是挑剔,但它是IEEE-75—1985(不是IEEE-75)。。严格来说,这就导致了UB。我不知道为什么在可以直接使用
reinterpret\u cast
的情况下定义位类型时会遇到麻烦。这似乎仍然是一个很好的解决方案。@Mark:这不会静态断言这两种类型都是POD类型,并且更容易打破别名规则。(无可否认,我给出了一个比要求更一般的解决方案;在这种情况下,直接做就行了。)我以前从未听说过这种语法。你有参考资料吗?我认为它是C99标准的一部分。它与GNU编译器一起工作,我不关心其他编译器。@Mark Ransom:我最近写了一篇关于这一点的文章:@Mark Ransom:在C99中添加。通过
%a
格式说明符在
printf
/
scanf
中也支持它。到目前为止,bes在C中指定浮点值的一种方法。将其视为整数应该使其与endian无关(除非你有一个奇怪的“混合endian”系统)@Rick Regan:谁会说“endian”是您的平台的浮点类型表示形式与整数类型表示形式一致吗?理论上您是对的——但是您有没有一个例子(除了混合的endian“软浮点”)呢?
#include <math.h>
double a = nextafter(1.0, 0.0);