С длинный двойной в Голанге

Я портирую алгоритм с 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 битами точности.

Если бы мне пришлось угадывать, я бы сказал, что (связанная с криптовалютой) библиотека использует здесь фиксированную точку, потому что они хотят гарантировать детерминированные результаты, см.: Как можно сделать вычисления с плавающей запятой детерминированными?. А поскольку плавающая запятая с расширенной точностью используется только для инициализации таблицы поиска, использование (предположительно медленной) математической / большой библиотеки, вероятно, будет отлично работать в этом контексте.

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