2

我有一个无法更改语法的函数,比如说这是我正在调用的一些库函数:

void schedule(double _val);

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

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

我打算做的是,如果该值大于双精度可以容纳的最大值,我需要循环剩余的值,以便最终得出正确的值。

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

我需要从变量“值”中提取 X 和 Y。如何实现?我的目标不是因为类型铸造而降低精度。

4

2 回答 2

2

如果您的问题只是在 中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被调用的参数为零,我们尚未确定这是允许的。如果这是一个问题,则应跳过此类呼叫。

于 2013-04-01T19:14:25.940 回答
0

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

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.

于 2013-04-01T19:04:14.927 回答