我在理解浮点型的精度方面有问题。msdn将该精度从6位写入到9位。但我注意到,精度取决于数字的大小:
float smallNumber = 1.0000001f;
Console.WriteLine(smallNumber); // 1.0000001
bigNumber = 100000001f;
Console.WriteLine(bigNumber); // 100000000
小数比大数更精确,我理解IEEE754,但我不明白MSDN是如何计算精度的,它有意义吗?
此外,您还可以在这里使用浮点格式的数字表示。请在“您输入的”输入中写入100000000值,然后单击右侧的“1”。然后将输入值更改为1,然后再次单击“1”。你可以看到精度上的差异。
我想他们在留档中的意思是,根据数字的精确度从小数点后6位到9位不等。按照你链接的页面上解释的标准,有时微软在留档方面有点懒,就像我们其他人一样。浮点数的问题是它不准确。如果你把1.05这个数字放在链接中的网站上,你会注意到它不能准确地存储在浮点数中。它实际上是作为1.0499999523162841796875存储的。这样存储可以更快地进行计算。这对金钱来说不是很好,例如,如果你的商品定价为1.05美元,而你卖出了10亿美元,那该怎么办?
是的,舍入误差前的位数是精度的衡量标准,但不能仅从两个数字来评估精度,因为您可能离舍入阈值更近或更远。
为了更好地理解这种情况,您需要了解浮动是如何表示的。
IEEE754 32位浮点数存储为:
bool(1bit sign) * integer(24bit mantisa) << integer(8bit exponent)
是的,尾数是24位而不是23位,因为它的MSB隐式设置为1。
正如你所看到的,只有整数和位移位。所以如果你代表的是2^24以下的自然数,你就没有完全舍入。对于更大的数字,二进制零填充从右边出现,导致了差异。
如果是小数点后的数字,则从左侧开始填充零。但另一个问题是,在二进制中,你不能准确地存储一些十进制数。例如:
0.3 dec = 0.100110011001100110011001100110011001100... bin
0.25 dec = 0.01 bin
正如你所看到的那样,二进制中的0.3 dec
序列是无限的(就像我们不能用decadic写1/3),因此,如果只将其裁剪为24位,则会丢失其余的部分,并且数字不再是你想要的。
如果将0.3
和0.125
进行比较,0.125是精确的,0.3不是,但0.125比0.3
小得多。所以你的度量是不正确的,除非你探索了更接近的值,这些值将涵盖舍入步骤,并计算出这些集合的最大差异。例如,你可以比较
1.0000001f
1.0000002f
1.0000003f
1.0000004f
1.0000005f
1.0000006f
1.0000007f
1.0000008f
1.0000009f
记住fabs(x-round(x))
的最大差异,然后对
100000001
100000002
100000003
100000004
100000005
100000006
100000007
100000008
100000009
然后比较这两个差异。
除此之外,你还错过了一件非常重要的事情。这就是从文本转换成二进制和二进制时的错误,通常更大。首先,试着在不舍入的情况下打印数字(例如,强制在小数点后打印20位小数)。
此外,数字存储在二进制中,所以为了打印它们,你需要将其转换为十进制,包括乘法和除法10。数字中缺少的位越多(零位),打印错误就越大。为了尽可能精确,我们使用了一个技巧,即用十六进制打印数字(无舍入错误),然后根据整数数学将十六进制字符串本身转换为十进制。这比单纯的浮点打印准确得多。有关更多信息,请参阅相关QA:
现在回到浮点数表示的“精确”位数。对于数字的整数部分就这么简单:
dec_digits = floor(log10(2^24)) = floor(7.22) = 7
然而,对于小数点后的数字来说,这并不像许多四舍五入那样精确(对于前几个十位数字)。有关更多信息,请参阅:
MSDN留档是荒谬和错误的。
糟糕的概念。二进制浮点格式在十进制数字中没有任何精度,因为它根本没有十进制数字。它表示带符号的数字、固定数量的二进制数字(位)和2的幂的指数。
高端的错误。浮点格式精确地表示许多数字,精度无限。例如,“3”是精确表示的。你可以写任意远的小数,3.0000000000…,所有的小数位数都是正确的。另一个例子是1.40129846432481709237295832899161312802619418765157717570682838897991082685860601486638188362158203125•10−45。这个数字在十进制中有105个有效数字,但float
格式正好代表它(它是2−149)。
低端错误。当“999999.97”从十进制转换为浮点数
时,结果是1,000,000。所以甚至没有一个十进制数字是正确的。
不是精确度的度量。因为浮点数
意义有24位,所以其最低位的分辨率比最高位的分辨率高223倍。这大约是6.9位,因为log10223大约是6.9位。但这只是告诉我们表示的分辨率——粗略度。当我们将一个数字转换为浮点数
格式时,我们得到的结果与该分辨率的数字最多相差1/2,因为我们四舍五入到最接近的可表示值。因此,转换为浮点数
的相对误差最多为224中的1部分,在上述意义上相当于大约7.2位数。如果我们使用数字来测量分辨率,那么我们说分辨率大约是7.2位数,而不是6-9位数。
这些数字来自哪里?
所以,如果“~6-9位”不是一个正确的概念,不是来自数字的实际界限,也不是测量精度,那么它来自哪里?我们不能确定,但是6和9确实出现在float
格式的两个描述中。
6是保证的最大数字x:
float
格式的正常指数范围内,并被转换为该格式中表示的最接近的值,那么,当结果被转换为最多有x个有效位的最接近的十进制数字时,转换的结果等于原始数字
因此,可以合理地说浮点数
至少可以保留六个十进制数字。然而,正如我们将看到的,没有涉及九个数字的约束。
9是保证这一点的最小数字x:
浮点数
被转换为具有x个数字的最接近的十进制数,那么,当结果被转换为浮点数
中表示的最接近的值时,转换的结果等于原始数。作为类比,如果float
是一个容器,那么保证容纳它的最大“十进制容器”是六位数字,保证容纳它的最小“十进制容器”是九位数字。6和9类似于浮子
容器的内部和外部测量。
假设你有一块7.2个单元长的积木,你正在看它在每1个单元长的砖块上的位置。如果你把积木的开始放在一块砖块的开始,它会延伸出7.2块砖块。然而,其他人选择它的开始,他们可能会从一块砖块的中间开始。然后它会覆盖那块砖块的一部分,接下来的6块,以及最后一块砖块的一部分(例如。5 6 .7 = 7.2)。所以一个7.2个单元的积木只能保证覆盖6块砖块。相反,如果你选择它们的位置,8块砖块可以覆盖7.2个单元的积木。但是如果其他人选择从哪里开始,第一个可能只覆盖0.1个单位的块。然后你需要7个更多的部分,所以需要9块砖块。
这个类比成立的原因是2的幂和10的幂相对于彼此的间隔是不规则的。210(1024)靠近103(1000)。10是在1024(包括在内)到2048(不包括在内)之间的数字的浮点数
格式中使用的指数。所以1024到2048之间的间隔就像是在100-1000结束和1000-10,000块开始之后放置的块。
但请注意,这个包含9位数字的属性是外部度量,它不是float
可以执行的功能,也不是它可以提供的服务。它是float
需要的东西(如果要以十进制格式保存),而不是它提供的东西。因此,它不是一个浮点数
可以存储多少位数的界限。
进一步阅读
为了更好地理解浮点运算,考虑Jean Michel Muller等人研究IEEE-74浮点运算标准或类似浮点算术手册之类的好教材。
谢谢
假设我的机器中有一个单精度浮点格式变量,我想给它分配给定操作的结果。来自维基百科: IEEE 754标准指定二进制32具有: 符号位:1位 我不清楚最后一个要求(e-6的精度)是如何得出的。一般来说,给定一个数据类型如上面的或,如何在基数10中找到精度限制?
我编写了一个程序来演示Go中的浮点错误: 它打印: 这与用C编写的相同程序的行为相匹配(使用双代码类型) 但是,如果改用,程序就会陷入无限循环!如果将C程序修改为使用而不是,它将打印 为什么在使用时,Go程序的输出与C程序的输出不一样?
问题内容: $a = ‘35’; $b = ‘-34.99’; echo ($a + $b); 结果为0.009999999999998 这是怎么回事?我想知道为什么我的程序不断报告奇怪的结果。 为什么PHP不返回预期的0.01? 问题答案: 因为浮点运算!=实数运算。对于一些浮子和,由不精确性引起的差异的说明是。这适用于使用浮点数的任何语言。 由于浮点数是具有有限精度的二进制数,因此存在有限数量
本文向大家介绍Fortran 浮点数精度,包括了Fortran 浮点数精度的使用技巧和注意事项,需要的朋友参考一下 示例 类型的浮点数real不能有任何实数值。它们可以表示实数,最多可以包含一定数量的十进制数字。 FORTRAN 77保证了两种浮点类型,而最新的标准则至少保证了两种实数类型。实变量可以声明为 x这是默认类型的实数,并且y是比更大的十进制精度的实数x。在Fortran 2008中,十
运行以下代码时,我希望收到这样的输出: 但结果如下: 欢迎任何能指导我正确使用浮点比较和正确使用setprecision的建议。