Насколько я понимаю,
Таким образом, я должен ожидать, что существует функция f
, которая может отображать каждый дубль в уникальный uint64_t, и что порядок должен поддерживаться, а именно для всех double lhs, rhs
, lhs < rhs == f(lhs) < f(rhs)
, кроме тех случаев, когда (lhs
или rhs
- это NaN
).
Мне не удалось найти такую функцию в библиотеке или ответе StackOverflow, хотя такая функция, вероятно, полезна, чтобы избежать создания экземпляра дополнительного шаблона для двойников в алгоритмах сортировки, где double
редко используется в качестве ключа сортировки.
Я знаю, что простое деление на EPSILON не сработает, потому что точность фактически уменьшается по мере увеличения числа (и улучшается по мере приближения чисел к нулю); Однако я не совсем проработал точные детали этого масштабирования.
Наверняка такая функция в принципе существует.
Разве я не нашел его, потому что он не может быть написан на стандартном C++? Что это будет слишком медленно? Что это не так полезно для людей, как я думаю?
Платформы IEEE 754 иногда имеют несколько отклонений. Если вы просто хотите скопировать бит, используйте memcpy
из одного в другой. Если вы пытаетесь извлечь значение, а не битовый шаблон, вы, вероятно, захотите извлечь бит знака в переменную, мантиссу в переменную и показатель степени в переменную. И как-нибудь пометить + Inf, -Inf и NaN.
@NathanOliver О, ты прав. Я видел диаграмму на en.cppreference.com/w/cpp/language/types, в которой это только что есть в «Кодировке», и пропустил «почти», где double объясняется как: double precision floating point type. Usually IEEE-754 64 bit floating point type
. То есть double даже не гарантированно "подходит" (не имеет более уникальных значений, чем) uint64_t?
Нет. Он должен быть не меньше числа с плавающей запятой, но вполне законно для реализации сделать размер двойника шириной 128 бит, если это необходимо. Однако вы можете static_assert(sizeof(std::uint64_t) == sizeof(double));
убедиться, что они одинаковой ширины.
Мне кажется, вы ищете какую-то магию, как это было в Quake 3: en.wikipedia.org/wiki/… Может быть, вы найдете новое магическое число и станете звездой;)
Если представления 64-битных чисел с плавающей запятой IEEE-754 обрабатываются как 64-битные значения с дополнением до двух, эти значения имеют тот же порядок, что и соответствующие значения с плавающей запятой. Единственная необходимая корректировка - это мысленная корректировка, чтобы увидеть образец битов как представляющий либо значение с плавающей запятой, либо целочисленное значение. В процессоре это просто: у вас есть 64 бита данных, хранящихся в памяти, и если вы применяете операцию с плавающей запятой к этим битам, вы выполняете операции с плавающей запятой, и если вы применяете целочисленные операции к этим битам, вы выполняете целочисленные операции.
В C++ тип данных определяет тип операций, которые вы можете выполнять. Чтобы применить операции с плавающей запятой к 64-битному объекту данных, этот объект должен быть типа с плавающей запятой. Для применения интегральных операций он должен быть целым типом.
Чтобы преобразовать битовые комбинации из чисел с плавающей запятой в целые:
std::int64_t to_int(double d) {
std::int64_t res
std::memcpy(&res, &d, sizeof(std::int64_t));
return res;
}
Преобразование в обратном направлении остается для читателя упражнением.
Пытался внести правку, чтобы изменить 64 на 8 (или, на самом деле, sizeof (std :: uint64_t), потому что программное обеспечение не допускает такого небольшого редактирования), но оно было отклонено. Очевидно, что memcpy предназначен для копирования 8 байтов, а не 64.
Судя по эксперименту, это работает для положительных двойников. Непонятно из ответа, как (уверенно) распространить это на негативы. Также неясно, как IEEE-754 гарантирует, что это будет работать.
@WilliamNavarre - IEEE-754 не гарантия, что это будет работать. Он говорит, что с типичным оборудованием с дополнением до двух это будет работать. И если присмотреться, то, вероятно, следует использовать int64_t
, а не uint64_t
. Вздох. Отредактировано соответствующим образом.
Спасибо за разъяснения. Я принял твой ответ.