Costumo usar o bc
utilitário para converter hexadecimal para decimal e vice-versa. No entanto, é sempre um pouco de tentativa e erro como ibase
e obase
deve ser configurado. Por exemplo, aqui eu quero converter o valor hexadecimal C0 em decimal:
$ echo "ibase=F;obase=A;C0" | bc
180
$ echo "ibase=F;obase=10;C0" | bc
C0
$ echo "ibase=16;obase=A;C0" | bc
192
Qual é a lógica aqui? obase
( A
no meu terceiro exemplo) precisa estar na mesma base que o valor que é convertido ( C0
nos meus exemplos) e ibase
( 16
no meu terceiro exemplo) deve estar na base para a qual estou convertendo?
Respostas:
O que você realmente quer dizer é:
para hexadecimal e decimal e:
para decimal para hexadecimal.
Você não precisa fornecer os dois
ibase
eobase
para qualquer conversão envolvendo números decimais, pois essas configurações são 10.Você não precisa dar tanto para as conversões, tais como binary-to-hex. Nesse caso, acho mais fácil entender as coisas se você der
obase
primeiro:Se você fornecer
ibase
primeiro, ele altera a interpretação da seguinteobase
configuração, para que o comando tenha que ser:Isso ocorre porque, nessa ordem, o
obase
valor é interpretado como um número binário, portanto, é necessário fornecer 10000₂ = 16 para obter a saída em hexadecimal. Isso é desajeitado.Agora vamos descobrir por que seus três exemplos se comportam como eles.
echo "ibase=F;obase=A;C0" | bc
180
Isso define a base de entrada como 15 e a base de saída como 10, pois um valor de um dígito é interpretado em hexadecimal, de acordo com o POSIX . Isso pede
bc
para lhe dizer o que C0₁₅ está na base A₁₅ = 10 e está respondendo corretamente a 180₁₀, embora essa certamente não seja a pergunta que você pretendia fazer.echo "ibase=F;obase=10;C0" | bc
C0
Esta é uma conversão nula na base 15.
Por quê? Primeiro, porque o
F
dígito único é interpretado em hexadecimal, como apontei no exemplo anterior. Mas agora que você definiu como base 15, a seguinte configuração da base de saída é interpretada dessa maneira e 10₁₅ = 15, para que você tenha uma conversão nula de C0₁₅ para C0₁₅.É isso mesmo, a saída não está em hexadecimal como você estava assumindo, está na base 15!
Você pode provar isso para si mesmo tentando converter em
F0
vez deC0
. Como não háF
dígito na base 15,bc
prenda-oE0
e dêE0
como saída.echo "ibase=16; obase=A; C0"
192
Este é o único de seus três exemplos que provavelmente tem algum uso prático.
Ele está mudando a base de entrada para hexadecimal primeiro , para que você não precise mais pesquisar na especificação POSIX para entender por que
A
é interpretado como hexadecimal 10 neste caso. O único problema é que é redundante definir a base de saída como A₁₆ = 10, já que esse é o valor padrão.fonte
Configuração
ibase
significa que você precisa definirobase
na mesma base. Explicar seus exemplos mostrará isso:Você define os
bc
números de entrada como representados na base 15 com o "ibase = F". "obase = A" define os números de saída para a base 10, que é o padrão.bc
lê C0 como um número base 15: C = 12. 12 * 15 = 180.Neste, você define a entrada para a base 15 e a saída para 10 - na base 15, então a base de saída é 15. A entrada C0 na base 15 é a saída C0 na base 15.
Defina a entrada para a base 16, a saída para a base 10 (A na base 16 é 10 na base 10).
C0 convertido na base 10 é: 12 * 16 = 192
Minha regra pessoal é definir obase primeiro, para que eu possa usar a base 10. Em seguida, defina ibase, também usando a base 10.
Observe que
bc
há uma exceção irônica:ibase=A
eobase=A
sempre define entrada e saída como base 10. Nabc
página de manual:Esse comportamento é consagrado na especificação de
bc
: Na especificação do OpenGroup 2004bc
:É por isso que a
ibase=F
configuração mudou sua base de entrada para a base 15 e por que eu recomendei sempre definir a base usando a base 10. Evite se confundir.fonte
Todos os números são interpretados pelo GNU bc como a base de entrada atual em vigor para a instrução em que o número aparece. Quando você usa um dígito fora da entrada atual, interpreta-os como o dígito mais alto disponível na base (9 em decimal) quando parte de um número de vários dígitos ou como seus valores normais quando usado como um número de dígito único (
A
== 10 em decimal).No manual GNU bc :
No entanto, você deve estar ciente de que o padrão POSIX só define este comportamento para atribuições para
ibase
eobase
, e não em qualquer outro contexto.A partir da especificação SUS no bc :
O principal fator que está faltando é que F não é de fato dezesseis, mas na verdade é quinze; portanto, quando você está configurando ibase = F, está definindo a base de entrada para quinze.
Portanto, para portably definir o ibase para hexadecimal de um estado desconhecido, portanto, você precisa usar duas declarações:
ibase=A; ibase=16
. No entanto, no início do programa, você pode confiar que ele é decimal e simplesmente usaribase=16
.fonte
ibase=A; ibase=16
.É sempre recomendável definir
ibase
eobase
usar um número de um dígito, em vez de um número como16
, pois, de acordo com abc
página de manual,Isso significa que
A,B,...,F
sempre têm os valores10,11,...,15
respectivamente, independentemente de qual seja o valoribase
. Você também pode usarF+1
para especificar o número16
. Por exemplo, é melhor escreverem vez de escrever
echo "ibase=16; obase=A; C0" | bc
para especificar que a base de entrada é16
e a base de saída é10
. Ou, por exemplo, se você quer ter ambosibase
eobase
ter 16 anos, é melhor usarem vez de usar
ibase=16; obase=10
. Da mesma forma, se você quiser inserir seus números na base 14 e produzi-los na base 16, useEmbora as formas de banho tenham os mesmos resultados, a primeira é menos suscetível a erros, enquanto a segunda pode levar a mais confusão e erro.
A diferença entre as duas formas se torna mais aparente, especialmente quando você está no ambiente de execução
bc
ou escreve seus cálculos em um arquivo e depois passa esse arquivobc
como argumento. Em tais situações, você pode ter que alterar os valores deibase
eobase
várias vezes, e usando a última forma, pode levar a sérias confusões e erros. (experencie)fonte