为什么存储在 Float 数据类型中的数据被视为近似值?
我一直不明白为什么浮点数据类型被认为是近似值,而小数数据类型被认为是精确的。我正在寻找一个好的解释,谢谢。
I've never understood why a float datatype is considered an approximation while a decimal datatype is considered exact. I'm looking for a good explanation, thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
嗯,这取决于你的观点。
float
和decimal
(假设您指的是 C# 中的类型)都表示精确值。然而,在这两种情况下,转换(和算术)最终都可能得到近似值,其中存储的值只是“最接近理论精确值的可用值”。特别重要的是,“
float
is approximation”想法的正常原因是代码中文字值的转换:这些文字以十进制数字表示 - 并且0.1不能精确地表示为二进制浮点数。但是,它可以精确地表示为十进制浮点数。
例如,如果我们使用二进制作为文字,
那么这里就不会有任何近似值 - 该值将与十进制值 0.75 完全相同。
基本上,这都是关于人类对以 10 为基数的数字的偏见。从一个单手有 3 个手指的外星人的角度来看,他们自然地代表以 3 为基数的值,
float
和 < code>decimal 将是“近似值”。(C# 中的
float
和decimal
之间在有效数字与值范围方面还有其他显着差异,但这是另一回事。)Well, it depends on your point of view. Both
float
anddecimal
(assuming you mean types like the ones in C#) represent exact values. However, in both cases conversions (and arithmetic) can end up with approximations where the value stored is only "the closest one available to the theoretical exact value".In particular - and importantly the normal cause of the "
float
is approximate" idea - is conversions of literal values in code:These literals are expressed in terms of decimal numbers - and 0.1 can't be exactly represented as a binary floating point number. However, it can be represented exactly as a decimal floating point number.
If we used binary for literals, e.g.
then there wouldn't be any approximation here - that value would be exactly the same as the decimal value 0.75.
Basically it's all about the bias of humans to think about numbers in base 10. From the point of view of an alien with 3 fingers on a single hand who represented values in base 3 naturally, both
float
anddecimal
would be "approximations".(There are other significant differences between
float
anddecimal
in C# around the significant digits vs the range of values, but that's a different matter.)嗯,你是对的——做出如此笼统的声明是具有误导性的。要完全理解,您需要掌握两件事。
首先,decimal 旨在存储(精确)具有固定小数位数的十进制值。通常是金钱(例如,小数点是美分)。这是一个非常具体的用例。它不是任何值的精确存储;它仅适用于具有固定小数点位数的十进制值,并且该实现是为了正确执行此操作而定制的。
其次,浮点数旨在成为一种更通用的数据类型 - 它们用于存储“任何”值 - 并且实现反映了这一点(因此,例如,实现的目标是覆盖广泛的范围并尽可能有效地支持操作)。特别是,它使用的二进制表示形式无法准确表示所有十进制值。例如,它可以精确存储 0.5,但不能精确存储 0.1。这只是所使用的二进制 - 以 2 为基数 - 表示形式的事实,但这意味着对于金钱来说,浮点数不是一个好主意:如果你不能将 0.10 精确地存储为浮点数,那么任何涉及 10 美分的计算都可能会意外累积错误。
换句话说,两者都有其局限性。十进制比浮点“更精确”的唯一方法是它更容易理解:它准确工作的值是明确定义的、有用的,并且与我们使用的“自然”基数 10 表示相匹配。相比之下,要理解哪些值将由浮点数准确存储,哪些值不是,则要困难得多,因为它们依赖于底层的基数 2 表示。
well, you're right - it's misleading to make such a blanket statement. to understand completely you need to grasp two things.
first, decimal is intended for storing (exactly) decimal values with a fixed number of decimal places. typically, money (where the decimals are cents, for example). that's a very specific use case. it's not an exact store for any value; it's only for decimal values with a fixed number of decimal points, and the implementation is tailored to do that correctly.
second, floats are intended to be a more general datatype - they are used to store "any" value - and the implementation reflects that (so, for example, the implementation aims to cover a wide range of scales and support operations as efficiently as possible). in particular, it uses a binary representation that cannot represent all decimal values exactly. so, for example, it can store 0.5 exactly, but it can't store 0.1 exactly. that's just a fact of life of the binary - base 2 - representation used, but it means that for money, floats are not a good idea: if you can't store 0.10 exactly as a float then any calculations involving 10 cents may accumulate unexpected errors.
in other words, both have their limitations. the only way that decimal is "more exact" than float is that it's easier to understand: the values for which it does work exactly are clearly defined, useful, and match the "natural" base 10 representation we use. in contrast, it's much harder to understand which values will be stored exactly by floats, and which not, because they depend on the underlying base 2 representation.
您可以在此处获取所有详细信息,但基本上 IEEE 浮点将数字存储为整数尾数乘以 2 的整数次幂。就像三分之一等一些分数不能精确地表示为不重复的以 10 为基数的十进制数一样,许多分数也不能精确地表示为二进制分数。这常常令人惊讶,因为虽然我们习惯将 1/3 作为循环小数,但我们直观地期望 1/5 可以轻松表示为 0.2,但在二进制中,它是一个循环小数(二进制?),无法在二进制中精确表示。有限位数。
You can get all the gory details here, but basically IEEE floating point stores numbers as an integer mantissa times two raised to an integer power. Just like some fractions like one-third cannot be expressed exactly as a non-repeating base 10 decimal number, many fractions cannot be expressed exactly as binary fractions. This is often surprising because, while we're used to 1/3 as a repeating decimal we intuitively expect 1/5 to be easily represented as 0.2, but in binary it's a repeating decimal (binarial?) that cannot be exactly represented in a finite number of bits.
十进制值完全等于其字符串表示形式的值(编辑:以十进制表示,如 Skeet 注释),并且十进制也能够精确表示带有数字数量有限。另一方面,
float
值通常与其字符串表示形式不同,并且有许多十进制数(例如 0.1)无法精确表示为float
。A
decimal
value is exactly equal to the value of its string representation (edit: in decimal, as Skeet notes), anddecimal
is also capable of exactly representing decimal numbers with a limited amount of digits. On the other hand, afloat
value often will differ from its string representation, and there are many decimal numbers (such as 0.1) that cannot be exactly represented as afloat
.