这里的关键是你的困惑:10
是的产品2
和5
。可以表示任何数量的恰好在底座10个小数即K * 1/2 Ñ * 1/5 米,其中k
,n
和m
是整数。
换句话说-如果n
1 / n中的数字包含一个不属于基数因子的因数,则该数字将不能以固定数量的数字准确地以二进制,十进制或该数字的任何扩展形式表示数字-它会有重复的部分。例如1/15 = 0.0666666666 ....因为3(15 = 3 * 5)不是10的因数。
因此,任何能够在基数2中精确表示的东西(k * 1/2 n)都可以在基数10中精确表示。
除此之外,还有一个问题是您要使用多少个数字/位来代表数字。有一些数字可以在某个基数中准确表示,但是要做的事情不止一些数字/位。
在二进制中,数字1/10(通常为十进制的0.1)不能表示为可以用固定位数的二进制形式表示的数字。相反,该数字为0.00011001100110011 ... 2(0011部分将永远重复)。
让我们来看看数1 2 /1010 2位更加紧密。
____
0.00011
+ ---------
1010 | 1.00000
0
-
1 0
0
----
1 00 --------- +
0 |
----- |
1 000 |
0 |
------ | 重复
1 0000 | 块
1010 |
------ |
1100 |
1010 |
---- |
100 ---- +
这与尝试进行1/3的长除法时得到的类型完全相同。
当分解为1 /(2 1 * 5 1)时为1/10 。对于以10为底的数字(或10的任意倍数),此数字终止,称为常规数字。重复的十进制扩展称为重复的十进制,那些永远不重复的数字就是无理数。
背后的数学探究了Fermat的小定理 ...一旦您开始说Fermat或定理,它便成为Math.SE问题。
是否存在不能以10为基数但可以以2为基数的数字?
答案是不'。
因此,在这一点上我们都应该清楚,有理数的每个固定长度的二进制扩展都可以表示为固定长度的十进制扩展。
让我们更仔细地看一下C#中的十进制,这导致我们到达.NET中的Decimal浮点,并且在作者看来,我接受那就是它的工作原理。
十进制类型与其他任何浮点数具有相同的组成部分:尾数,指数和符号。像往常一样,符号只是一位,但尾数为96位,指数为5位。但是,并非所有指数组合都是有效的。只有值0-28有效,并且它们实际上都是负数:数值是。这意味着该类型的最大值和最小值为+/-(2 96 -1),并且就绝对大小而言,最小的非零数为10 -28。sign * mantissa / 10exponent
我将立即指出,由于此实现,double
类型中的某些数字无法表示decimal
-超出范围的数字。 Double.Epsilon
是4.94065645841247e-324
不能用表示decimal
,但可以用表示double
。
但是,在十进制可以表示的范围内,它比其他本机类型具有更高的精度位,并且可以无错误地表示它们。
还有其他一些类型。C#中有一个BigInteger,它可以表示任意大的整数。没有相当于Java的BigDecimal的(其可以表示数字最多高达2的十进制数字32位长-这是一个相当大的范围)完全相同。但是,如果您四处摸索,则可以找到手动实现。
有些语言也具有有理数据类型,可让您精确表示有理(因此1/3实际上是1/3)。
具体来说,对于C#和float或有理数的选择,我将从.NET中的Decimal浮动pint转到Jon Skeet :
大多数业务应用程序可能应该使用小数而不是浮点数或双精度数。我的经验法则是,通常用十进制浮点数更好地表示诸如货币之类的人造值:例如,精确地1.25美元的概念是完全合理的。对于自然界的值(例如长度和权重),二进制浮点类型更有意义。即使理论上“精确地达到1.25米”,它也永远不会发生:您当然永远也无法测量精确的长度,并且它们甚至不可能出现在原子级。我们已经习惯了一定的容忍度。