我正在将算法从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代码,因为我正在为一个只包含uint64元素的数组赋一个long double。但C代码工作正常。
有人可以解释为什么这有效吗?
非常感谢。
更新:
可以在此处找到该函数的原始C代码:https://github.com/mjosaarinen/hilabliss/blob/master/distribution.c#L22
答案 0 :(得分:0)
作业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
仍然可以用于您的目的。
编辑在这种特殊情况下,源计算的值看起来是静态的,与输入无关。我只是在Go端使用float64
,看看计算值是否与C版本相同,当在真正的GNU / Linux下运行x86机器时(虚拟化应该没问题),可以解决Windows FPU问题。选择x86只是猜测,因为它可能是原作者使用的。我不了解底层加密,所以我不能说计算值的差异是否会影响安全性。 (另请注意,C代码似乎没有正确播种其PRNG。)
答案 1 :(得分:0)
golang中的C long double
标题暗示了对Go语言是否具有类似于C语言中的extended precision的long double
浮点类型的兴趣。
答案是:
这为什么起作用?
long double s = some_calculation();
uint64_t a = s;
之所以进行编译,是因为与Go不同,C允许某些隐式类型转换。 s
的浮点值的整数部分将被复制。假设s
值已经缩放,因此可以将其解释为fixed-point值,其中基于链接库源,0xFFFFFFFFFFFFFFFF
(2 ^ 64-1)表示值1.0 。为了充分利用此类分配,可能值得使用具有64个精度位的扩展浮点类型。
如果我不得不猜测,我会说(与密码相关的)库在这里使用定点,因为他们想要确保确定性的结果,请参阅:How can floating point calculations be made deterministic?。而且由于扩展精度浮点仅用于初始化查找表,因此在这种情况下使用(可能很慢)数学/大库可能会表现得很好。