如何以 10 以外的基数计算浮点数?

发布于 2024-07-22 07:40:52 字数 224 浏览 12 评论 0原文

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

我更多的是寻找一种算法,而不是这两个例子的解决方案。

Given Wikipedia's article on Radix Point, how would one calculate the binary equivalent of 10.1 or the hex equivalent of 17.17? For the former, what is the binary equivalent of a tenth? For the latter, the hex representation of 17/100?

I'm looking more for an algorithm than for solutions to just those two examples.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

巷雨优美回忆 2024-07-29 07:40:52

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

To convert decimal 10.1 to binary, separate the integer and fractional parts and convert each separately.

To convert the integer part, use repeated integer division by 2, and then write the remainders in reverse order:

10/2 = 5 remainder 0

5/2 = 2 remainder 1

2/2 = 1 remainder 0

1/2 = 0 remainder 1

Answer: 1010

To convert the fractional part, use repeated multiplication by 2, subtracting off the integer part at each step. The integer parts, in order of generation, represent your binary number:

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

... (cycle repeats forever)

So decimal 0.1 is binary 0.000110011001100...

(For a more detailed explanation see routines dec2bin_i() and dec2bin_f() in my article http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ .)

For hexadecimal, use the same procedure, except with a divisor/multiplier of 16 instead of 2. Remainders and integer parts greater than 9 must be converted to hex digits directly: 10 becomes A, 11 becomes B, ... , 15 becomes F.

难如初 2024-07-29 07:40:52

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

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 位数字后停止打印更长的重复小数。

The algorithm is quite simple, but in practice you can do a lot of tweaks both with lookup tables and logs to speed it up.
But for the basic algorithm, you may try something like this:

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

You may also put a test in there to stop printing after N digits for longer repeating decimals.

昇り龍 2024-07-29 07:40:52

以 b1 为基数的终止数(可以用有限位数表示的数字) n1,可能最终成为不同的非终止数以 b2 为底。 相反,一个基数 b1 中的非终止数可能会成为基数 b2 中的终止数。

数字 0.110 转换为二进制时是非终止数字,转换为十六进制数字时 0.1710 也是非终止数字。 但是以 3 为基数的终止数字 0.13,当转换为以 10 为基数时,就是非终止的重复数字 0.(3)10(表示数字 3 重复) )。 类似地,将 0.110 转换为二进制,将 0.1710 转换为十六进制,最终得到非终止的重复数字 0.0(0011)2和 0.2(B851E)16

因此,当将这样的数字从一种基数转换为另一种基数时,您可能会发现自己必须近似该数字,而不是完全准确的表示形式。

A terminating number (a number which can be represented by a finite number of digits) n1 in base b1, may end up being a non-terminating number in a different base b2. Conversely, a non-terminating number in one base b1 may turn out to be a terminating number in base b2.

The number 0.110 when converted to binary is a non-terminating number, as is 0.1710 when converted to a hexadecimal number. But the terminating number 0.13 in base 3, when converted to base 10 is the non-terminating, repeating number 0.(3)10 (signifying that the number 3 repeats). Similarly, converting 0.110 to binary and 0.1710 to hexadecimal, one ends up with the non-terminating, repeating numbers 0.0(0011)2 and 0.2(B851E)16

Because of this, when converting such a number from one base to another, you may find yourself having to approximate the number instead of having a representation which is completely accurate.

黄昏下泛黄的笔记 2024-07-29 07:40:52

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

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

The 'binary equivalent' of one tenth is one half, i.e instead of 1/10^1, it's 1/2^1.

Each digit represents a power of two. The digits behind the radix point are the same, it's just that they represent 1 over the power of two:

 8 4 2 1 . 1/2 1/4 1/8 1/16 

So for 10.1, you obviously need an '8' and a '2' to make the 10 portion. 1/2 (0.5) is too much, 1/4 ( 0.25 ) is too much, 1/8 (0.125) is too much. We need 1/16 (0.0625), which will leave us with 0.0375. 1/32 is 0.03125, so we can take that too. So far we have:

 8 4 2 1 . 1/2 1/4 1/8 1/16 1/32
 1 0 1 0    0   0   0   1     1

With an error of 0.00625. 1/64 (0.015625) and 1/128 (0.0078125) are both too much, 1/256 (0.00390625) will work:

 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

With an error of 0.00234375.

The .1 cannot be expressed exactly in binary ( just as 1/3 can't be expressed exactly in decimal ). Depending on where you put your radix, you eventually have to stop, probably round, and accept the error.

迟到的我 2024-07-29 07:40:52

在我根据我的 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

Before I twiddle with this in the light of my GMP library, here's where I got to trying to make Rick Regan's PHP code generic for any base from 2 up to 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文