Преобразовать десятичное значение в Base-4 в Баш

Я использовал довольно простой и по большей части прямой метод для преобразования чисел с базовыми 10 {1..256} к основанию-4 или четвертичным числам. Я использовал простое деление $(($NUM/4)) чтобы получить основной результат, чтобы получить остатки $(($NUM%4)) а затем распечатывать остатки в обратном порядке, чтобы получить результат. Я использую следующее bash скрипт для этого:

#!/bin/bash

NUM="$1"

main() {

local EXP1=$(($NUM/4))
local REM1=$(($NUM%4))
local EXP2=$(($EXP1/4))
local REM2=$(($EXP1%4))
local EXP3=$(($EXP2/4))
local REM3=$(($EXP2%4))
local EXP4=$(($EXP3/4))
local REM4=$(($EXP3%4))

echo "
$EXP1 remainder $REM1
$EXP2 remainder $REM2
$EXP3 remainder $REM3
$EXP4 remainder $REM4

Answer: $REM4$REM3$REM2$REM1
"
}

main

Этот скрипт отлично работает для чисел 0-255 или 1-256. Но за пределами этого (этих) диапазонов результаты становятся смешанными и часто повторяются или неточны. Это не такая большая проблема, так как я не собираюсь преобразовывать числа, превышающие 256 или меньше 0 (отрицательные числа [пока]).

Мой вопрос: "Есть ли более упрощенный метод для этого, возможно, с использованием expr или же bc?

2 ответа

Решение

Создать справочную таблицу, используя преимущества расширения скобок

$ echo {a..c}
a b c    
$ echo {a..c}{r..s}
ar as br bs cr cs
$ echo {0..3}{0..3}
00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33

и так, для 0-255 в десятичном виде к основанию-4

$ base4=({0..3}{0..3}{0..3}{0..3})
$ echo "${base4[34]}"
0202
$ echo "${base4[255]}"
3333

База 4 преобразования в Баш

int2b4() {
    local val out num ret=\\n;
    for ((val=$1;val;val/=4)){
        out=$((val%4))$out;
    }
    printf ${2+-v} $2 %s${ret[${2+1}]} $out
}

Вызывается только с 1 аргументом, это преобразует в базу 4 и печатает результат, за которым следует новая строка. Если присутствует второй аргумент, переменная с таким именем будет заполнена, без печати.

int2b4 135
2013
int2b4 12345678
233012011032

int2b4 5432 var
echo $var
1110320

Подробное объяснение:

  • Основная часть (можно написать):

    out=""
    for (( val=$1 ; val > 0 ; val = val / 4 )) ;do
        out="$((val%4))$out"
        done
    

    Мы можем легко понять цикл конверсии (я надеюсь)

  • local обеспечивать out val num быть локальными пустыми переменными и инициализироваться локально ret='\n'

  • printf линия использовать некоторые bashisms

    • ${2+-v} пуст, если $2 пусто и представляет -v если не.
    • ${ret[${2+1}]} стать соответственно ${ret[]} (или же ${ret[0]}) а также ${ret[1]}

    Так что эта линия стала

    printf "%s\n" $out
    

    если нет второго аргумента ($2) и

     printf -v var "%s" $out
    

    если второй аргумент var (Обратите внимание, что новая строка не добавляется к заполненной переменной, но добавляется для печати терминала).

Преобразование обратно в десятичное:

Существует bashism, позволяющий вам вычислить произвольную базу под bash:

echo $[4#$var]
5432

echo $[4#1110320]
5432

В скрипте:

for integer in {1234..1248};do
    int2b4 $integer quaternary;
    backint=$[4#$quaternary];
    echo $integer $quaternary $backint;
  done

1234 103102 1234
1235 103103 1235
1236 103110 1236
1237 103111 1237
1238 103112 1238
1239 103113 1239
1240 103120 1240
1241 103121 1241
1242 103122 1242
1243 103123 1243
1244 103130 1244
1245 103131 1245
1246 103132 1246
1247 103133 1247
1248 103200 1248
Другие вопросы по тегам