拆分64位值以适应双精度参数类型

spliting 64 bit value to fit in argument type of double

本文关键字:双精度 参数 类型 64位 拆分      更新时间:2023-10-16

我有一个函数,我不能改变语法,说这是一些库函数,我正在调用:

void schedule(double _val);
void caller() {
   uint64_t value = 0xFFFFFFFFFFFFFFF;
   schedule(value);
}

作为函数调度接受double作为实参类型,在实参值大于52位的情况下(考虑到double将尾数存储为52位值),在这种情况下我将失去精度。

我要做的是,如果该值大于双精度体所能容纳的最大值,我需要循环获取剩余的值,以便最终求和得到正确的值。

    void caller() {
       uint64_t value = 0xFFFFFFFFFFFFFFF;
       for(count = 0; count < X ; count++) {
           schedule(Y);
       }
    }

我需要从变量"值"中提取X和Y。如何才能做到这一点?我的目标是不要因为类型转换而失去精度。

如果您的问题只是在caller而不是schedule中失去精度,则不需要循环:

void caller() {
    uint64_t value = 0xFFFFFFFFFFFFFFF;
    uint64_t modulus = (uint64_t) 1 << 53;
    schedule(value - value % modulus);
    schedule(value % modulus)
}

value - value % modulus中,只有高11位是有效的,因为低53位已经被清除。因此,当转换为double时,没有错误,并且将准确的值传递给schedule。同样地,value % modulus只有53位,并且完全转换为双精度。

(IEEE-754 64位二进制浮点对象的有效位数编码为52位,但由于隐式前导位,实际有效位数为53位)

注意:上面的操作可能会导致调用schedule时带一个参数为0,我们还没有确定是否允许。如果这是一个问题,那么应该跳过这样的调用。

如果Ndouble可以精确表示的最大积分值,那么显然可以使用

Y = N

X = amount / Y

(假设整除)。一旦你完成了对X的迭代,你仍然需要调度剩余的

R = amount % Y

请记住,所有的整型计算都必须在uint64_t类型的域中执行,也就是说,你必须为常量(ULULL)添加适当的后缀,或者使用类型强制转换到uint64_t,或者使用uint64_t类型的中间变量。

当然,如果你的程序并不关心schedule被调用了多少次,只要总数是正确的,那么你可以为N使用任何值,只要它能被精确地表示。例如,您可以简单地设置N = 10000

另一方面,如果你想最小化schedule调用的次数,那么值得注意的是,由于"隐式1"规则,可以用52位尾数精确表示的最大整数是(1 << 53) - 1