浮点值 0.0 的表示方式是否与其他浮点值不同?
Is a floating-point value of 0.0 represented differently from other floating-point values?
我一直在翻阅我的 C++ 书籍,我遇到了一个声明,它说零可以精确地表示为浮点数。我想知道这怎么可能,除非 0.0 的值存储为浮点值以外的类型。我写了下面的代码来测试这个:
#include <iomanip>
#include <iostream>
int main()
{
float value1 {0.0};
float value2 {0.1};
std::cout << std::setprecision(10) << std::fixed;
std::cout << value1 << '\n'
<< value2 << std::endl;
}
运行 此代码给出了以下输出:
0.0000000000
0.1000000015
到10位精度,0.0还是0,0.1有一些不准确(这是意料之中的)。值 0.0 在表示方式上是否与其他浮点数不同,这是编译器或计算机体系结构的特性吗?
2如何表示为一个精确的数字? 4? 15? 0.5?答案只是有些数字可以精确地用浮点格式表示(基于base-2/binary),而有些则不能。
这与十进制没有区别。你不能用十进制表示 1/3,但这并不意味着你不能表示 0.
零在某种程度上是特殊的,因为(像其他实数一样)证明这个 属性 比一些任意小数更简单。但仅此而已。
所以:
what is it about these values (0, 1/16, 1/2048, ...) that allows them to be represented exactly.
简单的数学。在任何给定的基数中,在我们正在讨论的表示形式中,一些数字可以用固定的小数位数写出;其他人不能。就是这样。
您可以在线玩 H. Schmidt's IEEE-754 Floating Point Converter 不同的数字,以查看一堆不同的表示形式,以及编码到这些表示形式中会出现哪些错误。对于初学者,请尝试 0.5、0.2 和 0.1。
It was my (perhaps naive) understanding that all floating point values contained some instability.
不,绝对不是。
您希望将程序中的每个浮点值视为可能存在一些小错误,因为您通常不知道 是什么计算顺序导致的。你不能相信它,一般来说。我希望过去有人把这个教给你一半,这就是导致你误解的原因。
但是,如果您确实知道在创建值(例如"all I've done is initialised it to zero")的每个步骤中涉及的错误(或缺少错误),那很好!那就不用担心了。
这是一种看待这种情况的方法:用 64 位来存储一个数字,有 2^64
位模式。其中一些是 "not-a-number" 表示,但大多数 2^64
模式表示数字。表示的数字是准确表示的,没有错误。在了解 floating point math 之后,这可能看起来很奇怪;一个警告潜伏在前方。
但是,有2^64
那么大,实数还有无穷多。当计算产生非整数结果时,答案很可能不是由 2^64
模式之一表示的数字。也有例外。例如,1/2
由其中一种模式表示。如果将 0.5
存储在浮点变量中,它实际上将存储 0.5
。让我们试试其他个位数的分母。 (注:我写分数是为了表现力,不是整数运算。)
1/1
– 正好存储
1/2
– 正好存储
1/3
– 未准确存储
1/4
– 正好存储
1/5
– 未准确存储
1/6
– 未准确存储
1/7
– 未准确存储
1/8
– 正好存储
1/9
– 未准确存储
因此,对于这些简单的示例,超过一半的示例并未准确存储。当您进行更复杂的计算时,任何一项计算都会让您脱离精确表示的孤岛。您明白为什么一般的经验法则是浮点值不精确吗?很容易落入那个境界。避免它是可能的,但不要指望它。
有些数字可以用浮点值精确表示。大多数不能。
我一直在翻阅我的 C++ 书籍,我遇到了一个声明,它说零可以精确地表示为浮点数。我想知道这怎么可能,除非 0.0 的值存储为浮点值以外的类型。我写了下面的代码来测试这个:
#include <iomanip>
#include <iostream>
int main()
{
float value1 {0.0};
float value2 {0.1};
std::cout << std::setprecision(10) << std::fixed;
std::cout << value1 << '\n'
<< value2 << std::endl;
}
运行 此代码给出了以下输出:
0.0000000000
0.1000000015
到10位精度,0.0还是0,0.1有一些不准确(这是意料之中的)。值 0.0 在表示方式上是否与其他浮点数不同,这是编译器或计算机体系结构的特性吗?
2如何表示为一个精确的数字? 4? 15? 0.5?答案只是有些数字可以精确地用浮点格式表示(基于base-2/binary),而有些则不能。
这与十进制没有区别。你不能用十进制表示 1/3,但这并不意味着你不能表示 0.
零在某种程度上是特殊的,因为(像其他实数一样)证明这个 属性 比一些任意小数更简单。但仅此而已。
所以:
what is it about these values (0, 1/16, 1/2048, ...) that allows them to be represented exactly.
简单的数学。在任何给定的基数中,在我们正在讨论的表示形式中,一些数字可以用固定的小数位数写出;其他人不能。就是这样。
您可以在线玩 H. Schmidt's IEEE-754 Floating Point Converter 不同的数字,以查看一堆不同的表示形式,以及编码到这些表示形式中会出现哪些错误。对于初学者,请尝试 0.5、0.2 和 0.1。
It was my (perhaps naive) understanding that all floating point values contained some instability.
不,绝对不是。
您希望将程序中的每个浮点值视为可能存在一些小错误,因为您通常不知道 是什么计算顺序导致的。你不能相信它,一般来说。我希望过去有人把这个教给你一半,这就是导致你误解的原因。
但是,如果您确实知道在创建值(例如"all I've done is initialised it to zero")的每个步骤中涉及的错误(或缺少错误),那很好!那就不用担心了。
这是一种看待这种情况的方法:用 64 位来存储一个数字,有 2^64
位模式。其中一些是 "not-a-number" 表示,但大多数 2^64
模式表示数字。表示的数字是准确表示的,没有错误。在了解 floating point math 之后,这可能看起来很奇怪;一个警告潜伏在前方。
但是,有2^64
那么大,实数还有无穷多。当计算产生非整数结果时,答案很可能不是由 2^64
模式之一表示的数字。也有例外。例如,1/2
由其中一种模式表示。如果将 0.5
存储在浮点变量中,它实际上将存储 0.5
。让我们试试其他个位数的分母。 (注:我写分数是为了表现力,不是整数运算。)
1/1
– 正好存储1/2
– 正好存储1/3
– 未准确存储1/4
– 正好存储1/5
– 未准确存储1/6
– 未准确存储1/7
– 未准确存储1/8
– 正好存储1/9
– 未准确存储
因此,对于这些简单的示例,超过一半的示例并未准确存储。当您进行更复杂的计算时,任何一项计算都会让您脱离精确表示的孤岛。您明白为什么一般的经验法则是浮点值不精确吗?很容易落入那个境界。避免它是可能的,但不要指望它。
有些数字可以用浮点值精确表示。大多数不能。