1. Approach ¶
๋งจ ์ฒ์์ ๋ฌธ์ ๋ฅผ ์ฝ๊ณ ๋๋ต ์ฐ์ต์ฅ์ ๋ฌธ์ ์์ ๊ฐ ๋ณ์๋ค์ด ๋ ๋งํ ๋ถ๋ถ๋ค์ ๋ณด์๋ค. ์ผ๋จ ์์๋ค์ ํฉ์ด๋ผ ํ๊ณ , 4์๋ฆฌ์ ํฉ์ด๋ผ๊ณ ํ๋ค. ๋๋ต pseudo code ๋ฅผ ๋ค์์ ๊ฐ์ด ์์ฑํด๋ณด์๋ค.
~cpp for eachGenNumberFour in GenNumbersFour isAllPrimeNumber: print eachGenNumberFour return print "impossible" GenNumbersFour = ํฉ์ด x ์ธ ์ ์กฐํฉ๋ฆฌ์คํธ
ํฉ์ด x ์ธ ์ ์กฐํฉ๋ฆฌ์คํธ์ ๋ํด ์ด๋ป๊ฒ ๊ตฌํ ๊น ๊ถ๋ฆฌํ๋์ค, ์์๋ฆฌ์คํธ๋ฅผ ๋จผ์ ๋ง๋ค๊ณ ์์๋ฆฌ์คํธ์์ 4๊ฐ๋ฅผ ๊ณจ๋ผ์ ํฉ์ ๊ตฌํ ๊ฒฐ๊ณผ๊ฐ n ์ธ์ง๋ฅผ ๋น๊ตํ๋ ๋ฐฉ๋ฒ์ด ๋ ๋นจ๋ฆฌ ๊ตฌํํ ์ ์๊ฒ ๊ตฌ๋๋ผ๋ ์๊ฐ์ด ๋ค์๋ค. ์ด์ ๋ํด์ TDD๋ก ์งํ.
~cpp class PrimeNumberList: def __init__(self,aNum): self.size = aNum self.resultTable = [] self.createList() def createList(self): for i in range(2,self.size+1): if self.isPrimeNumber(i): self.resultTable.append(i) def isPrimeNumber(self,aNum): for eachValue in self.resultTable: if aNum % eachValue == 0: return False return True def getList(self): return self.resultTable class PrimeNumberTest(unittest.TestCase): def testPrimeNumber(self): self.assertEquals([2,], PrimeNumberList(2).getList()) self.assertEquals([2,3], PrimeNumberList(3).getList()) self.assertEquals([2,3,5], PrimeNumberList(5).getList()) self.assertEquals([2,3,5,7,11], PrimeNumberList(12).getList()) self.assertEquals([2,3,5,7,11,13,17,19], PrimeNumberList(20).getList())๊ทธ๋ฆฌ๊ณ ์์๋ฆฌ์คํธ๋ก๋ถํฐ 4๊ฐ๋ฅผ ๊ตฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์๊ฐํ๋ค. ๋งจ ์ฒ์์ ๋ํด์๋ ์ค๋ณต์ ํ์ฉํ๋ฉด ์๋๋ ์ค ์๊ณ ๊ตฌํํ์๋ค. ๊ทธ๋ฌ๋ค๊ฐ ๋ฌธ์ ์์ ์ค๋ณต์ ํ์ฉํ๋ค๋ ์ฌ์ค์ ์๊ณ ๋ค์ ๊ตฌํ.
~cpp def selectionFour(aList): sizeOfList = len(aList) for i in range(sizeOfList): for j in range(sizeOfList): for k in range(sizeOfList): for l in range(sizeOfList): yield [aList[i],aList[j],aList[k],aList[l]]
2. full source ¶
~cpp from __future__ import generators import psyco class PrimeNumberList: def __init__(self,aNum): self.size = aNum self.resultTable = [] self.createList() def createList(self): for i in range(2,self.size+1): if self.isPrimeNumber(i): self.resultTable.append(i) def isPrimeNumber(self,aNum): for eachValue in self.resultTable: if aNum % eachValue == 0: return False return True def getList(self): return self.resultTable def selectionFour(aList): sizeOfList = len(aList) for i in range(sizeOfList): for j in range(sizeOfList): for k in range(sizeOfList): for l in range(sizeOfList): yield [aList[i],aList[j],aList[k],aList[l]] def main(): n = int(raw_input('input number : ')) primeNumberList = PrimeNumberList(n) for eachPrimeNumberSeq in selectionFour(primeNumberList.getList()): if sum(eachPrimeNumberSeq) == n: print eachPrimeNumberSeq return print "Impossible" if __name__=="__main__": #unittest.main(argv=('','-v')) psyco.full() main()
3. ๋ฌธ์ ์ - 4์ด ์ด๋ด์ ๋ต์ด ๋์ค์ง ์๋๋ค. ¶
์คํ์ 10000000 ๊ฐ ๋ด์์ 4์ด ์ด๋ด์ ๋ต์ด ๋์์ผ ํ๋ค. ์ด์ ๋ํด์ ํ์ฌ์ ๋ณ๋ชฉ์ง์ ์ ๋ํด profiling ์ ํด ๋ณด์๋ค.
PrimeNumber๋ฅผ ์ฐธ๊ณ , ์ต์ ํ๋ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์์ ํ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ญ์ psyco ๋ฅผ ์ด์ฉํ์๋ค. ๊ทธ ๊ฒฐ๊ณผ, 10000000 ๊ธฐ์ค 10์ด. ๊ธฐ์กด ์๊ณ ๋ฆฌ์ฆ์ ๊ฒฝ์ฐ 50000๋ฒ ๊ธฐ์ค 24์ด ์ด์.
~cpp C:\WINDOWS\system32\cmd.exe /c python SummationOfFourPrimes.py input number : 10000 [2, 2, 23, 9973] 21065 function calls in 6.387 CPU seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 1 0.075 0.075 1.201 1.201 summationoffourprimes.py:13(createList) 0 0.000 0.000 profile:0(profiler) 1 5.103 5.103 6.387 6.387 summationoffourprimes.py:88(main) 1 0.000 0.000 1.201 1.201 summationoffourprimes.py:8(__init__) 9999 1.126 0.000 1.126 0.000 summationoffourprimes.py:18(isPrimeNumber) 1 0.000 0.000 0.000 0.000 summationoffourprimes.py:24(getList) 11061 0.083 0.000 0.083 0.000 summationoffourprimes.py:79(selectionFour) 1 0.000 0.000 6.387 6.387 <string>:1(?)
~cpp C:\WINDOWS\system32\cmd.exe /c python SummationOfFourPrimes.py input number : 50000 [2, 2, 3, 49993] 60269 function calls in 24.926 CPU seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 1 0.428 0.428 19.348 19.348 summationoffourprimes.py:13(createList) 0 0.000 0.000 profile:0(profiler) 1 5.492 5.492 24.923 24.923 summationoffourprimes.py:88(main) 1 0.000 0.000 19.348 19.348 summationoffourprimes.py:8(__init__) 49999 18.920 0.000 18.920 0.000 summationoffourprimes.py:18(isPrimeNumber) 1 0.000 0.000 0.000 0.000 summationoffourprimes.py:24(getList) 10265 0.083 0.000 0.083 0.000 summationoffourprimes.py:79(selectionFour) 1 0.003 0.003 24.926 24.926 <string>:1(?) Hit any key to close this window...๋๋ถ๋ถ์ ์๊ฐ์ ์์ํ ์ด๋ธ์ ์์ฑํ๋ ๋ถ๋ถ์ด ๋๋ค. ๊ทธ๋์ ์ด ๋ถ๋ถ์ ๋ํด์

