DC에서의 골프 팁


18

DC 에서 골프를 치기 위해 어떤 일반적인 팁이 있습니까?

dc는 C 언어 이전의 UNIX / Linux 용 계산기 유틸리티입니다. DC 프로그램 (계산?)을 더 짧게 만드는 방법에 관심이 있습니다. 최소한 dc에만 해당되는 일반적인 적용될 수있는 아이디어를 찾고 있습니다 (예 : 주석 제거는 도움이되지 않습니다)

답변 당 하나의 팁을 게시하십시오.


7
대신 Marvel을 사용하십시오.
Magic Octopus Urn

답변:


6

if-then-else 문

조건을 확인하고 싶다고 가정 해 보자 a==b( 각각 명명 된 레지스터에 저장 ab저장).

편집하다:
[         # Everything is wrapped in one big macro
  [         # An inner macro for our *then* part
              # <-- Stuff to execute if a==b here
  2Q          # Then quit the inner and outer macro
]sE       # `E' is for Execution register ;)
la lb =E  # if a==b, execute E
          # if E is executed, it will quit the whole macro, so the rest is never reached:
          # <-- Stuff to execute if a!=b here
]x        # End macro; Execute

하자 (foo)응축의 목적에 대한 자리가 될 :

[[(then)2Q]sE(condition)E(else)]x

이것이 가능한 가장 컴팩트 한 if 문인지 확인하십시오 ( 여기에도 나와 있습니다 ).


