无法理解长双精度数如何大于 2^80
Can't understand how a long double number can be greater than 2^80
所以我正在求解泰勒级数,它在这里:
这是代码:
#define _CRT_SECURE_NO_WARNINGS
#include<conio.h>
#include<stdio.h>
#include<math.h>
long double Fact(long double h) {
if (h <= 0) return 1;
else return h*Fact(h - 1);
}
void main(void) {
int p = 0;
long double s = 0, k = 0, c = 0, l = 0,d=0;
int n = 0, x = 0;
printf(" n ");
scanf("%d", &n);
printf(" x ");
scanf("%d", &x);
d = x;
while (n>=0) {
k = pow(-1, n);
c = (2 * n + 1);
l = Fact(c);
d = pow(x, 2 * n + 1);
s = s+ ((k / l)*d);
n = n - 1;
}
printf("Result : %.16LG\n", s);
_getch();
}
问题是:如果我输入 n = 16
和 x = 2,147,483,646
但它仍然写出正确的结果(我将程序的结果与沃尔夫拉姆阿尔法)
假设你说的是 2^80,因为你假设大小为 80 位的浮点数最多只能存储 280。您对浮点数的理解是错误的。与将数字编码为二进制数的无符号整数不同,浮点数的编码不同。
您可以在 wikipedia 上了解更多,但基本思想是浮点数编码为
sign * something * 2^something_else
这里的重要部分是 2^something_else
。对于 32 FP 数字 something_else
(指数)是 8 位长,因为一些特殊情况意味着对于普通数字它可以从 −126
到 +127
,对于 long double 假设它是 80 位x86 FP 它可以转到 16383:
让我们假设我决定发明我自己的数据类型,我称之为 bloat
(比如 float
,geddit?)。这种类型只有一个字节宽(8 位)并使用以下表示:位 #0(最低有效位)的权重为 40 = 1,位 #1 的权重41 = 4,位 #2 的权重为 42 = 16,位 #3 的权重为 43 = 64 依此类推。
bloat
中的位 00010001
的组合将代表 1 + 256 = 257
。 bloat
中可表示的最大值为 11111111
,即 21845
。所以,你是这样的:使用我新发明的 bloat
类型,我设法在仅 8 位内存中表示值 21845
。 21845
大于 214,但我设法将它压缩成 8 位!我是怎么做到的?
简单:为了 "stretch" 我的类型的明显范围,我牺牲了一些中间值。例如,我的 bloat
类型不能表示数字 2
。它不能表示数字 66
。等等。 21845
下有很多我的bloat
无法表示的值。如果你计算我的 bloat
can 代表的所有可能的不同值,你会发现正好有 256
个,即恰好 28 可以表示不同的值。
浮点类型,例如您的 long double
对 "stretch" 它们的范围采用几乎相同的原理。它们的内部格式和属性比我的bloat
更复杂,但基本思想是一样的:80位浮点类型的绝对范围比280大得多 因为它 "skips"(无法表示)该范围内的很多值。
它们内部表示的确切细节是 widely available on the Net。
x86 扩展精度格式(如果这是导致您引用 80 位的原因)有 63 个尾数位和 15 个指数位(偏差为 16383,保留值 32767)。
因此它可以表示的最大值非常接近 2 x 2^(32766-16383) ~ 1.189731 x 10^4932,比 2^80 大很多很多。
普通 IEEE 双精度的最大可表示数约为 1.79769 x 10^308。
所以我正在求解泰勒级数,它在这里:
这是代码:
#define _CRT_SECURE_NO_WARNINGS
#include<conio.h>
#include<stdio.h>
#include<math.h>
long double Fact(long double h) {
if (h <= 0) return 1;
else return h*Fact(h - 1);
}
void main(void) {
int p = 0;
long double s = 0, k = 0, c = 0, l = 0,d=0;
int n = 0, x = 0;
printf(" n ");
scanf("%d", &n);
printf(" x ");
scanf("%d", &x);
d = x;
while (n>=0) {
k = pow(-1, n);
c = (2 * n + 1);
l = Fact(c);
d = pow(x, 2 * n + 1);
s = s+ ((k / l)*d);
n = n - 1;
}
printf("Result : %.16LG\n", s);
_getch();
}
问题是:如果我输入 n = 16
和 x = 2,147,483,646
但它仍然写出正确的结果(我将程序的结果与沃尔夫拉姆阿尔法)
假设你说的是 2^80,因为你假设大小为 80 位的浮点数最多只能存储 280。您对浮点数的理解是错误的。与将数字编码为二进制数的无符号整数不同,浮点数的编码不同。
您可以在 wikipedia 上了解更多,但基本思想是浮点数编码为
sign * something * 2^something_else
这里的重要部分是 2^something_else
。对于 32 FP 数字 something_else
(指数)是 8 位长,因为一些特殊情况意味着对于普通数字它可以从 −126
到 +127
,对于 long double 假设它是 80 位x86 FP 它可以转到 16383:
让我们假设我决定发明我自己的数据类型,我称之为 bloat
(比如 float
,geddit?)。这种类型只有一个字节宽(8 位)并使用以下表示:位 #0(最低有效位)的权重为 40 = 1,位 #1 的权重41 = 4,位 #2 的权重为 42 = 16,位 #3 的权重为 43 = 64 依此类推。
bloat
中的位 00010001
的组合将代表 1 + 256 = 257
。 bloat
中可表示的最大值为 11111111
,即 21845
。所以,你是这样的:使用我新发明的 bloat
类型,我设法在仅 8 位内存中表示值 21845
。 21845
大于 214,但我设法将它压缩成 8 位!我是怎么做到的?
简单:为了 "stretch" 我的类型的明显范围,我牺牲了一些中间值。例如,我的 bloat
类型不能表示数字 2
。它不能表示数字 66
。等等。 21845
下有很多我的bloat
无法表示的值。如果你计算我的 bloat
can 代表的所有可能的不同值,你会发现正好有 256
个,即恰好 28 可以表示不同的值。
浮点类型,例如您的 long double
对 "stretch" 它们的范围采用几乎相同的原理。它们的内部格式和属性比我的bloat
更复杂,但基本思想是一样的:80位浮点类型的绝对范围比280大得多 因为它 "skips"(无法表示)该范围内的很多值。
它们内部表示的确切细节是 widely available on the Net。
x86 扩展精度格式(如果这是导致您引用 80 位的原因)有 63 个尾数位和 15 个指数位(偏差为 16383,保留值 32767)。
因此它可以表示的最大值非常接近 2 x 2^(32766-16383) ~ 1.189731 x 10^4932,比 2^80 大很多很多。
普通 IEEE 双精度的最大可表示数约为 1.79769 x 10^308。