Есть ли функция, которая может преобразовывать каждое двойное значение в уникальный uint64_t, сохраняя точность и ПОРЯДОК? (Почему я не могу его найти?)

Насколько я понимаю,

  • Двойники в C++ (по крайней мере, концептуально) кодируются как числа с плавающей запятой двойной точности в кодировке IEEE 754.
  • IEEE 754 говорит, что такие числа могут быть представлены 64-битными.

Таким образом, я должен ожидать, что существует функция f, которая может отображать каждый дубль в уникальный uint64_t, и что порядок должен поддерживаться, а именно для всех double lhs, rhs, lhs < rhs == f(lhs) < f(rhs), кроме тех случаев, когда (lhs или rhs - это NaN).

Мне не удалось найти такую ​​функцию в библиотеке или ответе StackOverflow, хотя такая функция, вероятно, полезна, чтобы избежать создания экземпляра дополнительного шаблона для двойников в алгоритмах сортировки, где double редко используется в качестве ключа сортировки.

Я знаю, что простое деление на EPSILON не сработает, потому что точность фактически уменьшается по мере увеличения числа (и улучшается по мере приближения чисел к нулю); Однако я не совсем проработал точные детали этого масштабирования.

Наверняка такая функция в принципе существует.

Разве я не нашел его, потому что он не может быть написан на стандартном C++? Что это будет слишком медленно? Что это не так полезно для людей, как я думаю?

Двойники в C++ (по крайней мере, концептуально) кодируются как числа с плавающей запятой двойной точности в кодировке IEEE 754.. Неа. В стандарте указано: Представление значений типов с плавающей запятой определяется реализацией.
NathanOliver 17.12.2018 21:26

Платформы IEEE 754 иногда имеют несколько отклонений. Если вы просто хотите скопировать бит, используйте memcpy из одного в другой. Если вы пытаетесь извлечь значение, а не битовый шаблон, вы, вероятно, захотите извлечь бит знака в переменную, мантиссу в переменную и показатель степени в переменную. И как-нибудь пометить + Inf, -Inf и NaN.

Eljay 17.12.2018 21:30

@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?

William Navarre 17.12.2018 21:31

Нет. Он должен быть не меньше числа с плавающей запятой, но вполне законно для реализации сделать размер двойника шириной 128 бит, если это необходимо. Однако вы можете static_assert(sizeof(std::uint64_t) == sizeof(double)); убедиться, что они одинаковой ширины.

NathanOliver 17.12.2018 21:34

Мне кажется, вы ищете какую-то магию, как это было в Quake 3: en.wikipedia.org/wiki/… Может быть, вы найдете новое магическое число и станете звездой;)

R2RT 17.12.2018 22:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если представления 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.

William Navarre 20.12.2018 20:01

Судя по эксперименту, это работает для положительных двойников. Непонятно из ответа, как (уверенно) распространить это на негативы. Также неясно, как IEEE-754 гарантирует, что это будет работать.

William Navarre 20.12.2018 20:02

@WilliamNavarre - IEEE-754 не гарантия, что это будет работать. Он говорит, что с типичным оборудованием с дополнением до двух это будет работать. И если присмотреться, то, вероятно, следует использовать int64_t, а не uint64_t. Вздох. Отредактировано соответствующим образом.

Pete Becker 20.12.2018 20:26

Спасибо за разъяснения. Я принял твой ответ.

William Navarre 20.12.2018 20:41

Другие вопросы по теме