1
아마도 [[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI f시작일까요? tehn 및 기타 조치는 스택에 있으며 " If"매크로는이를 교환하고 조건부로 계산됩니다. 그런 다음 스택 맨을 실행하고 사용하지 않는 매크로를 삭제하여 스택을 정리합니다. 2 4비교할 예제 데이터 일뿐입니다. 대안 [x]sI가독성을 고려하면 부분은, 비교로 이동 할 수 있습니다 [[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f. f스택 나중에 깨끗 TAT 예에서 그냥 .. 제시해야한다

1
Dc에 대한 Rosetta Code의 페이지 는 3 가지 맛을 언급 dc했으며 이것이 OpenBSD dcif-then-else구조를 본 첫 페이지였습니다 . dc모든 주요 운영 체제에 대해 3 가지 맛을 모두 갖춘 팬 번들이 필요하다고 생각 합니다 ... o :-) ... if-then-else위의 제안 dcr명령 이 없기 때문에 원본에서 작동하지 않습니다 ... :-(

1
무엇에 대해 : [[(if)2Q]si(condition)i(else)]x- 당신이 할 수 그래서, 매크로에서 전체를 포장하고, 그 안에 다른 매크로 내부의 경우-부분 2Qelse 블록 부분에 도달하기 전에 모든 일에서 당신의 방법을 UIT. 당신이 원하는 경우에 따라서 경우 1 == 1 다음 한 다른 인쇄 (2) 인쇄 , 그것은 것 1[[1P2Q]si1=i2P]x내가 바로 여기 그리고 지금 직류에 액세스 할 수 없습니다로 (검증되지 않은. 또한 반드시 내가 여기 전에 대답이 트릭을 수행 있었다 하지만 찾을 수 없습니다)
daniero

그래, 나는 수학을했다, 나의 제안은 더 짧다. 그것의 공백 같은 예와 "표기법"으로하고, 제거 [/*else*/]sE[[/*then*/]sE]sIlalb=IlEx[[/*then*/2Q]sIlalb=I/*else*/]x6의 차이를 바이트 -. 아직 검증되지 않은 상점 : P
daniero

1
잘 했어, @daniero! 시간이 있으면 게시물을 업데이트하거나 원하는 경우 게시 할 수 있습니다.
Joe

5

당신은 입력을 저장할 수 있습니다 d

사용하여 d여전히 사용할 수있는 동안 서비스 약관 (스택 맨)을 복제하는, 당신은 나중에 사용하기 위해 길에서 입력을 이동할 수 있습니다.


트윗 담아 가기 감사!
Rɪᴋᴇʀ

5

배열

초보자에게는 골치 거리이지만 dc배열을 제공합니다. 그들은 다음과 같이 작동합니다 :

value index :a    # store `value' in array linked to top of stack `a', with index `index'
      index ;a    # push a[index] on (main) stack

평소와 같이 첫 번째 요소는 인덱스 0을 갖습니다. 배열은 SUDSI sequence 에서처럼 특히 카운터와 결합하여 시퀀스로 작업 할 때 유용 할 수 있습니다 . 배열은 환경을 파괴하지 않고 특정 요소를 선택하려는 경우 수행해야하는 수 셔플 링 양 (및 카운터 및 비교 수)을 줄일 수 있습니다. 예를 들어, 많은 수의 배열을 배열로 이동하려면 z(스택 깊이)를 사용하거나 z 1-인덱스로 요소를 저장하고 z == 0자체 종료 여부 를 확인 하는 재귀 함수를 작성할 수 있습니다.

[z 1- :a z 0 !=F]dsFx    # or I could just write such a function for you :)

다음 사항에 유의하십시오.

  • 배열은 명명 된 스택의 인스턴스와 연결됩니다. 연관된 배열이있는 스택에서 새 값을 푸시하면 해당 배열도 "밀어지고" "새"배열이 대신 사용됩니다. 명명 된 스택의 해당 값을 사용할 수있을 때까지 (즉, 스택 맨 위에서) 이전 배열을 사용할 수 없습니다. 이것은 저 너머의 좋은 애니메이션으로 더 잘 설명되는 복잡한 개념입니다.
  • 실제로 이름이 지정된 해당 레지스터로 값을 푸시하지 않고 이름이 지정된 배열에 항목을 저장할 수 있습니다 . 그러나 이렇게 하면 나머지 세션 동안 해당 이름으로 스택 / 레지스터에 액세스 할 수 없습니다 . dc충돌합니다.
  • 명명 된 스택에서 값을 가져 오면 해당 배열의 모든 값 (경고, 보호 기능 없음)이 손실됩니다. 방금 사라졌습니다 (유용 할 수도 있습니다).

DC 팁과 함께 잘 했어요!
Rɪᴋᴇʀ

dc최근에 업데이트되었을 수 있으며 충돌과 관련하여 배열 동작이 약간 변경되었을 수 있습니다. 지금도 확인할 수는 없지만 Linux에서 마지막으로 사용했을 때 뭔가 다른 것으로 생각합니다.
Joe

1
설정되지 않은 배열에서 인덱스를 읽으려고하면 0이 아니라 오류가 발생합니다. 매우 유용 할 수 있지만 잠재적으로 배열에 0을 넣는 경우 유의해야 할 가치가 있습니다 ... 색인이 터치되었는지 테스트하는 다른 방법이 필요합니다.
brhfl

5

조건부 / 매크로 대신 0에서 n의 제곱

때때로 당신은 뭔가해야 할 수도 있습니다 삼항 조건을 :

A == B ? C : D;

이를 처리하는 좋은 방법은 @ Joe 's answer에 설명되어 있습니다. 그러나 우리는 더 잘할 수 있습니다.

0AB-^E*C+

여기서 E는 D-C입니다.

이것은 두 값의 차이의 거듭 제곱으로 0을 올림으로써 동등성을 테스트합니다. 같으면 1, 그렇지 않으면 0이됩니다. 나머지는 1 또는 0을 값 C 또는 D로 스케일링합니다. 이것은 n! = 1에 대해 dc0 0 = 1 및 0 n = 0을 주기 때문에 작동 합니다 .


4

때때로 스택에서 숫자를 폐기해야합니다. 이를 수행하는 한 가지 방법은 변수를 사용하지 않는 변수, 즉 st. 그러나 어떤 상황에서는 더 이상 숫자 입력이 없을 때 입력 기준 또는 정밀도가 다른 곳에서 수행 할 작업이 더 이상없는 경우 정밀도 지정자에 두 개의 다른 위치에이를 표시 할 수 있습니다. 전자의 경우을 사용하십시오 i. 후자의 경우을 사용하십시오 k.


숫자 출력이 중요하지 않은 경우 o에도 사용할 수 있습니다. 이러한 것들 중 하나가 중요하지 않은 경우, 그들은 스토리지뿐만 아니라 단순한 폐기로 사용할 수 있습니다 - I/ K/이 O각각 그들을 기억, 이상 바이트 저장 sa/ la등 유효한 값 AFAIK을 : i2-16; k음이 아닌 정수; o1보다 큰 정수
brhfl

4

길이 계산 : Z, X, 및z

ZToS를 팝하고 숫자 인 경우 자릿수 (10 진수) 또는 문자열 인 경우 문자 수를 푸시합니다. 이는 결과 길이 (버퍼링 출력)를 감지하거나 문자열 길이를 계산하는 데 유용 할 수 있습니다. 숫자 Z의 경우 정수 부분과 분수 부분의 결합 된 길이를 푸시합니다.

XToS를 팝하고 숫자의 소수 부분에서 자릿수를 푸시합니다. ToS가 문자열 인 0경우 푸시됩니다.

숫자의 정수 부분에서 자릿수를 찾으려면을 사용할 수 있습니다 dZrX-. 기본값에서 정밀도를 변경하지 않은 경우를 k==0사용하는 1/Z것이 더 짧지 만 작업 후 0이 아닌 특정 정밀도를 유지해야한다고 가정하십시오 Kr0k1/Zrk.

z스택의 항목 수를 푸시합니다. 내가 가장 좋아하는 명령 중 하나이며 실제로 값을 표시하지 않습니다! 일련의 숫자를 생성하거나 카운터를 증가시키는 데 사용될 수 있습니다. zd매크로를 시작할 때 반복적으로 사용하면 각 자연수 또는 정수에 대한 계산 을 오름차순으로 테스트 할 수 있습니다.


사용하고 z이과 그 전에,하지만 카운터의 해킹 ... 우수 ...로 사용하는 나에게 발생하지 않았다
brhfl

4

숫자 AF들이 아직도 여행자 효과적으로 10 개 자리를 처리해야하지만 (15)에 숫자 10을 대신하여 사용될 수있다 (입력 기본 가정은 10이다) 때 다른 장소이다. 즉, 입력 기준이 10 FF인 경우 255를 나타내지 (15 * 10) + 15않거나 165를 나타냅니다 .

사실이 모든 숫자 작동 0으로 F모든 입력 기지 216. 입력 염기가 5이면 그렇다면, 26E(2 * 5^2) + (6 * 5) + 14, 또는 94.

이 동작은 수정되지 않은 GNU 소스에 적용됩니다. 그러나 @SophiaLechner가 지적했듯이 RedHat 기반 배포판은 bc-1.06-dc_ibase.patch 를 사용 하여이 동작을 변경 ibase - 1하여 실제 값에 관계없이 숫자> = ibase 가로 취급됩니다 . TIO dc 는 bc-1.06-dc_ibase.patch를 가지고 있지 않습니다 (Fedora 28 ¯_ (ツ) _ / ¯).


입력베이스 위의 한 자리 숫자는 원하는대로 해석되지만 리터럴에 여러 자리 숫자 또는 소수점이있는 경우 잘못된 자리 숫자는 (베이스 1)로 해석됩니다. 따라서 입력베이스 (10) FF는를 나타내고 99, 입력베이스 (5) 26E244베이스 (10) 와 동일하다 74.
소피아 레크 너

@SophiaLechner 확실합니까? tio.run/##S0n@/9/QIJ/L0CCTy82tgMs0k8vIzLXg/38A 어떤 dc버전을 실행하고 있습니까? 우분투에서 GNU dc 1.4.1을 사용하고 MacOS에서 GNU dc 1.3을 사용하고 있습니다
Digital Trauma

흥미 롭군 Red Hat에서 1.3.95를 실행하고 있으며 샘플 프로그램은 다음과 같습니다. [slechner @ XXX] $ dc -e '10o 10i FFp 5i 26Ep'99 74 [slechner @ XXX] $ dc --version dc (GNU bc 1.06 .95) 1.3.95
소피아

Argh ... 코멘트에서 코드 블록을 작동시킬 수 없습니다. 요점은 1.3.95로 FFp출력 99된다는 것입니다. 그렇다면 MacOS 버전에서이를 확인할 수 있습니까?
소피아 레크 너

1
확실한 것! 모든 연구에 감사드립니다.
Sophia Lechner

2

초기화하는 경우 기능 매크로를 (우리가 사용할 것이다 F당신이 즉시 같이 사용 무언가를 실행하려면이) dsFx보다는를 sFlFx. 같은 변수 작품 : dsa보다는 sala.

저장과 로딩 사이에 다른 작업을 수행 해야하는 경우 (예 sa[other stuff]la:) 위의 실행 가능성을 고려하십시오. 다른 작업 전에 스택에 값을 남겨두면 끝까지 맨 위로 돌아갑니다 그 작업 중?


2

우연히 이것을 발견했습니다. 0을 생성하는 또 다른 방법 : _.

_다음 숫자가 음수라는 dc 신호입니다. 예:

_3 # pushes -3

그러나 우리가 숫자를 따르지 않으면 어떻게 될까요?

_ # pushes 0...sometimes

밑줄 뒤의 다음 비 공백 문자가 숫자가 아닌 경우에 작동합니다. 줄 바꿈 후에도 숫자가 뒤에 오면 음수로 해석됩니다.

c4 5_6  # -6,5,4
c4 5_ 6 # -6,5,4
c4 5_
6       # -6,5,4 # still a negative sign since the next thing it sees is a digit
c4 5_z  #  3,0,5,4 # if it's followed by a non-digit, it's a 0
c4 5_p6 #  6,0,5,4
c4 _*   #  0 # 4*0=0

1

프로그램이 끝날 때 전체 스택의 내용을 인쇄해야하는 경우 재귀 매크로 루프를 사용하여이를 달성 할 수 있습니다. 그러나 단순히 f명령을 사용하는 것이 훨씬 짧습니다 .


1

dc한 번에 한 줄씩 입력을 읽습니다. 여러 항목을 읽어야하는 경우 한 줄에 하나씩 수행하려면 ?모든 줄을 읽거나 번거로운 매크로 루프가 필요합니다. 대신 모든 입력 항목을 공백으로 구분 된 한 줄에 넣을 수 있으면 단일 ?항목이 모든 입력 항목을 읽고 각 항목을 스택으로 밀어 넣습니다.

예를 들어에서 seq 10 | dc -e'?f', seq라인 당 하나씩 정수 1-10을 출력합니다. 는 전체 스택을 덤프 할 때 출력되는 ?첫 번째 1를 읽습니다 f. 그러나에서 seq 10 | tr '\n' ' ' | dc -e'?f'상기는 tr모든 공간이 분리 된 정수 입력한다. 이 경우에는 ?행에서 모든 정수를 한 번에 읽고 모두 f출력합니다.


1

운영자가 소스에서 제한되는 경우 다음을 사용하여 새 운영자를 만드십시오. a

몇 번이나 나에게 유용한 것은 이제 연산자의 ASCII 값을 푸시하고 a문자열로 변환하는 데 사용 하고 s나중에 매크로로 실행되도록 레지스터에서이 연산자를 사용하여 특정 연산자를 사용하지 않는 것입니다 의 위에. 예를 들어, 나눗셈을해야하지만 캐릭터 사용을 금지하거나 피하려고합니다 /. 대신 47asd16을 4로 나누어야 할 때 대신 할 수 있습니다 16 4 ldx.

  • 이것은 단일 문자 연산자 (문자열을 만들 수 없음)에서만 작동하며 이와 같은 명령 s은 무언가로 접미사가 필요 하지 않습니다 .
  • 이것은 꽤 많은 바이트를 추가하므로 특정 문자를 피하거나 점수 보너스를 얻는 경우에만 적합합니다.

1

공백 피하기

공백을 피하는 것은 상당히 어려운 문제이며 일반적으로 쉽습니다 dc. 문자열 외에도 공백이 필요한 매우 구체적인 시간은 여러 개의 숫자를 연속으로 밀어 넣는 경우입니다 1 2 3. 이것을 피해야하는 경우 :

  • 다음 사이에 빈 매크로를 실행하십시오 1[]x2[]x3[]x.
  • 대괄호가 테이블에서 벗어난 경우 매크로의 NOP를 미리 저장하고 다음 사이에 35asn실행 하십시오1lnx2lnx3lnx .

dc: ',' (054) unimplemented경고를 할 의향이 있다면 쉼표로 구분 된 숫자를 사용할 수도 있습니다 .
디지털 외상

나는 그것을 생각하지 않았다 – 아마도 이것은 명령으로 해석되지 않는 주어진 토큰에 적용된다. .. 흥미있는…
brhfl
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.