我在工作中读取流量计算机上的寄存器(有点像PLC)。根据文档,寄存器存储为IEEE单精度浮点数。我读了寄存器并将它们存储在CComVariants(MS VARIANT类的包装器)中。
我知道这样的值存储在设备寄存器中......
0.45
0.3
0.2
0.05
当我通过VS2010中的断点暂停执行时,我会看到像这样的奇怪尾随分数的值......
0.4500000000031
0.300000034
0.2000000005
0.05000000004
我的问题是,这是一个问题,Visual Studio 2010 IDE是不精确的还是IEEE单精度浮点数对于这个应用程序来说根本不够精确(+/- 0.00001)?
我问,因为我可能需要输入代码来检查以后这些值是否在某个范围内,并检查代码以查看所有这些分数是否总和为1.
答案 0 :(得分:1)
浮点精度是小数点后的位数。 单/双等是它能够存储的数字范围以及它能够在该点之后保留的数量。
如果您需要精确的表示,则不能使用浮点。
您可以尝试将它们转换为十进制类型或其他类型(例如* 100并使用int),或者只是将其设置为足够准确并保留它。
浮点根本无法表示其范围内的所有可能值。会有差距。这与用十进制的1/3写的问题相同。
0.33333333已接近,但它是渐近的。你可以通过添加更多的3来接近1/3,但你永远不会到达那里。
答案 1 :(得分:0)
浮点数通常不会存储分数。通常,单精度浮点数(“float”)存储符号,24位二进制数字(“有效数字”)和8位指数,用于缩放数字。如果符号为s(+1或-1),则有效数为f,指数为e,则存储的浮点数表示s * f * 2 e 。
浮点数不能完全代表.45因为没有符号,有效数和指数使得s * f * 2 e 正好是.45。没有多少精度可以改变这一点,因为没有整数,当乘以2上升到整数的幂时,恰好等于.45。因此,当.45准备存放在浮点数中时,它必须被舍入,通常是浮点数可以表示的最接近的数字。这就是为什么你看到0.4500000000031。
请注意,我遗漏了一些东西。这些可能对你的直接问题没有帮助,但我提到它们的完整性:可能存在非典型的浮点表示。这些日子很少见;它们在IEEE-754浮点运算标准之前更为常见。虽然有效数是24位,但只存储了23位;领先位是隐含的一位。 8位指数作为数字存储在区间1到254中,表示-126到127的指数。当存储的指数为0时,有效位数小于24位;隐含位为零,指数保持钳位在-126。当存储的指数为255时,float表示无穷大(如果有效数为零)或“非数字”(否则)。最新的IEEE-754标准规定了十进制算术的格式,但并非所有系统都支持它。
如果您使用的系统支持十进制算术,并且您使用的所有数字都可以精确表示为可用精度的小数,则可以使用它来获得准确的答案。
如果没有十进制算术,可以选择使用更常见的二进制浮点算法,但要处理舍入误差。有时候,当你有一个完全添加到1的数字列表,然后将它们存储在浮点数中并对浮点数求和时,你会得到一个不完全是1的答案。有时,当你的数字不加1时,并且你以相同的方式添加它们,你将得到正确的1.因此可能存在误报结果(“是,总和是1”,但它不是)和假阴性结果(“不,总和不是1“,但它是)。您可以选择以接受误报为代价来拒绝误报。 (例如,计算你的求和过程中可能出现多少错误,并接受任何接近1的数字。这将使你接受所有总和,如果完全完成,那么它也会使你接受一些总和如果完全完成则不是1。)
如果您无法接受,可能还有其他方法可以执行计算。如果所有数字的形式都是n / 100,其中n是整数,则将n存储在int中,而不是将n / 100存储在float中。然后你可以准确地添加整数,如果存储的整数之和是100,你就知道确切的和是1。