数字系统中的浮点表示
Floating point representation in number system
我不知道如何解决这个问题,我知道浮点数的显式、隐式和 IEEE-754 规范化表示,但如何将其分解为小问题。请帮我想象一下。
让我们假设 IEEE-754 单精度浮点数。在这样的浮点数中,你有大约 7 位精度 - 之后你就进入了浮点荒野。
我是什么意思?好吧,假设我有一个数字 = 7654321。我可以将其转换为 32 位浮点值,然后我可以取回那个确切的数字。当数字变得比那个大时,我开始失去精度 - 即数字从浮点数的末尾掉落并丢失。
考虑以下几点:
#include <stdio.h>
int main(int argc, char *argv[])
{
float f1 = 7654321, f2 = 987654321;
printf("f1 = %f f2 = %f\n", f1, f2);
}
当我 运行 我得到
f1 = 7654321.000000 f2 = 987654336.000000
希望您看到后说:“说什么?!?!”。 f2
怎么了?
正如我所说,32 位浮点数只有大约 7 位(十进制)精度。如果您尝试将精度超过 7 位的数字放入 32 点浮点变量中,则会失去精度 - 低位数字会丢失。
那么让我们考虑一下您问题中的值:
A = 2.0 * 10^30
B = -2.0 * 10^30
C = 1.0
并且你应该在执行计算时弄清楚你得到什么
X = A + B
X = X + C
和
Y = A + C
Y = Y + B
好吧,让我们从第一个开始。代入我们得到的值
X = A + B = (2.0 * 10^30) + (-2.0 * 10^30)
幸运的话,X 现在将为零。那么我们有
X = X + C
所以,代入我们得到的值
X = 0.0 + 1.0
所以 X 应该以 1.0 结尾。
好的,这很有趣。下面再看看Y的计算,其实和X的计算是一样的,只是重新排列了一下:
Y = 2.0 * 10^30 + 1.0
这应该给我们结果 2.0 * 10^30
。嗯?为什么?!?好吧,2*10^30
超出了浮点数可能的精度(只能保留 7 位精度),因为它代表一个 30 位数字,因此将值 1.0
添加到 2*10^30 不改变它。所以此时Y = 2.0 * 10^30
。然后我们将 B = -2.0 * 10^30
添加到它,我们得到 - 是的,零。
所以你最终得到 X = 1.0,Y = 0.0 即使你在头脑中执行这些计算而不考虑计算机中浮点数的精度限制,你也会得到一个值两者均为 1.0.
此处的预期教训是,当您处理浮点值时,运算顺序非常重要,您必须仔细考虑您正在使用的值的大小以计划您的计算,以便你不会以数字糊状结束。
顺便说一句,这里有一个小程序可以实现你的任务:
#include <stdio.h>
#include <math.h>
int main(int argc, char *argv[])
{
float A = 2.0 * pow(10, 30), B = -2.0 * pow(10, 30), C = 1.0;
float X, Y;
X = A + B;
X = X + C;
Y = A + C;
Y = Y + B;
printf("X = %f Y = %f\n", X, Y);
}
运行 它并打印
X = 1.000000 Y = 0.000000
我不知道如何解决这个问题,我知道浮点数的显式、隐式和 IEEE-754 规范化表示,但如何将其分解为小问题。请帮我想象一下。
让我们假设 IEEE-754 单精度浮点数。在这样的浮点数中,你有大约 7 位精度 - 之后你就进入了浮点荒野。
我是什么意思?好吧,假设我有一个数字 = 7654321。我可以将其转换为 32 位浮点值,然后我可以取回那个确切的数字。当数字变得比那个大时,我开始失去精度 - 即数字从浮点数的末尾掉落并丢失。
考虑以下几点:
#include <stdio.h>
int main(int argc, char *argv[])
{
float f1 = 7654321, f2 = 987654321;
printf("f1 = %f f2 = %f\n", f1, f2);
}
当我 运行 我得到
f1 = 7654321.000000 f2 = 987654336.000000
希望您看到后说:“说什么?!?!”。 f2
怎么了?
正如我所说,32 位浮点数只有大约 7 位(十进制)精度。如果您尝试将精度超过 7 位的数字放入 32 点浮点变量中,则会失去精度 - 低位数字会丢失。
那么让我们考虑一下您问题中的值:
A = 2.0 * 10^30
B = -2.0 * 10^30
C = 1.0
并且你应该在执行计算时弄清楚你得到什么
X = A + B
X = X + C
和
Y = A + C
Y = Y + B
好吧,让我们从第一个开始。代入我们得到的值
X = A + B = (2.0 * 10^30) + (-2.0 * 10^30)
幸运的话,X 现在将为零。那么我们有
X = X + C
所以,代入我们得到的值
X = 0.0 + 1.0
所以 X 应该以 1.0 结尾。
好的,这很有趣。下面再看看Y的计算,其实和X的计算是一样的,只是重新排列了一下:
Y = 2.0 * 10^30 + 1.0
这应该给我们结果 2.0 * 10^30
。嗯?为什么?!?好吧,2*10^30
超出了浮点数可能的精度(只能保留 7 位精度),因为它代表一个 30 位数字,因此将值 1.0
添加到 2*10^30 不改变它。所以此时Y = 2.0 * 10^30
。然后我们将 B = -2.0 * 10^30
添加到它,我们得到 - 是的,零。
所以你最终得到 X = 1.0,Y = 0.0 即使你在头脑中执行这些计算而不考虑计算机中浮点数的精度限制,你也会得到一个值两者均为 1.0.
此处的预期教训是,当您处理浮点值时,运算顺序非常重要,您必须仔细考虑您正在使用的值的大小以计划您的计算,以便你不会以数字糊状结束。
顺便说一句,这里有一个小程序可以实现你的任务:
#include <stdio.h>
#include <math.h>
int main(int argc, char *argv[])
{
float A = 2.0 * pow(10, 30), B = -2.0 * pow(10, 30), C = 1.0;
float X, Y;
X = A + B;
X = X + C;
Y = A + C;
Y = Y + B;
printf("X = %f Y = %f\n", X, Y);
}
运行 它并打印
X = 1.000000 Y = 0.000000