¿Qué consejos generales tienes para jugar al golf en DC ?
dc es una utilidad de calculadora para UNIX / Linux que es anterior al lenguaje C. Estoy interesado en cómo acortar mis programas de CC (¿cálculos?). Estoy buscando ideas que se puedan aplicar al código general de golf que sean al menos un poco específicas de DC (por ejemplo, eliminar comentarios no es una respuesta útil)
Por favor, publique un consejo por respuesta.
Respuestas:
Declaraciones If-then-else
Supongamos que queremos verificar la condición
editar:a==b
(leta
yb
se almacenará en sus registros nombrados respectivamente).Dejar
(foo)
ser un marcador de posición, con el fin de condensar:Estoy bastante seguro de que esta es la declaración más compacta posible (también presentada aquí ).
fuente
[[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI f
es un comienzo? Las acciones para tehn y más están en la pila, laI
macro " f" las intercambia y se llama condicionalmente. entonces se ejecutará la parte superior de la pila y la macro no utilizada se soltará en I para limpiar la pila.2 4
son solo los datos de ejemplo para comparar. Como alternativa, la[x]sI
parte se puede mover a la comparación, si se considera más fácil de leer:[[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f
. Enf
los ejemplos solo se mostrará que la pila está limpia después ...dc
y esa fue la primera página donde vidc
laif-then-else
construcción de OpenBSD . Creo que necesitamos undc
paquete de ventiladores con los 3 sabores para todos los principales sistemas operativos ... o :-) ... y miif-then-else
propuesta anterior no funciona en el originaldc
porque carece delr
comando ... :-([[(if)2Q]si(condition)i(else)]x
- envolver todo en una macro, y la porción if dentro de otra macro dentro de eso, para que pueda2Q
salir de todo antes de llegar a la porción else. Entonces, si desea hacer si 1 == 1, imprima 1 más imprima 2 , sería1[[1P2Q]si1=i2P]x
(no probado ya que no tengo acceso a CC aquí y ahora. También estaba seguro de que había hecho este truco en una respuesta aquí antes pero no pudo encontrarlo)[/*else*/]sE[[/*then*/]sE]sIlalb=IlEx
vs[[/*then*/2Q]sIlalb=I/*else*/]x
- 6 bytes de diferencia. Aún no probado: PPuede guardar la entrada con
d
Al usar
d
, que duplica el ToS (parte superior de la pila), puede mover la entrada fuera del camino para su uso posterior, sin dejar de poder usarlo.fuente
Matrices
Aunque son un dolor de cabeza para los principiantes,
dc
ofrece matrices. Funcionan así:Como de costumbre, el primer elemento tiene el índice 0. Las matrices pueden ser útiles cuando se trabaja con secuencias, como en la secuencia SUDSI , especialmente en combinación con contadores. Las matrices pueden reducir la cantidad de combinación de números que debe hacer (y la cantidad de contadores y comparaciones) si desea seleccionar un elemento en particular sin destruir su entorno. Por ejemplo, si desea mover una pila de números a una matriz, puede escribir una función recursiva que utilice
z
(profundidad de la pila) oz 1-
como índice, almacene el elemento y compruebe si sez == 0
termina.Tenga en cuenta lo siguiente:
dc
se estrellaráfuente
dc
puede haber sido actualizado recientemente, y el comportamiento de la matriz puede haber cambiado ligeramente con respecto al bloqueo. No puedo confirmar tampoco en este momento, pero creo que algo fue diferente la última vez que lo usé en Linux.0 a la enésima potencia en lugar de condicionales / macros
A veces puede que tenga algo como c ternaria condicional:
Una buena manera de manejar esto se describe en la respuesta de @ Joe . Sin embargo, podemos hacerlo mejor:
donde E es D - C.
Esto prueba la igualdad elevando 0 a la potencia de la diferencia de los dos valores. Esto da como resultado 1 si es igual y 0 en caso contrario. El resto simplemente escala el 1 o 0 a los valores C o D. Esto funciona porque
dc
da 0 0 = 1 y 0 n = 0 para n! = 1.fuente
A veces es necesario descartar un número de la pila. Una forma de hacerlo es simplemente introducirlo en una variable no utilizada, es decir
st
. Sin embargo, en algunas situaciones, puede abrirlo en un par de otros lugares, por ejemplo, la base de entrada cuando no tenga más entrada numérica o al especificador de precisión si no tiene más operaciones que hacer donde la precisión marcaría la diferencia. En el primer caso, usei
. En el último caso, usek
.fuente
o
se puede usar. Y si alguna de estas cosas no es importante, se pueden usar como almacenamiento y como simple descarte -I
/K
/O
recuperarlos respectivamente, y guardar bytes sobresa
/la
etc. Valores válidos AFAIK:i
2-16;k
cualquier número entero no negativo;o
cualquier número entero mayor que 1.Cálculo de longitud:
Z
,X
yz
Z
abre el ToS y empuja el número de dígitos (decimal) si es un número o el número de caracteres si es una cadena. Esto puede ser útil para detectar la longitud de un resultado (para la memoria intermedia) o calcular la longitud de la cadena. Tenga en cuenta que para los números,Z
empuja la longitud combinada de la parte entera y la parte fracción.X
abre el ToS y empuja el número de dígitos en la parte fraccionaria del número. Si el ToS era una cadena,0
se empuja.Para encontrar el número de dígitos en la parte entera del número, uno podría usar
dZrX-
. Si no ha cambiado la precisión por defectok==0
, el uso1/Z
es más corto, pero suponga que necesita mantener una precisión particular distinta de cero después de la operación:Kr0k1/Zrk
es más bien una monstruosidad.z
empuja el número de artículos en la pila. ¡Uno de mis comandos favoritos, en realidad no muestra ningún valor! Podría usarse para generar una secuencia de números o incrementar un contador. El usozd
repetido (digamos, al comienzo de una macro) podría permitir probar un cálculo en cada número natural o entero en orden ascendente.fuente
z
esto y aquello antes, pero nunca se me ocurrió usarlo como un truco de un mostrador ... Excelente ...Los dígitos
A
aF
se pueden usar en sustitución de los números del 10 al 15. Sin embargo, aún deben tratarse eficazmente como dígitos de base 10 (suponiendo que la base de entrada sea 10) cuando se encuentran en diferentes lugares. En otras palabras, con la base de entrada 10FF
no representaría 255, representaría(15 * 10) + 15
o 165.De hecho esto funciona para todos los dígitos
0
queF
en cualquier base de entrada2
a16
. Entonces, si la base de entrada es 5, entonces26E
sería(2 * 5^2) + (6 * 5) + 14
, o 94.Tenga en cuenta que este comportamiento está vigente para las fuentes GNU no modificadas. Sin embargo, como señala @SophiaLechner, las distribuciones basadas en RedHat parecen usar bc-1.06-dc_ibase.patch que cambia este comportamiento para que los dígitos> = ibase se traten como
ibase - 1
, independientemente de su valor real. Tenga en cuenta que el TIOdc
parece no tener bc-1.06-dc_ibase.patch (a pesar de que es Fedora 28 ¯_ (ツ) _ / ¯).fuente
FF
representa99
, en la base de entrada 526E
es lo mismo que244
, es decir, la base 1074
.dc
versión está ejecutando? Estoy usando GNU dc 1.4.1 en ubuntu y GNU dc 1.3 en MacOSFFp
salidas99
en 1.3.95. ¿Podrías comprobar esto en tu versión de MacOS, entonces?Al inicializar una macro de
función(usaremosF
) que desea ejecutar de inmediato, use algo así como endsFx
lugar desFlFx
. Lo mismo funciona para las variables: endsa
lugar desala
.Si necesita hacer otras cosas entre el almacenamiento y la carga (por ejemplo,
sa[other stuff]la
), considere si lo anterior es viable: si deja un valor en la pila antes de las otras operaciones, ¿volverá a estar en la parte superior al final? de esas operaciones?fuente
Acabo de descubrir esto por accidente. Sin embargo, otra manera de generar un cero:
_
._
es una señal a dc de que los siguientes dígitos son un número negativo. Ejemplo:Pero, ¿y si no lo seguimos con un número?
Esto funciona cuando el siguiente carácter no en blanco después del guión bajo no es un dígito. Si un dígito lo sigue, incluso después de una nueva línea, se interpreta como un signo negativo.
fuente
Si el contenido de toda la pila necesita imprimirse al final de un programa, se podría utilizar un bucle macro recursivo para lograr esto. Sin embargo, es mucho más corto simplemente usar el
f
comando.fuente
dc
lee la entrada de una línea a la vez. Si necesita leer en varios elementos, hacerlo uno por línea requiere un?
para cada línea para leer, o un engorroso macro loop. En cambio, si todos los elementos de entrada pueden colocarse en una línea separada por espacios, entonces un solo?
leerá todos los elementos de entrada, empujando cada uno a la pila.Por ejemplo en
seq 10 | dc -e'?f'
,seq
salidas enteros 1-10, uno por línea. el?
solo leerá el primero1
que saldrá cuando sef
descargue toda la pila. Sin embargoseq 10 | tr '\n' ' ' | dc -e'?f'
, entr
hace que la entrada integre todo el espacio separado. En este caso?
, leerá todos los enteros de la línea de una vez y losf
generará todos.fuente
Si un operador está restringido desde la fuente, cree uno nuevo con
a
Algo que me ha resultado útil un par de veces ahora es evitar usar un operador específico presionando el valor ASCII del operador, usarlo
a
para convertirlo en una cadena ys
torsionarlo en un registro para ejecutarlo como macro más adelante en. Por ejemplo, necesito hacer una división, pero no puedo o intento evitar usar el personaje/
. Puedo, en cambio, hacerlo47asd
y luego en el futuro cuando necesito dividir 16 por 416 4 ldx
,.s
ese que deben ser fijados por algo.fuente
Evitar espacios en blanco
Evitar el espacio en blanco surge en bastantes desafíos, y generalmente es fácil
dc
. Aparte de las cadenas, la única vez muy específico que hace necesario un espacio en blanco es al empujar varios números en una fila:1 2 3
. Si esto debe evitarse:1[]x2[]x3[]x
.35asn
y ejecutar que en el medio:1lnx2lnx3lnx
.fuente
dc: ',' (054) unimplemented
advertencias.