【问题标题】:How to find the multiplier that produces a smaller output for every double values?如何找到为每个双精度值产生较小输出的乘数?
【发布时间】:2018-08-22 15:55:46
【问题描述】:

您如何找到最大和正的 IEEE-754 二进制 64 值 C,使得正的标准化二进制 64 值 AC 的每个 IEEE-754 乘积都小于 A ?

我知道它一定接近 0.999999...但我想找到最大的那个。

假设从四舍五入到最近,与偶数相关。

【问题讨论】:

  • 尾数位的二进制搜索怎么样?
  • 对于特定平台上的特定号码或一般最接近的号码,这是动态的。如果是后者,那么它将是 0 的符号,除第一位和最后一位之外的所有 1 的指数,以及所有 1 的尾数。
  • C11 标准的第 5.2.4.2.2 节有一个关于浮点类型属性的信息日志。也许其中的一些组合会有所帮助?
  • 根据舍入模式,它可能高达 1-DBL_EPSILON,如果您不假设 IEEE-754,那么它实际上可以是任何东西。您是否愿意假设“标准”浮点系统 (IEEE-754) 和“标准”舍入模式(舍入到最接近,与偶数相关)?
  • 对了,我没有具体说明,需要添加到帖子中。

标签: algorithm floating-point double multiplication ieee-754


【解决方案1】:

有几种实验方法;这是C = 1 - ε的证明,其中ε是机器ε(即1与大于1的最小可表示数之间的距离。)

我们当然知道C < 1,所以尝试C = 1 - ε/2 是有意义的,因为它是下一个小于1 的可表示数字。 (ε/2 是因为C 在可表示数字的[0.5, 1) 桶中。)让我们看看它是否适用于所有A

我将在本段中假设1 <= A < 2。如果AAC 都在“正常”区域,那么指数是多少并不重要,情况与指数2^0 相同。现在,C 的选择显然适用于A=1,所以我们只剩下区域1 < A < 2。查看A = 1 + ε,我们看到AC(精确值,不是四舍五入的结果)已经大于1;而对于A = 2 - ε,我们看到它小于2。这很重要,因为如果AC 介于1 和2 之间,我们知道ACround(AC) 之间的距离(即四舍五入到最接近的可表示值)最多为ε/2。现在,如果A - AC < ε/2,那么我们想要的round(AC) = A。 (如果 A - AC = ε/2可能 舍入到 A 给定正常 FP 舍入规则的“与偶数”部分,但让我们看看我们是否可以做得更好。)因为我们选择了C = 1 - ε/2,我们可以看到A - AC = A - A(1 - ε/2) = A * ε/2。因为它大于ε/2(记住,A>1),所以它距离A 足够远,可以舍入它。

但是!我们必须检查的A 的另一个值是可表示的最小正常值,因为AC 不在正常范围内,因此我们的“到最近的相对距离”规则不申请。我们发现,在这种情况下,A-AC 正好是该地区机器 epsilon 的一半。 “四舍五入到最近,平局”开始,产品四舍五入回到等于A。德拉特。

C = 1 - ε 进行同样的处理,我们看到round(AC) < A,并且没有其他任何东西接近于向A 进行四舍五入(我们最终询问是否A * ε > ε/2,当然是哪个)。所以妙语是C = 1-ε/2几乎有效,但法线和非法线之间的界限把我们搞砸了,C = 1-ε 让我们进入了终点区。

【讨论】:

  • 非常感谢,我现在 100% 相信了。
【解决方案2】:

由于浮点类型的性质,C 会根据 A 的值大小而有所不同。您可以使用nextafter 获得小于1 的最大值,这将是C 的粗略值

但是,如果 A 太大或太小,A*C 将与 A 相同。我无法从数学上证明 nextafter(1.0, 0) 将适用于所有可能的 A,因此我'我建议这样的解决方案

double largestCfor(double A)
{
    double C = nextafter(1.0, 0);
    while (C*A >= A)
        C = nextafter(C, 0);
    return C;
}

如果您想要一个适用于任何AC 值,即使C*A 可能不是最大的可能值,您也需要检查该类型可以表示的每个指数

double C = 1;
for (double A = 0x1p-1022; isfinite(A); A *= 2) // loop through all possible exponents
{
    double c = largestCfor(A);
    if (c < C) C = c;
}

我尝试在Ideone 上运行并得到了结果

C                 = 0.999999999999999777955395074969
nextafter(1.0, 0) = 0.999999999999999888977697537484

编辑:

0.999999999999999777955395074969 是0x1.ffffffffffffep-1,也是1 - DBL_EPSILON。这与上面 Sneftel 的证明一致

【讨论】:

  • 不是缺少任何 A 的外循环吗?
  • @Anonymous 没有。为什么你需要用 A 循环任何东西?它的值已经在函数中固定。第一行将计算 1.0 之前的值,如果仍然很大,它将减小该值,直到找到最大的合适 C
  • @phuclv 我认为他的意思是A 本身不是一个常数,因此您需要遍历A 的可能值。
  • @ChristianGibbons 那是不可能的。没有一个常量C 可以适用于所有As。每个 C 仅适用于一系列值
  • 我正在寻找所有 A 值的通用常数(几乎 2^63 个样本),“外循环”问题有点讽刺,我很抱歉 :)
猜你喜欢
  • 2017-02-05
  • 2013-02-11
  • 2021-08-22
  • 2018-02-17
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
相关资源
最近更新 更多