3

鉴于维基百科关于Radix Point的文章,如何计算 10.1 的二进制等价物或 17.17 的十六进制等价物?对于前者,十分之一的二进制等价物是多少?对于后者,17/100 的十六进制表示?

我正在寻找一种算法,而不是仅仅针对这两个示例的解决方案。

4

5 回答 5

6

要将十进制 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...

(有关更详细的解释,请参阅我的文章http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/中的例程 dec2bin_i() 和 dec2bin_f() 。)

对于十六进制,使用相同的过程,但除数/乘数为 16 而不是 2。大于 9 的余数和整数部分必须直接转换为十六进制数字:10 变为 A,11 变为 B,...,15 变为 F .

于 2009-05-31T19:26:03.730 回答
3

该算法非常简单,但在实践中,您可以使用查找表和日志进行大量调整以加快速度。但是对于基本算法,您可以尝试这样的事情:

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 位之后停止打印,以获得更长的重复小数。

于 2009-05-31T15:59:05.973 回答
3

以 b 1为基数的终止数(可以由有限位数表示的数字)n 1可能最终成为不同基数 b 2的非终止数。相反,一个底数b 1中的非终止数可能会变成底数b 2中的终止数。

转换为二进制时的数字 0.1 10是非终止数,转换为十六进制数时的 0.17 10也是如此。但是以 3 为底的终止数字 0.1 3转换为以 10 为底的数字是非终止的重复数字 0.(3) 10(表示数字 3 重复)。类似地,将 0.1 10转换为二进制,将 0.17 10转换为十六进制,最终会得到非终止的重复数字 0.0(0011) 2和 0.2(B851E) 16

因此,在将此类数字从一个基数转换为另一个基数时,您可能会发现自己不得不近似该数字,而不是获得完全准确的表示。

于 2009-05-31T16:37:13.517 回答
1

十分之一的“二进制等价物”是二分之一,即不是 1/10^1,而是 1/2^1。

每个数字代表二的幂。小数点后面的数字是相同的,只是它们代表 1 的 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 不能用十进制精确表示一样)。根据您放置基数的位置,您最终必须停下来,可能会舍入并接受错误。

于 2009-05-31T16:31:08.217 回答
0

在我根据我的 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
于 2009-06-01T14:26:13.050 回答