определить двойную константу как шестнадцатеричное? - PullRequest
6 голосов
/ 16 октября 2010

Я бы хотел, чтобы ближайшее число было меньше 1,0 в качестве плавающей запятой.Прочитав статью в Википедии о IEEE-754 , мне удалось выяснить, что двоичное представление для 1.0 равно 3FF0000000000000, поэтому самое близкое двойное значение на самом деле 0x3FEFFFFFFFFFFFFF.

.Я знаю, как инициализировать двойное с этими двоичными данными так:

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

Что довольно неудобно для использования.

Есть ли лучший способ определить это двойное число, если это возможнокак константа?

Ответы [ 6 ]

7 голосов
/ 16 октября 2010

Шестнадцатеричное число с плавающей запятой и двойные литералы существуют.Синтаксис 0x1. (Мантисса) p (экспонента в десятичной дроби) В вашем случае синтаксис будет

double x = 0x1.fffffffffffffp-1
3 голосов
/ 16 октября 2010
#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 голосов
/ 16 октября 2010

Это небезопасно, но что-то вроде:

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

Однако, это зависит от определенной последовательности значений с плавающей точкой в ​​вашей системе, поэтому не делайте этого!

Вместо этого просто положите DBL_EPSILON в <cfloat> (или, как указано в другом ответе, std::numeric_limits<double>::epsilon()) для хорошего использования.

1 голос
/ 16 октября 2010

Если вы делаете 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 из него .

0 голосов
/ 09 мая 2018

Этот синтаксис 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 для спасения!

0 голосов
/ 16 октября 2010

Это немного архаично, но вы можете использовать union.Предполагая, что long 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;
}

Здесь вам не нужно заранее знать, что такое битовое представление 1.0.

...