单个数字(浮点)数据类型的优点和缺点

时间:2016-04-01 15:54:55

标签: math floating-point int computer-science precision

为什么我们在编程语言中使用各种数据类型?为什么不到处使用浮动?我听过一些像

这样的论点
  1. int 上的算术更快(但为什么?)
  2. 存储浮动需要更多内存。 (我明白了。)
  3. 使用各种类型的数字数据类型有哪些额外的好处?

1 个答案:

答案 0 :(得分:2)

整数算术传统上更快,因为它操作更简单。它可以在逻辑门中实现,如果设计得当,整个过程可以在一个时钟周期内完成。

在大多数现代PC上,浮点支持实际上非常快,因为大量的时间已投入到快速制作中。它只适用于浮点严重受损的低端处理器(如Arduino或某些版本的ARM平台),或者完全不在CPU中。

浮点数包含几个不同的数据:有一个符号位,尾数和指数。要将这三个部分放在一起以确定它们所代表的值,您可以执行以下操作:

value = sign * mantissa * 2^exponent

它比这复杂得多,因为浮点数可以优化它们如何存储尾数(例如尾数的第一位假定为1,因此第一位实际上并不是真的需要存储...但这也意味着零必须以特定方式存储,并且有各种特殊值"可以存储在像#34这样的浮点数中;而不是数字" #34;和使用浮点数时必须正确处理的无穷大)

所以存储号码" 3"你的尾数为0.75,指数为2.(0.75 * 2 ^ 2 = 3)。

但是要将两个浮点数加在一起,首先必须对齐它们。例如,3 + 10:

m3 = 0.75  (stored as binary (1)1000000...  the first (1) implicit and not actually stored)
e3 = 2
m10 = .625  (stored as binary (1)010000...)
e10 = 4     (.625 * 2^4 = 10)

你不能只将m3和m10加在一起,因为你得到了错误的答案。首先必须将m3移位几位以使e3和e10匹配,然后可以将尾数添加到一起并将结果重新组合成新的浮点数。当然,具有良好浮点实现的CPU可以为您完成所有这些工作,并且可以快速完成。

那么为什么你不想为所有东西使用浮点值呢?那么,对于初学者来说,存在准确性的问题。如果你添加或乘以两个整数来获得另一个整数,只要你不超过整数大小的限制,你得到的答案将完全正确。这不是浮点的情况。例如:

x = 1000000000.0
y = .0000000001
for (cc = 0; cc < 1000000000; cc++) { x += y; }

从逻辑上讲,您希望(x)的最终值为1000000000.1,但这几乎肯定不是您将获得的。当你添加(y)到(x)时,对(x)的尾数的改变可能很小,甚至不适合浮点数,因此(x)可能根本不会改变。即使情况并非如此,(y)的价值也不准确。没有两个整数(a,b)使得(a * 2 ^ b = 10 ^ -10)。实际上,对于许多常见的十进制值来说,这是正确的。即使像0.3这样简单的东西也不能存储为二进制浮点数中的精确值。

所以(y)并不恰好是10 ^ -10,它实际上是少量的。对于32位浮点数,它将关闭约10 ^ -26:

y = 10^-10 + error, error is about 10^-26

然后,如果你将(y)加上一百亿次,那么错误也会放大大约一百亿次,所以你的最终错误大约是10 ^ -16

一个好的浮点实现会尽量减少这些错误,但它总是能够做到正确。问题是如何存储数字的基础,并且在某种程度上是不可避免的。因此,例如,即使将货币值存储在浮点数中似乎很自然,也可能最好将其存储为整数,以确保该值始终是精确的。

&#34;准确性&#34;问题也意味着当你测试浮点数的值时,一般来说,你不能使用精确的比较。例如:

x = 11.0 / 500
if (x * 50 == 1.1) { ...  It doesn't!

for (float x = 0.0; x < 1.0; x += 0.01) { print x; }
// prints 101 values instead of 100, the last one being 0.9999999...

测试失败,因为(x)并不完全是我们指定的值,而1.1,当编码为浮点数时,并不完全是我们指定的值。他们关闭但不是完全。所以你必须做不准确的比较:

if (abs(x - expected_value) < small_value) {...

选择正确的&#34; small_value&#34;对自己来说是一个问题。它取决于您对价值观的影响,以及您尝试实现的行为。

最后,如果你看一下&#34;它需要更多的内存和#34;问题,您也可以根据您使用的内存的获取来解决这个问题。

如果您可以使用整数数学来解决您的问题,那么32位无符号整数可以使用0到40亿之间的(精确)值。

如果您使用的是32位浮点数而不是32位整数,则可以存储大于40亿的值,但是您仍然受到表示的限制:在这32位中,使用一个对于符号位,以及8为尾​​数,所以你得到23位(24,有效)的尾数。一旦(x> = 2 ^ 24),你就超出了存储整数的范围&#34;确切地说&#34;在那个浮点数中,所以(x + 1 = x)。所以像这样的循环:

float i;
for (i = 1600000; i < 1700000; i += 1);

将永远不会终止:(i)将达到(2 ^ 24 = 16777216),并且其尾数的最低有效位将大于1,因此向(i)添加1将不再具有任何效果。