我正在对我开发的数学软件进行数值分析。我想确定结果的不确定性。由于f()
我的方法和x
输入值,我想将y
的结果标识为f(x) +/- y
。我的f()
方法在float
个变量之间有多个操作。为了研究f()
中发生的错误传播,我必须应用不确定性统计传播公式,为了做到这一点,我必须知道float
变量的不确定性
我理解IEEE 754标准中规定的float
变量的体系结构以及将后者固有的十进制值转换为float
的舍入误差。
根据我对文献的理解,http://www.cplusplus.com/reference/cfloat/中的FLT_EPSILON
宏
定义了我的y
值,但这个快速测试证明它是错误的:
float f1 = 1.234567f;
float f2 = 1.234567f + 1.192092896e-7f;
float f3 = 1.234567f + 1.192092895e-7f;
printf("Inicial:\t%f\n", f1);
printf("Inicial:\t%f\n", f2);
printf("Inicial:\t%f\n\n", f3);
输出:
Inicial: 1.234567
Inicial: 1.234567
Inicial: 1.234567
当预期输出应为:
Inicial: 1.234567
Inicial: 1.234568 <---
Inicial: 1.234567
我错了什么?
float
和x + FLT_EPSILON
的{{1}}值不应该相同吗?
编辑:我的问题是x - FLT_EPSILON
R
float
值x
y
值x + y || x - y
等于R
float
} EventData
值?
答案 0 :(得分:2)
Propagation of uncertainty来自统计领域,指的是输入中的不确定性如何影响它们的数学函数。对计算算术中发生的错误的分析是numerical analysis。
FLT_EPSILON
不是衡量浮点结果的不确定性或误差的指标。它是1和下一个float
类型中可表示的值之间的距离。因此,它是大小为1的可表示数字之间的步长。
当您将十进制数字转换为浮点数时,在使用公共舍入到最近模式时,得到的舍入误差的幅度可能高达步长的1/2。边界大小为1/2步长的原因是对于任何数字 x (在浮点格式的有限域内),在步长(包括)的1/2内存在可表示的值。这是因为,如果在一个方向上存在大于1/2步长的可表示数字,则在另一个方向上存在小于1/2步长的可表示数字。
步长随数字的大小而变化。使用二进制浮点,它在2处加倍,在4处加倍,然后是8,依此类推。低于1,它减半,再次在½,¼等等。
执行浮点算术运算时,计算中发生的舍入可能会复合或取消先前的错误。最终错误没有通用公式。
您的示例代码1.192092897e-7f
和1.192092896e-7f
中使用的两个数字非常接近,它们会转换为相同的float
值,2 -23 。这就是为什么您的f2
和f3
没有区别。
f1
和f2
之间存在差异,但您没有打印足够的数字来显示它。
您问“float
和x + FLT_EPSILON
的{{1}}值是否应该相同?”,但您的代码不包含x - FLT_EPSILON
。
回复:“我的问题是x - FLT_EPSILON
R
的浮动值,x
||的y
值是多少? x + y
等于相同的x - y
浮点值?“R
= 0很容易满足这个问题。你的意思是问y
满足条件的最大值是多少?这有点复杂。
数字 x 的步长称为 x 的ULP,我们可以将其视为函数ULP( x )。 ULP代表最低精度单位。它是 x 的浮点表示中最小数字的位置值。它不是一个常数;它是 x 的函数。
对于以浮点格式表示的大多数值,满足条件的最大y
是½ULP( x )的浮点表示中的最小数字< em> x 是偶数,如果数字是奇数,则它刚好低于½ULP( x )。这种复杂性源于这样的规则:算术结果四舍五入到最接近的可表示值,并且在平行的情况下,选择具有偶数低位的值。因此,如果低位数是偶数,那么将½ULP( x )添加到 x 将产生一个平局为 x 的平局,但不会如果低位是奇数,则舍入到 x 。
但是,对于位于ULP更改边界的 x ,满足条件的最大y
为¼ULP( x )。这是因为,在 x (大小)下方,步长会发生变化,而下一个 x 的数字是 x 的一半s步长而不是通常的全步长。因此,在更改减法结果之前,您只能走向该值的一半,因此y
最多可以是¼ULP( x )。
答案 1 :(得分:1)
float f1 = 1.234567f;
float f2 = f1 + 1.192092897e-7f;
float f3 = f1 + 1.192092896e-7f;
printf("Inicial:\t%.20f\n", f1);
printf("Inicial:\t%.20f\n", f2);
printf("Inicial:\t%.20f\n\n", f3);
<强>输出:强>
Inicial: 1.23456704616546630000
Inicial: 1.23456716537475590000
Inicial: 1.23456716537475590000
否,您的期望是错误的
在第一次printf
调用中,您将打印变量 f1 而不会产生1.234567f
的影响。
答案 2 :(得分:1)
Float是32
位IEEE 754单精度浮点数:符号为1
位,指数为8
位,值为23
* ,即float具有7
精度的十进制数字。
增加printf
个已打印的数字以查看更多但在7
个数字后只是噪音:
#include <stdio.h>
int main(void) {
float f1 = 1.234567f;
float f2 = 1.234567f + 1.192092897e-7f;
float f3 = 1.234567f + 1.192092896e-7f;
printf("Inicial:\t%.16f\n", f1);
printf("Inicial:\t%.16f\n", f2);
printf("Inicial:\t%.16f\n\n", f3);
return 0;
}
输出:
Inicial: 1.2345670461654663
Inicial: 1.2345671653747559
Inicial: 1.2345671653747559