Как вычислить плавающую запятую в системе счисления, отличной от 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 становится А, 11 становится Б,..., 15 становится F.
Другие советы
Конечное число (число, которое может быть представлено конечным числом цифр) n1 в базе б1, может оказаться непрерывным числом в другой системе счисления b2.И наоборот, неконцевое число по одной базе b1 может оказаться конечным числом по основанию b2.
Число 0,110 при преобразовании в двоичный формат является непрерывным числом, как и 0,17.10 при преобразовании в шестнадцатеричное число.Но конечное число 0,13 в системе счисления 3 при преобразовании в систему 10 представляет собой непрерывное повторяющееся число 0.(3)10 (что означает, что цифра 3 повторяется).Аналогично, конвертируя 0,110 в двоичный и 0,1710 в шестнадцатеричном формате, в итоге получаются бесконечные повторяющиеся числа 0,0 (0011).2 и 0,2(В851Е)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) — слишком много, 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, я попытаюсь сделать 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