Que dicas gerais você tem para jogar golfe no dc ?
dc é um utilitário de calculadora para UNIX / Linux anterior à linguagem C. Estou interessado em como reduzir meus programas de CC (cálculos?). Estou procurando idéias que possam ser aplicadas ao código-golfe geral que sejam pelo menos um pouco específicas ao dc (por exemplo, remover comentários não é uma resposta útil)
Poste uma dica por resposta.
Respostas:
Instruções if-then-else
Suponha que desejamos verificar a condição
editar:a==b
(deixea
eb
seja armazenada em seus registros com nomes respectivos).Seja
(foo)
um espaço reservado, com a finalidade de condensar:Certamente essa é a declaração if mais compacta possível (também apresentada aqui ).
fonte
[[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI f
seja um começo? As ações para tehn e else estão na pilha, aI
macro "f" as troca e é calibrada condicionalmente. o topo da pilha será executado e a macro não utilizada será descartada em I para limpar a pilha.2 4
são apenas os dados de exemplo para comparar. Em alternativa, a[x]sI
peça pode ser movida para a comparação, se considerado mais legível:[[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f
. Af
nos exemplos apenas deve mostrar tat a pilha é limpo depois ...dc
e essa foi a 1ª página em que vidc
aif-then-else
construção do OpenBSD . Eu acho que precisamos de umdc
pacote de fãs com todos os 3 tipos para todos os principais sistemas operacionais ... o :-) ... e minhaif-then-else
proposta acima não funciona no originaldc
porque falta or
comando ... :-([[(if)2Q]si(condition)i(else)]x
- agrupar a coisa toda em uma macro e a parte if dentro de outra macro dentro dela, para que você possa2Q
sair da coisa toda antes de chegar à parte else. Portanto, se você quiser fazer se 1 == 1 e imprimir 1 mais imprimir 2 , seria1[[1P2Q]si1=i2P]x
(não testado, pois não tenho acesso ao dc aqui e agora. Também tinha certeza de que havia feito esse truque em uma resposta aqui antes mas não consegui encontrá-lo)[/*else*/]sE[[/*then*/]sE]sIlalb=IlEx
vs[[/*then*/2Q]sIlalb=I/*else*/]x
- diferença de 6 bytes. Ainda tho não testado: PVocê pode salvar a entrada com
d
Ao usar
d
, que duplica os ToS (parte superior da pilha), você pode mover a entrada para uso posterior, enquanto ainda pode usá-la.fonte
Matrizes
Embora sejam uma dor de cabeça para iniciantes,
dc
oferece matrizes. Eles funcionam assim:Como de costume, o primeiro elemento possui o índice 0. As matrizes podem ser úteis ao trabalhar com sequências, como na sequência SUDSI , especialmente em combinação com contadores. As matrizes podem reduzir a quantidade de embaralhamento de números que você precisa fazer (e o número de contadores e comparações) se desejar selecionar um elemento específico sem destruir o ambiente. Por exemplo, se você quiser mover uma pilha de números para uma matriz, poderá escrever uma função recursiva que use
z
(profundidade da pilha) ouz 1-
como índice, armazene o elemento e verifique sez == 0
deve terminar automaticamente.Esteja ciente do seguinte:
dc
irá falhar.fonte
dc
pode ter sido atualizado recentemente e o comportamento da matriz pode ter sido ligeiramente alterado em relação a falhas. Não posso confirmar agora, mas acho que algo estava diferente da última vez que o usei no Linux.0 à enésima potência em vez de condicionais / macros
Às vezes você pode precisar de algo como condicional ternário:
Uma boa maneira de lidar com isso é descrita na resposta de @ Joe . No entanto, podemos fazer melhor:
onde E é D - C.
Isso testa a igualdade aumentando 0 para o poder da diferença dos dois valores. Isso resulta em 1 se igual e 0 em caso contrário. O resto apenas escala 1 ou 0 para os valores C ou D. Isso funciona porque
dc
fornece 0 0 = 1 e 0 n = 0 para n! = 1.fonte
Às vezes é necessário descartar um número da pilha. Uma maneira de fazer isso é simplesmente inseri-lo em uma variável não utilizada, ie
st
. No entanto, em algumas situações, você pode localizá-lo em alguns outros lugares, por exemplo, na base de entrada quando não houver mais entrada numérica ou no especificador de precisão, se você não tiver mais operações para fazer onde a precisão faria diferença. No primeiro caso, usei
. No último caso, usek
.fonte
o
pode ser usada. E se alguma dessas coisas não for importante, elas podem ser usadas como armazenamento e apenas como descartá- las -I
/K
/O
recuperá-las respectivamente e salvar bytes sobresa
/la
etc. Valores válidos AFAIK:i
2-16;k
qualquer número inteiro não negativo;o
qualquer número inteiro maior que 1.Comprimento Cálculo:
Z
,X
, ez
Z
abre o ToS e pressiona o número de dígitos (decimal) se for um número ou o número de caracteres se for uma string. Isso pode ser útil para detectar o comprimento de um resultado (para buffer de saída) ou calcular o comprimento da string. Observe que, para números,Z
empurra o comprimento combinado da parte inteira e da parte da fração.X
exibe os ToS e pressiona o número de dígitos na parte da fração do número. Se o ToS era uma sequência,0
é pressionado.Para encontrar o número de dígitos na parte inteira do número, pode-se usar
dZrX-
. Se você não alterou a precisão do padrãok==0
, o uso1/Z
é menor, mas suponha que você precise manter uma precisão diferente de zero após a operação:Kr0k1/Zrk
é bastante desagradável.z
empurra o número de itens na pilha. Um dos meus comandos favoritos, na verdade não exibe nenhum valor! Pode ser usado para gerar uma sequência de números ou incrementar um contador. Usarzd
repetidamente (digamos, no início de uma macro) pode permitir testar um cálculo de cada número natural ou inteiro em ordem crescente.fonte
z
para este e que antes, mas nunca ocorreu-me a usá-lo como um hack de um contador ... Excelente ...Os dígitos
A
aF
serem usados em substituição aos números 10 a 15. No entanto, eles ainda devem ser tratados com eficácia como dígitos da base 10 (assumindo que a base de entrada seja 10) quando em locais diferentes. Em outras palavras, com a base de entrada 10FF
não representaria 255, representaria(15 * 10) + 15
ou 165.Na verdade, isso funciona para todos os dígitos
0
paraF
em qualquer base de entrada2
para16
. Portanto, se a base de entrada for 5,26E
seria(2 * 5^2) + (6 * 5) + 14
ou 94.Observe que esse comportamento está em vigor para as fontes GNU não modificadas. No entanto, como o @SophiaLechner aponta, as distros baseadas no RedHat parecem usar bc-1.06-dc_ibase.patch que altera esse comportamento para que dígitos> = ibase sejam tratados como
ibase - 1
, independentemente de seu valor real. Note que o TIOdc
parece não ter bc-1.06-dc_ibase.patch (mesmo que seu Fedora 28 ¯_ (ツ) _ / ¯).fonte
FF
representa99
, na base de entrada 526E
é o mesmo que244
, ou seja, base 1074
.dc
versão você está executando? Eu estou usando o GNU dc 1.4.1 no ubuntu e o GNU dc 1.3 no MacOSFFp
saídas são99
1.3.95. Você poderia verificar isso na sua versão do MacOS?Ao inicializar uma macro de
função(que usaremosF
) que você deseja executar imediatamente, use algo como emdsFx
vez desFlFx
. O mesmo funciona para variáveis: emdsa
vez desala
.Se você precisar fazer outras coisas entre o armazenamento e o carregamento (por exemplo,
sa[other stuff]la
), considere ainda a viabilidade acima: Se você deixar um valor na pilha antes das outras operações, ele voltará ao topo no final dessas operações?fonte
Acabei de descobrir isso por acidente. Ainda outra maneira de gerar um zero:
_
._
é um sinal para dc de que os dígitos seguintes são um número negativo. Exemplo:Mas e se não o seguirmos com um número?
Isso funciona quando o próximo caractere que não estiver em branco após o sublinhado não for um dígito. Se um dígito o seguir, mesmo após uma nova linha, ele será interpretado como um sinal negativo.
fonte
Se o conteúdo de toda a pilha precisar ser impresso no final de um programa, um loop macro recursivo poderá ser usado para isso. No entanto, é muito mais curto simplesmente usar o
f
comando.fonte
dc
lê a entrada de uma linha de cada vez. Se você precisar ler vários itens, fazer uma por linha exige uma?
para cada linha a ser lida ou um loop macro pesado. Em vez disso, se todos os itens de entrada puderem ser colocados em uma linha separada por espaço, um único?
lerá todos os itens de entrada, empurrando cada um deles para a pilha.Por exemplo em
seq 10 | dc -e'?f'
,seq
gera números inteiros 1 a 10, um por linha. o?
irá apenas ler o primeiro1
que será produzido quandof
despejar toda a pilha. No entantoseq 10 | tr '\n' ' ' | dc -e'?f'
,tr
faz com que os números inteiros de entrada sejam separados por todo o espaço. Nesse caso,?
ele lerá todos os números inteiros da linha de uma só vez ef
exibirá todos eles.fonte
Se um operador estiver restrito da fonte, faça um novo com
a
Algo que já me foi útil algumas vezes agora é evitar o uso de um operador específico, pressionando o valor ASCII do operador,
a
convertendo-o em uma cadeia de caracteres es
inserindo-o em um registro para ser executado como uma macro posteriormente em. Por exemplo, preciso fazer divisão, mas sou proibido de tentar evitar o uso do personagem/
. Em vez disso, eu posso fazer47asd
e, no futuro, quando precisar dividir 16 por 416 4 ldx
,.s
esse que precisam ser postfixados por alguma coisa.fonte
Evitando espaço em branco
Evitar o espaço em branco surge em alguns desafios e geralmente é fácil
dc
. Além de cordas, um momento muito específico que os espaços em branco se torna necessário é quando empurrando vários números consecutivas:1 2 3
. Se isso deve ser evitado:1[]x2[]x3[]x
.35asn
e executar -lo no meio:1lnx2lnx3lnx
.fonte
dc: ',' (054) unimplemented
avisos.