计算浮点精度(K&R 2-1)
Computing floating point accuracy (K&R 2-1)
我发现 Stevens Computing Services – K & R Exercise 2-1 对 K&R 2-1 的一个非常详尽的回答。这段完整代码计算 C 编程语言中 float
类型的最大值。
不幸的是,我对 float
值的理论理解非常有限。我知道它们由有效数(尾数..)和一个 2 的幂组成。
#include <stdio.h>
#include <limits.h>
#include <float.h>
main()
{
float flt_a, flt_b, flt_c, flt_r;
/* FLOAT */
printf("\nFLOAT MAX\n");
printf("<limits.h> %E ", FLT_MAX);
flt_a = 2.0;
flt_b = 1.0;
while (flt_a != flt_b) {
flt_m = flt_b; /* MAX POWER OF 2 IN MANTISSA */
flt_a = flt_b = flt_b * 2.0;
flt_a = flt_a + 1.0;
}
flt_m = flt_m + (flt_m - 1); /* MAX VALUE OF MANTISSA */
flt_a = flt_b = flt_c = flt_m;
while (flt_b == flt_c) {
flt_c = flt_a;
flt_a = flt_a * 2.0;
flt_b = flt_a / 2.0;
}
printf("COMPUTED %E\n", flt_c);
}
我知道后半部分基本上是检查可以使用三变量算法将有效数提高到 2 的哪个次方。第一部分呢?
我可以看到 2 的倍数的级数最终应该确定尾数的值,但我试图追踪一些小数字来检查它应该如何工作但未能找到正确的值...
============================================= =========================
这个程序基于什么概念?随着必须找到更长的非整数,这个程序是否变得更精确?
第一个循环通过找到最小的 2 次幂来确定对有效数字有贡献的位数,使得向其加 1(使用浮点运算)无法更改其值。如果这是 2 的 n
次方,则有效数使用 n
位,因为使用 n
位可以表示从 0 到 2^n
- 1 的所有整数,但不是 2^n
。因此,2^n
的浮点表示必须具有足够大的指数,以使(二进制)单位数字不重要。
出于同样的原因,找到 2 的第一个幂,其 float
表示比单位精度差, 做 的最大 float
值单位精度少一。 那个值记录在变量flt_m
.
第二个循环然后通过从最大单位精度值开始并重复将其加倍(从而使指数增加 1)来测试最大指数,直到发现无法通过减半将结果转换回来。最大值 float
是最终加倍之前的值。
请注意,顺便说一句,以上所有内容都假定为 base-2 浮点表示。您不太可能 运行 任何不同的东西,但 C 实际上 不需要 任何特定的表示。
关于你问题的第二部分,
does this program gets more precise as longer and non-integer numbers have to be found?
程序会注意避免丢失精度。它确实采用了如您所描述的二进制浮点表示形式,但无论这种表示形式的有效位数或指数中的位数如何,它都能正常工作。不涉及非整数,但该程序已经处理了比单位精度更差的数字,并且数字大于可以用类型 int
.
表示的数字
我发现 Stevens Computing Services – K & R Exercise 2-1 对 K&R 2-1 的一个非常详尽的回答。这段完整代码计算 C 编程语言中 float
类型的最大值。
不幸的是,我对 float
值的理论理解非常有限。我知道它们由有效数(尾数..)和一个 2 的幂组成。
#include <stdio.h>
#include <limits.h>
#include <float.h>
main()
{
float flt_a, flt_b, flt_c, flt_r;
/* FLOAT */
printf("\nFLOAT MAX\n");
printf("<limits.h> %E ", FLT_MAX);
flt_a = 2.0;
flt_b = 1.0;
while (flt_a != flt_b) {
flt_m = flt_b; /* MAX POWER OF 2 IN MANTISSA */
flt_a = flt_b = flt_b * 2.0;
flt_a = flt_a + 1.0;
}
flt_m = flt_m + (flt_m - 1); /* MAX VALUE OF MANTISSA */
flt_a = flt_b = flt_c = flt_m;
while (flt_b == flt_c) {
flt_c = flt_a;
flt_a = flt_a * 2.0;
flt_b = flt_a / 2.0;
}
printf("COMPUTED %E\n", flt_c);
}
我知道后半部分基本上是检查可以使用三变量算法将有效数提高到 2 的哪个次方。第一部分呢?
我可以看到 2 的倍数的级数最终应该确定尾数的值,但我试图追踪一些小数字来检查它应该如何工作但未能找到正确的值...
============================================= =========================
这个程序基于什么概念?随着必须找到更长的非整数,这个程序是否变得更精确?
第一个循环通过找到最小的 2 次幂来确定对有效数字有贡献的位数,使得向其加 1(使用浮点运算)无法更改其值。如果这是 2 的 n
次方,则有效数使用 n
位,因为使用 n
位可以表示从 0 到 2^n
- 1 的所有整数,但不是 2^n
。因此,2^n
的浮点表示必须具有足够大的指数,以使(二进制)单位数字不重要。
出于同样的原因,找到 2 的第一个幂,其 float
表示比单位精度差, 做 的最大 float
值单位精度少一。 那个值记录在变量flt_m
.
第二个循环然后通过从最大单位精度值开始并重复将其加倍(从而使指数增加 1)来测试最大指数,直到发现无法通过减半将结果转换回来。最大值 float
是最终加倍之前的值。
请注意,顺便说一句,以上所有内容都假定为 base-2 浮点表示。您不太可能 运行 任何不同的东西,但 C 实际上 不需要 任何特定的表示。
关于你问题的第二部分,
does this program gets more precise as longer and non-integer numbers have to be found?
程序会注意避免丢失精度。它确实采用了如您所描述的二进制浮点表示形式,但无论这种表示形式的有效位数或指数中的位数如何,它都能正常工作。不涉及非整数,但该程序已经处理了比单位精度更差的数字,并且数字大于可以用类型 int
.