浮点数据类型的不确定性

时间:2018-03-23 16:29:32

标签: c floating-point precision epsilon

我正在对我开发的数学软件进行数值分析。我想确定结果的不确定性。由于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

我错了什么? floatx + FLT_EPSILON的{​​{1}}值不应该相同吗?

编辑:我的问题是x - FLT_EPSILON R floatx yx + y || x - y等于R float } EventData值?

3 个答案:

答案 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-7f1.192092896e-7f中使用的两个数字非常接近,它们会转换为相同的float值,2 -23 。这就是为什么您的f2f3没有区别。

f1f2之间存在差异,但您没有打印足够的数字来显示它。

您问“floatx + 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