~cpp C:\WINDOWS\system32\cmd.exe /c python SummationOfFourPrimes.py input number : 10000 [2, 2, 23, 9973] 11067 function calls in 5.417 CPU seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 0.000 0.000 summationoffourprimes.py:48(getList) 1 0.000 0.000 5.417 5.417 <string>:1(?) 1 0.000 0.000 0.013 0.013 summationoffourprimes.py:36(createList) 1 0.000 0.000 0.013 0.013 summationoffourprimes.py:31(__init__) 11061 0.094 0.000 0.094 0.000 summationoffourprimes.py:103(selectionFour) 1 5.309 5.309 5.416 5.416 summationoffourprimes.py:112(main) 1 0.013 0.013 0.013 0.013 summationoffourprimes.py:8(prime2) Hit any key to close this window...
~cpp C:\WINDOWS\system32\cmd.exe /c python SummationOfFourPrimes.py input number : 50000 [2, 2, 3, 49993] 10271 function calls in 7.878 CPU seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 0.000 0.000 summationoffourprimes.py:48(getList) 1 0.002 0.002 7.878 7.878 <string>:1(?) 1 0.002 0.002 0.090 0.090 summationoffourprimes.py:36(createList) 1 0.000 0.000 0.090 0.090 summationoffourprimes.py:31(__init__) 10265 0.098 0.000 0.098 0.000 summationoffourprimes.py:103(selectionFour) 1 7.688 7.688 7.876 7.876 summationoffourprimes.py:112(main) 1 0.088 0.088 0.088 0.088 summationoffourprimes.py:8(prime2) Hit any key to close this window...์ต์ ํ ์ดํ 50000๋ฒ ๊ธฐ์ค์ผ๋ก๋ ๋ณ๋ชฉ์ ๋ํ ๋ณ๋ณ๋ ฅ์ด ์๋ค.
~cpp C:\WINDOWS\system32\cmd.exe /c python SummationOfFourPrimes.py input number : 1000000 [2, 2, 13, 999983] 470994 function calls in 26.768 CPU seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 0.000 0.000 summationoffourprimes.py:48(getList) 1 0.040 0.040 26.768 26.768 <string>:1(?) 1 0.062 0.062 2.708 2.708 summationoffourprimes.py:36(createList) 1 0.000 0.000 2.708 2.708 summationoffourprimes.py:31(__init__) 470988 5.244 0.000 5.244 0.000 summationoffourprimes.py:103(selectionFour) 1 18.777 18.777 26.728 26.728 summationoffourprimes.py:112(main) 1 2.646 2.646 2.646 2.646 summationoffourprimes.py:8(prime2) Hit any key to close this window...
์ฌ๊ธฐ์ selectionFour ์ ๊ฒฝ์ฐ๋ percall ์ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ์ ๋ค. ํ์ง๋ง, call ํ์ ์์ฒด๊ฐ 470988 ๋ฒ์ผ๋ก ๋ง๋ค. ์ด ๋ถ๋ถ์ ๋ํด์ ์ผ์ข
์ inlining ์ ํ์๋ค.
~cpp C:\WINDOWS\system32\cmd.exe /c python SummationOfFourPrimes.py input number : 1000000 (2, 2, 13, 999983) 6 function calls in 16.671 CPU seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 0.000 0.000 summationoffourprimes.py:48(getList) 1 13.736 13.736 16.540 16.540 summationoffourprimes.py:121(main2) 1 0.067 0.067 2.804 2.804 summationoffourprimes.py:36(createList) 1 2.738 2.738 2.738 2.738 summationoffourprimes.py:8(prime2) 1 0.131 0.131 16.671 16.671 <string>:1(?) 1 0.000 0.000 2.804 2.804 summationoffourprimes.py:31(__init__) Hit any key to close this window...10000000 ๊ฑด์ ๋ํด์๋ 7.49 ์ด ๊ธฐ๋ก (profiler ๋ฅผ ์ด์ฉํ ๊ฒฝ์ฐ ์๋์ ํ๊ฐ ์๊ธฐ ๋๋ฌธ์ profiler ๋ฅผ ๋๊ณ psyco ๋ง์ผ๋ก ์คํ)
4. ์ต์ ํ 2์ฐจ : ๋ฌธ์ ์์ญ์ ์ค์ด๊ธฐ ¶
๋น๋ก inlining ์ ์์ผฐ์ง๋ง ์ฌ์ ํ ๊ฒ์ selectionFour ๋ถ๋ถ์ด๋ค. selectionFour ๊ฐ ์คํ๋๋ ๊ฒฝ์ฐ์ ์ต์
์ ๊ฒฝ์ฐ๋ (n ๊น์ง์ ์์๊ฐฏ์)^4 ๊ฐ ๋๋ค. ์ด๋ฅผ ์ข ๋ smart ํ๊ฒ ํ ๋ฐฉ๋ฒ์ด ์์๊น.
์์์ ๊ด๋ จํ์ฌ ์ข ๋ ๋๋ํ๊ฒ ๊ฒ์ํ ๋ฐฉ๋ฒ์ด ์กด์ฌํ๋ฆฌ๋ผ ์๊ฐํ๋ค.
๊ฐ์ฅ ๊ฐ๋จํ ์์ด๋์ด๋ก, 4๋ฒ์งธ ๊ฐ์ ๋ํด์๋ ๋ฐ๋ก ๊ณ์ฐ์ ํ ์๊ฐ ์๊ฒ ๋ค.
์์์ ๊ด๋ จํ์ฌ ์ข ๋ ๋๋ํ๊ฒ ๊ฒ์ํ ๋ฐฉ๋ฒ์ด ์กด์ฌํ๋ฆฌ๋ผ ์๊ฐํ๋ค.
๊ฐ์ฅ ๊ฐ๋จํ ์์ด๋์ด๋ก, 4๋ฒ์งธ ๊ฐ์ ๋ํด์๋ ๋ฐ๋ก ๊ณ์ฐ์ ํ ์๊ฐ ์๊ฒ ๋ค.
selectionFour ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ์๋ค.
~cpp def selectionFour(aList,aNum): sizeOfList = len(aList) for i in range(sizeOfList): for j in range(sizeOfList): for k in range(sizeOfList): for l in range(sizeOfList): expectedLastValue = aNum-(aList[i]+aList[j]+aList[k]) if expectedLastValue in aList: yield [aList[i],aList[j],aList[k],expectedLastValue] else: breakinlining ์ ํ์ง ์์์์๋ 6.4์ด๋๋ฅผ ๊ธฐ๋กํ์๋ค. inlining ์ ํ๋ฉด 5.7์ด๋๋ฅผ ๊ธฐ๋กํ๋ค.
5. ์ต์ ํ 3์ฐจ : PyRex ¶
PyRex ๋ Python ์ฝ๋๋ฅผ C ์ฝ๋๋ก ์ ํํด์ค๋ค. ์ด๋ฅผ ์ด์ฉ, C ๋ชจ๋๋ก ๋ง๋ค์ด ์ปดํ์ผํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์คํ. ์์ธ๋ก 7.x ๋๋ก, PsyCo ๋ฅผ ์ผ์๋๋ณด๋ค ์คํ๋ ค ์ฑ๋ฅ์ด ๋จ์ด์ก๋ค. C ์ฝ๋๋ฅผ ๋ณด๋ ์ฌ๊ฑธ. ์ ํ ์์๋ณผ์๊ฐ ์๋ ์ฝ๋๋ค. ์ฐจ๋ผ๋ฆฌ ๊นจ๋ํ๊ฒ ์ง์ ์์ฑํด์ฃผ๋๊ฒ ์ฑ๋ฅํฅ์ ์์ผ๋ก๋ ์ ๋ฆฌํ๊ฒ ๋ค๋ ์๊ฐ.
6. ํ ์ผ ๋๋น ๋๋์ ¶
- ์ด์ ์๋ ๋๋ ์ ์ด์ง๋ง, ํ๊ฐ์ง ๋ฌธ์ ๋ฅผ ์์ฃผ ๊น๊ฒ ํ์ด๋ณด๋ ค๊ณ ํ๋ ๊ฒ๋ ์ฌ๋ฌ๊ฐ์ง๋ก ํ์ต์ด ๋๋ค.
- ๊ณผ์ ์ ๋ํ ๊ธฐ๋ก. ๋ฌด์ธ๊ฐ ์ ๊ด๋ฆฌ๊ฐ ์๋๋ ์ํฉ์ด ์ค๋๋ ๋, ํ ์ผ๋ค๊ณผ ์ฌ์ค๋ค์ ๊ธฐ๋กํด๋ณด๋ ๊ฒ์ ์๋นํ ๋์์ด ๋๋ค.
7. ๋ ํ์์ผ๋ฉด ํ๋ ์ . ๋ณด์ ¶
- PrimeNumber ์ ์ต์ ํ์ ๋ํด์. ๊ธฐ์กด์ ์๋ ์๊ณ ๋ฆฌ์ฆ์ด ์๋, ์ง์ ์ต์ ํ๋ฅผ ์๋ํด๋ณด๋ ๊ฒ์ผ๋ก ๋ ๋ง์ ๊ฒ์ ํ์ตํ ์ ์์ผ๋ฆฌ๋ผ. ์ด๋ฒ์ ๊ฒฝ์ฐ๋ 2์๊ฐ ์์
์ผ๋ก ๊ณํ์ ์ก์๋ ๊ด๊ณ๋ก.
- ์ด๋ฌํ ๋ฌธ์ ์ ๊ฒฝ์ฐ ํน์ ์๊ณ ๋ฆฌ์ฆ์ ์์ฃผ ์ต์ ํ ๋ ๊ฒฐ๊ณผ๋ฌผ์ด ๋ต์ด๊ธฐ ๋ณด๋ค๋, ๋ฌด์ธ๊ฐ ๋ค๋ฅธ ์ฐจ์์์ ๋ดค์๋ ๋๋ฌด๋ ๋นจ๋ฆฌ ๋ต์ด ๋์ค๊ฒ ๋๋ ๊ฒฝ์ฐ์ผ๊ฒ์ด๋ผ ์ถ์ธก. ์ ํ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ดํ๋ก์น๋ ์๊ฐํด๋ณด๊ณ ์ถ๋ค.