鉴于维基百科上关于基数点的文章,如何计算10.1的二进制等价物或17.17的十六进制等价物?对于前者,十分之一的二进制等价物是什么?对于后者,17/100的十六进制表示是什么?
我更希望得到一个算法,而不仅仅是这两个例子的解决方案。
我更希望得到一个算法,而不仅仅是这两个例子的解决方案。
(有关更详细的说明,请参见我的文章http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/中的dec2bin_i()和dec2bin_f()例程。)
对于十六进制,使用相同的过程,但将除数/乘数改为16。余数和大于9的整数部分必须直接转换为十六进制数字:10变成A,11变成B,...,15变成F。
这个算法相当简单,但在实践中,您可以通过查找表和日志进行许多微调以加快速度。 但对于基本算法,您可以尝试以下内容:
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。
每个数字代表2的幂。小数点后面的数字是相同的,只是它们代表2的负幂:
8 4 2 1 . 1/2 1/4 1/8 1/16
因此,对于10.1,显然需要一个“8”和一个“2”来组成10部分。 1/2(0.5)太多了,1/4(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。
十进制小数.1在二进制中无法准确表达(就像1/3在十进制下无法准确表达一样)。根据小数点的位置,你最终不得不停止、可能四舍五入,并接受误差。
在我使用GMP库进行调整之前,这里是我尝试使Rick Regan的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