如何以 10 以外的基数计算浮点数?
-
06-09-2019 - |
题
鉴于维基百科的文章 小数点, ,如何计算 10.1 的二进制等值或 17.17 的十六进制等值?对于前者,十分之一的二进制相当于多少?对于后者,17/100 的十六进制表示?
我更多地寻找一种算法,而不是这两个例子的解决方案。
解决方案
要将十进制 10.1 转换为二进制,请将整数部分和小数部分分开并分别进行转换。
要转换整数部分,请使用重复的整数除以 2,然后以相反的顺序写入余数:
10/2 = 5 余数 0
5/2 = 2 余 1
2/2 = 1 余数 0
1/2 = 0 余数 1
回答:1010
要转换小数部分,请重复乘以 2,并在每一步减去整数部分。整数部分按生成顺序表示您的二进制数:
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
...(循环永远重复)
所以十进制 0.1 是二进制 0.000110011001100...
(有关更详细的解释,请参阅我的文章中的例程 dec2bin_i() 和 dec2bin_f() http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ .)
对于十六进制,请使用相同的过程,只不过除数/乘数为 16 而不是 2。余数和大于 9 的整数部分必须直接转换为十六进制数字:10 变为 A,11 变为 B,..., 15 变为 F。
其他提示
一终止数字(一些这可以由有限数量的数字)n1 在基b1, 可能是一个非终止的数量在不同的基b2.相反,一个非终止的数量在一个基b1 可以变成是一个终止的数量在基b2.
数0.110 当转换为是二进制的一个非终止的数量,为的是0.1710 当转换为一个进制数字。但是终端数量为0.13 在基3,当转换为基10是非终止,重复数量为0。(3)10 (标志着数3重复).同样,将0.110 二进制和0.1710 到十六、一个结束了非终止、重复的数字0.0(0011)2 和0.2(B851E)16
因此,当将这样一个数字从一个到另一个基地,您可能发现自己具有近似数,而不是具有代表性,这是完全准确。
该算法很简单,但实际上,你可以做很多事情都与查找表和日志的调整来加快速度。 但对于基本的算法,您可以尝试是这样的:
shift=0;
while v>=base, v=v/base, shift=shift+1;
Next digit:
if v<1.0 && shift==0, output the decimal point
else
D=floor(v)
output D
v=v-D
v=v*base
shift = shift-1
if (v==0) exit;
goto Next Digit
您还可以将一个测试中有N个数位后停止打印更长循环小数。
十分之一的 '二进制等效' 是二分之一,即代替1- / 10 ^ 1,它的1/2 ^ 1
每个数字表示的二的幂。小数点后面的数字是相同的,只是它们所代表1以上的两个功率:
8 4 2 1 . 1/2 1/4 1/8 1/16
因此,对于10.1,则显然需要一个“8”和“2”,使10部分。 1/2(0.5)过多,四分之一(0.25)过多,1/8(0.125)是太多了。我们需要1/16(0.0625),这将使我们能够对0.0375。 1/32为0.03125,所以我们可以利用这一点。到目前为止,我们有:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32
1 0 1 0 0 0 0 1 1
使用的0.00625错误。 1/64(0.015625)和1/128(0.0078125)均过多,1/256(0.00390625)将工作:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256
1 0 1 0 0 0 0 1 1 0 0 1
使用的0.00234375错误。
在0.1不能被精确以二进制(正如1/3不能精确十进制来表示)来表示。这取决于你把你的基数,你最终不得不停止,可能是圆的,并接受错误。
在我在GMP库的光这个玩弄,这里的地方我一定要努力让里克·里根的PHP代码一般从2任何基高达36。
Function dec2base_f(ByVal ddecimal As Double, ByVal nBase As Long, ByVal dscale As Long) As String
Const BASES = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 'up to base 36
Dim digitCount As Long
Dim wholeNumber As Double
Dim digit As String * 1
digitCount = 0
dscale = max(dscale, Len(CStr(ddecimal)) - Len("0."))
Dim baseary_f As String
baseary_f = "0."
Do While ddecimal > 0 And digitCount < dscale
ddecimal = ddecimal * nBase
digit = Mid$(BASES, Fix(ddecimal) + 1)
baseary_f = baseary_f & digit '"1"
ddecimal = ddecimal - Fix(ddecimal)
digitCount = digitCount + 1
Loop
dec2base_f = baseary_f
End Function
Function base2dec_f(ByVal baseary_f As String, nBase As Double) As Double
Const BASES As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim decimal_f As Double
Dim i As Long
Dim c As Long
For i = Len(baseary_f) To Len("0.") + 1 Step -1
c = InStr(BASES, Mid$(baseary_f, i, 1)) - 1
decimal_f = decimal_f + c
decimal_f = decimal_f / nBase
Next
base2dec_f = decimal_f
End Function
Debug.Print base2dec_f(dec2base_f(0.09, 2, 200), 2) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 8, 200), 8) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 16, 200), 16) --> 0.09