소개
어린 시절에 더하기와 곱하기를 마스터했다고 생각하면 누군가가 와서 다음과 같이 알려줍니다.
a * b + c = (a * b) + c! = a * (b + c),
이전에 배운 것만 큼 간단하거나 선형 적이 지 않았습니다. 작업 순서 라는 것이 있다는 것을 알게 됩니다 . 이것은 괄호가 모든 것을 방해하지 않고 일정 수준의 일관성과 표현을 유지하는 매우 중요한 방법입니다.
일반적인 스토리
어느 날, 당신은 거리에서 공황의 소리에 일어납니다. ” 2560 ” 이라는 이름의 극단주의 단체 (도덕적 인 육십이를 가진 “작전 조직에 대한 조직”의 짧은)는 그들의 사악한 방법을 사용하여 세계의 모든 핵무기를 통제했습니다. 그들은 전체 행성 인질을 보유하고 있으며 간단한 요구가 있습니다. 수용 된 순서를 바꾸거나 박멸하십시오 (괄호는 우선 순위를 유지해야 함). 새로운 시스템을 PSADME (괄호, 뺄셈 / 더하기, 나누기 / 곱하기, 지수)라고하며 식은 오른쪽에서 왼쪽으로 평가됩니다.
a - b - c = a - (b - c) = a + c - b
일이 지나고 전환이 진행 중입니다. 수학자와 물리학 자들이 모두 방정식을 다시 작성하는 데 바쁘지만 컴퓨터 과학자들은 컴퓨터가 수학 표현을 해석하는 방식을 바꾸는 작업에 직면하고 있습니다. 우연히하고, 당신이 무작위로 선택됩니다 – 당신은 원인의 목표는 많은 새로운 글로벌 군주에 대한 고통으로 비밀 반군 프로그램 그룹에 속한 2560 및 벤치 마크 계산 프로그램을 생산하는 임무.
당신의 임무
(숫자) 수학 표현식을 입력으로 사용하고 PSADME 를 연산 순서로 사용하여 표현식을 계산 하고 결과를 출력 하는 프로그램 (또는 함수)을 작성하십시오 . 식은 오른쪽에서 왼쪽으로 평가되므로
간단히하기 위해 제공된 모든 숫자는 정수가되고 계산은 정수 결과를 생성합니다.
규칙과 득점
- 프로그램은 최대 128 자 길이의 입력을 허용해야합니다. 언어 / 플랫폼의 최대 입력 길이가 낮은 경우 허용 가능한 변명입니다.
- 표준 허점은 금지되어 있습니다.
- 당첨 코드는 11 월 18 일 (이 게시물 날짜부터 4 주)에 선택됩니다.
- 골프에 적합하지 않은 코드를 게시하십시오. 이것은 재미에 관한 것입니다. 이 작업을 수행하는 데 흥미로운 방법이 있지만 직접 골프를 칠 수 없거나 방법의 특성에 따라 게시 할 수 있다면 어쨌든 게시 할 수 있습니다.
평소와 같이 당첨 코드는 바이트 수가 가장 적고 엔터테인먼트 가치 보너스가있는 코드입니다.
- 제공된 표현식에서 문자를 사용하지 않으려면 -5 : + , – , ( , ) , ^ , * , /
- -5 계산 방법이 명확하지 않은 경우 (클럭 또는 불필요한 루프 사용) 표준 컴퓨터에서 계산하는 데 5 분 (10 분 이하)이 소요됩니다. 목표는 당신이되지 않는다는 새로운 군주를 설득하는 노력 운명의 자신의 계산을 방해 할 수 있습니다.
- -(5 + N) 2560의 멤버에 대한 직접적인 공격 메시지 (길이 N, 선행 / 트레일 링 공백 제외)의 경우 코드 내에서 명확하게 볼 수있는 2560 멤버에 대한 이유와 함께 우스운 설명 그곳에. 코드가 제거되면 코드 가 올바르게 작동 하지 않아야 합니다. 예, 엔터테인먼트 가치에 대한 무료 포인트.
예와 설명
[program] 2 - 2 - 2
2
2-(2-2) = 2
[program] (2 + 2 * 3 + 3) / 3 + 3
4
(4 * 6) / (3 + 3) = 4
[program] 3 + 2 + 1 ^ 3
216
(3 + 2 + 1) ^ 3 = 216
[program] -5^2
25
(-5) ^ 2 = 25
[program] 32 / 8 * 3 - 1
2
32 / (8 * (3-1)) = 32/16 = 2
답변
하스켈, 134 바이트
import qualified Prelude as P
infixl 6 ^
(^)=(P.^)
infixr 8 +
(+)=(P.+)
infixr 8 -
(-)=(P.-)
infixr 7 /
(/)=P.div
infixr 7 *
(*)=(P.*)
새로운 연산자와 우선 순위를 사용하여 수학 연산자를 재정의합니다. 지금:
*Main> 32 / 8 * 3 - 1
2
답변
exec 확장자를 가진 GNU sed -r, 398
s@ *\^ *@ ** @
:
s@\((-?[0-9]+)\)@\1@
t
s@(-?[0-9]+ - )+(-?[0-9]+ - -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [-+] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ / )+(-?[0-9]+ / -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [*/] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ \*\* )+(-?[0-9]+ \*\* -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ \*\* -?[0-9]+)(.*)@bash -c 'echo \1$[\3]\4'@e
t
특히 짧지는 않지만 작업을 완료합니다.
sed는 우선 순위를 파싱해도 괜찮지 만 산술을하지 않습니다. 따라서 우리는 s
명령에 GNU sed exec 확장을 사용하여 필요한 산술을 쉘에 아웃소싱합니다.
^
앞뒤에 정확히 하나의 공백이 있는 것을 제외하고 모든 연산자를 가정합니다 .
테스트 출력 :
$ cat psadme.txt
2 - 2 - 2
(2 + 2 * 3 + 3) / 3 + 3
3 + 2 + 1 ^ 3
-5^2
32 / 8 * 3 - 1
$ sed -rf psadme.sed psadme.txt
2
4
216
25
2
$
답변
자바 스크립트 (ES6) 287 (300)
편집 코드 조각의 끝 부분에 대한 자세한 설명을 추가 – 버그 수정 (단지 오타는 6 4 있었어야)
편집 2 다른 도전에 대한 개선 사항을 발견했습니다
그러나 약간의 차이가 있지만 동일한 파서의 또 다른 포팅. (비교 이 )
f=(x,W=[],Q=['('],z=1,h=p=>'+-*/^^))('.indexOf(p)>>1,C=n=>{for(;h(q=Q.pop())<h(n);W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))a=W.pop(b=W.pop());z&&Q.push(q,n)})=>((x+')').replace(/\d+|\S/g,t=>t>'('?t>'('?~h(t)?z&&t=='-'?z=-z:C(t,z=1):(W.push(z*t),z=0):C(t,z=0):(Q.push(t),z=1)),W.pop())
// More readable
U=(x,W=[],Q=['('],z=1,
h=p=>'+-*/^^))('.indexOf(p)>>1,
C=n=>{
for(;h(q=Q.pop())<h(n);
W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))
a=W.pop(b=W.pop());
z&&Q.push(q,n)
}
)=>(
(x+')')
.replace(/\d+|\S/g,t=>
t>'('
?t>'('
?~h(t)
?z&&t=='-'?z=-z:C(t,z=1)
:(W.push(z*t),z=0)
:C(t,z=0)
:(Q.push(t),z=1)
),
W.pop()
)
// TEST
console.log=(...x)=>O.innerHTML+=x.join` `+'\n'
console.log(f('1 - 3 + 4')) // -6
console.log(f('2-2-2')) // 2
console.log(f('(2 + 2 * 3 + 3) / 3 + 3')) // 4
console.log(f('3 + 2 + 1 ^ 3')) // 216
console.log(f('-5^2')) // 25
console.log(f('32 / 8 * 3 - 1')) // 2
// Explained
X=(x,W=[],Q=['('],z=1,
h=p=> // operator priority '+-:1, */:3, ^:5, ):7, (:9. If an operand then -1
'+-*/^^))('.indexOf(p)>>1,
C=n=>{ // Evaluate operators present on stack if they have upper priority, then push new operator on stack
//console.log('Operand '+n)
while( h(q = Q.pop()) < h(n) ) // pop operator from op stack and compare priority with current
{
// Pop operands from stack and push result
b = W.pop();
a = W.pop();
r = q=='^' ? Math.pow(a,b) : eval('a'+q+'b')
// console.log('Evaluate '+a+q+b+'='+r)
W.push(r);
}
// if z == 0 do nothing, because the current operands are '(' and ')' that must be discarded
// else Push again the last operator popped and the current one
z && Q.push(q, n) //
}
)=>(
(x+')')
.replace(/[\d.]+|\S/g,t=> {
//console.log('Q:'+Q,'W:'+W,'T:'+t,'U:'+h(t),'Z:'+z), // display status
if (t == '(')
{ // open parenthesis
z = 1
Q.push(t) // push a operator, its the highest priority
}
else if (t == ')')
{ //close parenthesis
z = 0
C(t)
}
else if (h(t) < 0)
{ // operand
W.push(z*t) // push operand with right sign
z = 0 // set z to 0 to mark that we just pushed an operand, so next '-' (if present) is a binary operator
}
else
{ // operator
if (z && t=='-') // the minus is an unary operator (the only unary operator allowed is '-', '+' will not work)
z =-z // change the sign
else
z = 1, // no unary minus
C(t)
}
}),
W.pop() // return the value at top of operand stack
)
<pre id=O></pre>