golang 中的 C long double

C long double in golang

我正在将算法从 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

赋值 cdf[i] = s 执行到 uint64_t 的隐式转换。如果没有您省略的计算,很难判断这是不是有意为之。

在实践中,long double 作为一种类型在不同的体系结构中具有相当大的差异。 Go 的 float64 是否是合适的替代品取决于您从中移植的架构。例如,在 x86 上,long double 是一个 80 字节的扩展精度类型,但是 Windows systems are usually configured in such a way to compute results only with the 53-bit mantissa,这意味着 float64 仍然可以等效于您的目的。

EDIT 在这种特殊情况下,源计算的值似乎是静态的并且独立于输入。我只会在 Go 端使用 float64 并查看计算值是否与 C 版本的值相同,当 运行 在真实 GNU/Linux 下的 x86 机器上(虚拟化应该没问题),解决 Windows FPU 问题。选择 x86 只是一个猜测,因为它很可能是原作者使用的。我不了解底层密码学,所以我不能说计算值的差异是否会影响安全性。 (另请注意,C 代码似乎无法正确播种其 PRNG。)

C long double in golang

标题表明对 Go 是否在 C 中有 extended precision floating-point type similar to long double 感兴趣。

答案是:


Why this is working?

long double s = some_calculation();
uint64_t a = s;

它可以编译,因为与 Go 不同,C 允许某些隐式类型转换。 s 的 floating-point 值的 整数部分 将被复制。据推测,s 值已按比例缩放,因此可以将其解释为 fixed-point value where, based on the linked library source, 0xFFFFFFFFFFFFFFFF (2^64-1) 表示值 1.0。为了充分利用此类分配,使用具有 64 个精度位的扩展 floating-point 类型可能是值得的。

如果非要我猜的话,我会说 (crypto-related) 库在这里使用 fixed-point 因为他们想确保确定性的结果,请参阅:How can floating point calculations be made deterministic?。由于 extended-precision 浮点数仅用于初始化查找 table,因此使用(可能很慢)math/big 库在这种情况下可能会表现得非常好。