floating-point - 网格步长(两个相邻机器可表示数字之间的差异
问题描述
我写了这样一个代码来查找网格步长(两个相邻的机器可表示数字之间的差异,机器 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;
}
解决方案
浮点数表示为符号(+1 或 -1)s、指数e和具有固定基数(称为有效数)的固定位数的数字f 。以b为底,精度(位数)p,用符号s、指数e和数字f 0、f -1、f -2、f -3、f -4、… f 1−<em>表示的数字p是s •<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
.
推荐阅读
- python - 将 MatLab 中的 max 函数转换为 numpy
- c# - 试图用两个数组组来洗牌
- layout - 如何在swiftUI控件中隐藏边框?
- javascript - 如何自定义 Feathersjs 的错误对象?
- javascript - Windows 10 下 node.js 文件无法编译错误 800A03EA
- javascript - 向现有的 Rest 服务添加新参数
- spring - SpringBoot 2.1.9 -> 2.2.0 - 健康端点不再工作
- spring - 检查启动后添加特定数据 - spring boot
- javascript - 这个 punycode 包含来自哪里?
- excel - 将文本从文本框复制到剪贴板的命令按钮不起作用