C++ 将双常量定义为十六进制?
我希望将小于1.0的最接近数字作为浮点。通过阅读维基百科关于的文章,我发现1.0的二进制表示形式是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; 使用起来相当麻烦 如果可能的话,有没有更好的方法将这个双倍数
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-数值限制::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()
frommath.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);