首页 > 解决方案 > 网格步长(两个相邻机器可表示数字之间的差异

问题描述

我写了这样一个代码来查找网格步长(两个相邻的机器可表示数字之间的差异,机器 epsilon 是大于 1 和 1 的最小机器可表示数字之间的差异)。为什么这个程序对于 x 的巨大值显示 1 以及如何修复它以显示正确答案?

#include <stdio.h>
int main(void)
{
    long double x,eps=1.0,a; 
    scanf("%Lg",&x);
    do
    {
        a=eps;
        eps/=2.0;
    }
    while( x+eps>x);
    printf("Grid step: %Le",(long double)a);
    return 0;
}

标签: floating-pointieee-754

解决方案


浮点数表示为符号(+1 或 -1)s、指数e和具有固定基数(称为有效数)的固定位数的数字f 。b为底,精度(位数)p,用符号s、指数e和数字f 0f -1f -2f -3f -4、… f 1−<em>表示的数字ps •<em>b e •sum( f i •<em>bi为 -<em>p < i ≤ 0)。

例如,底数为 2、精度为 4、符号 +1、指数 1 和有效位数 1.001,表示的数字为 +1•2 1 •1.001 2 = 2•1⅛ = 2¼ = 9/4 = 2.25。

给定范围内的任何可表示数,通过将有效数的最低位加 1 来获得下一个更大的可表示数。在上面的例子中,下一个更大的数的有效数为 1.010,并且具有相同的符号和指数,因此它将是 +1•2 1 •1.010 2 = 2•1¼ = 2½ = 10/4 = 2.5。

这意味着,如果一个数x用指数e表示,那么它与下一个更大的可表示数之间的差是b e •<em>b 1−<em>p = b e +1−<em>p

数字 1 用指数 0 表示,因为 1 = +1•<em>b 0 •1.000…000 b。所以 1 和下一个可表示的数字之间的差是b 1−<em>p。如果您的long double格式的底数为 2,精度为 64 位(位),则此差异为 2 1−64 = 2 −63,因此所谓的“机器 epsilon”的值应为 2 −63

如果使用二进制格式,则 2 用指数 1 表示,因此它与下一个可表示数字之间的差是b e +1−<em>p = 2 1+1−64 = 2 −62。这些差异称为 ULP,即最低精度单位。

4 的 ULP 为 2 -61,8 的 ULP 为 2 -60,依此类推。对于 2 63,ULP 为 2 63−63 = 1。

当您输入 2 64或更大的数字时,您的程序无法找到 ULP,因为 ULP 大于 1,但您的程序开始查找 1 并向下工作。

您可以通过从long double格式中可能最大的 ULP 开始或通过将程序更改为向上或向下工作来修复它,具体取决于x.


推荐阅读