С длинный двойной в Голанге
Я портирую алгоритм с C на Go. И я немного запутался. Это функция C:
void gauss_gen_cdf(uint64_t cdf[], long double sigma, int n)
{
int i;
long double s, d, e;
//Calculations ...
for (i = 1; i < n - 1; i++) {
cdf[i] = s;
}
}
А в цикле for значение "s" присваивается элементу "x" массива cdf. Как это возможно? Насколько я знаю, long double - это float64 (в контексте Go). Так что я не должен быть в состоянии скомпилировать код C, потому что я присваиваю long double массиву, который содержит только элементы uint64. Но код C работает нормально.
Так может кто-нибудь объяснить, почему это работает?
Большое спасибо.
ОБНОВИТЬ:
Оригинальный C-код функции можно найти здесь: https://github.com/mjosaarinen/hilabliss/blob/master/distribution.c#L22
1 ответ
Назначение cdf[i] = s
выполняет неявное преобразование в uint64_t
, Трудно сказать, предназначено ли это без вычислений, которые вы пропустили.
На практике, long double
как тип имеет значительные различия между архитектурами. Будь го float64
Соответствующая замена зависит от архитектуры, с которой вы портируете. Например, на x86, long double
является типом с повышенной точностью 80 байт, но системы Windows обычно настраиваются таким образом, чтобы вычислять результаты только с помощью 53-битной мантиссы, что означает, что float64
все еще может быть эквивалентным для ваших целей.
РЕДАКТИРОВАТЬ В этом конкретном случае значения, рассчитанные источниками, кажутся статическими и независимыми от ввода. Я бы просто использовал float64
на стороне Go и посмотрите, идентичны ли вычисленные значения значениям версии C при запуске на компьютере с архитектурой x86 под реальной GNU/Linux (с виртуализацией все должно быть в порядке), чтобы обойти проблемы Windows FPU. Выбор x86 - всего лишь предположение, потому что, скорее всего, это использовал первоначальный автор. Я не понимаю основную криптографию, поэтому не могу сказать, влияет ли разница в вычисленных значениях на безопасность. (Также обратите внимание, что код C, похоже, неправильно заполняет свой PRNG.)
C long double в голанге
Название предполагает интерес к тому, имеет ли Go тип с плавающей запятой повышенной точности, подобный long double
в C.
Ответ:
- Не как примитив, см. Основные типы.
- Но произвольная точность поддерживается математической / большой библиотекой.
Почему это работает?
long double s = some_calculation();
uint64_t a = s;
Он компилируется, потому что, в отличие от Go, C допускает определенные неявные преобразования типов. Целая часть из плавающей точкой значенияs
будет скопировано. Предположительноs
значение было масштабировано таким образом, чтобы его можно было интерпретировать как значение с фиксированной точкой, где на основе источника связанной библиотеки 0xFFFFFFFFFFFFFFFF
(2^64-1) представляет значение 1.0. Чтобы максимально использовать такие назначения, может быть целесообразно использовать расширенный тип с плавающей запятой с 64 битами точности.
Если бы мне пришлось угадывать, я бы сказал, что (связанная с криптовалютой) библиотека использует здесь фиксированную точку, потому что они хотят гарантировать детерминированные результаты, см.: Как можно сделать вычисления с плавающей запятой детерминированными?. А поскольку плавающая запятая с расширенной точностью используется только для инициализации таблицы поиска, использование (предположительно медленной) математической / большой библиотеки, вероятно, будет отлично работать в этом контексте.