[英]How to write this floating point code in a portable way?
我正在研究一种加密货币,并且节点必须进行计算:
average /= total;
double ratio = average/DESIRED_BLOCK_TIME_SEC;
int delta = -round(log2(ratio));
无论系统使用什么架构或标准库,都要求每个节点都具有完全相同的结果。 我的理解是 log2 可能有不同的实现,产生的结果略有不同,或者 --ffast-math 之类的标志可能会影响输出结果。
有没有一种简单的方法可以将上述计算转换为可在不同架构中可移植的东西(固定点?),或者我是否过度考虑了所需的精度(假设我最后将答案四舍五入)。
要使这种计算准确,必须要么精确计算所有除法和对数,要么可以倒推。
-round(log2(x)) == round(log2(1/x))
,这意味着可以将其中一个除法翻转以获得 (1/x) >= 1。
round(log2(x)) == floor(log2(x * sqrt(2))) == binary_log((int)(x*sqrt(2)))
。
这里的一个小细节是,如果(double)sqrt(2)
向下或向上舍入。 如果四舍五入,则可能存在一个或多个值x * sqrt2 == 2^n + epsilon
(四舍五入后),如果它向下舍入,我们将得到2^n - epsilon
。 一个会给出n
的 integer 值,另一个会给出n-1
。 哪个是对的?
自然是正确的,它与理论中点x * sqrt(2)
的比值更小。
x * sqrt(2) / 2^(n-1) < 2^n / (x * sqrt(2))
-- 乘以 x*sqrt(2)x^2 * 2 / 2^(n-1) < 2^n
-- 乘以 2^(n-1)x^2 * 2 < 2^(2*n-1)
为了使这种比较准确, x^2 or pow(x,2)
在边界上也必须准确——重要的是,原始值的范围是多少。 在扩展x = a/b
时可以并且应该进行类似的分析,以便可以以乘法中可能的溢出为代价来减轻除法的不精确性......
再说一次,我想知道所有其他类似的应用程序如何处理甚至可能不存在的极端情况——假设average
和total
是足够小的整数,这些情况可能会被蛮力搜索。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.