Showing posts with label Tutorials. Show all posts
Showing posts with label Tutorials. Show all posts

Wednesday, October 8, 2008

การเขียนโปรแกรมหาจำนวนเฉพาะโดยใช้ Python

ไหนๆก็ไปโพสท์ไว้ใน blognone แล้ว ก็เลยเอามาแปะไว้นี่ด้วยเลยเผื่อเป็นประโยชน์

ย้ายไปเขียนบน LongSpine.com เนื่องจากโค้ดเละ

วิธีการหาจำนวนเฉพาะ ..แบบเขียนง่ายๆอ่านง่ายๆ


ไอเดียแรกคือการหาจำนวนเฉพาะใหม่จากจำนวนเฉพาะเก่าที่มีอยู่แล้ว โดยมีหลักคือจำนวนเฉพาะนั้นคือจำนวนที่ไม่มีจำนวนเฉพาะอื่นๆหารมันลงตัว

prime = [2]
for i in range(3, 100000):
flag = True # สมมุติว่าจำนวน i เป็นจำนวนเฉพาะ
for j in prime: # จำนวน j ใดๆที่เป็นจำนวนเฉพาะต้องหารจำนวนนี้ไม่ลงตัว
if (i % j == 0): # แต่ถ้าดันหารได้ลงตัว (มีเศษเป็น 0)
flag = False # เราก็พบว่าจำนวนนั้นไม่ใช่จำนวนเฉพาะ
break # ออกจากลูปทันที
if flag == True: # ถ้าพิสูจน์แล้วว่าเป็นจำนวนเฉพาะจริงๆ
prime.append(i) # ให้ใส่ค่านั้นเข้าไปในตัวแปร prime

ไอเดียที่สองคือลดจำนวนตัวที่ต้องวนหารลง เนื่องจากจำนวนเต็มใดๆ j สูงสุดที่จะหาจำนวนเต็มใดๆ i ได้นั้น จะต้องมีค่าไม่มากไปกว่ารากที่สองของ i

prime = [2]
for i in range(3, 100000):
flag = True # สมมุติว่าจำนวน i เป็นจำนวนเฉพาะ
for j in prime: # จำนวน j ใดๆที่เป็นจำนวนเฉพาะต้องหารจำนวนนี้ไม่ลงตัว
if (j ** 2 > i): # ถ้า j มีค่ามากกว่าตัวหารสุงสุดที่เป็นไปได้ (มีค่ามากกว่ารากที่สองของ i)
break # ให้ออกจากลูป
if (i % j == 0): # แต่ถ้าดันหารได้ลงตัว (มีเศษเป็น 0)
flag = False # เราก็พบว่าจำนวนนั้นไม่ใช่จำนวนเฉพาะ
break # ออกจากลูปทันที
if flag == True: # ถ้าพิสูจน์แล้วว่าเป็นจำนวนเฉพาะจริงๆ
prime.append(i) # ให้ใส่ค่านั้นเข้าไปในตัวแปร prime


ไอเดียที่สาม เรายังทำให้เร็วได้มากไปกว่านี้อีก โดยใช้วิธีซีฟของเอราทอสเทนีส ซึ่งใช้หน่วยความจำมาช่วยในการคำนวน (อ่านรายละเอียดได้ตามลิงค์) วิธีนี้ข้อเสียคือเปลืองหน่วยความจำมาก

import numpy

n = 100000 # หาจำนวนเฉพาะที่มีค่าน้อยกว่า 100000

primeArr = numpy.zeros(n) # สร้าง array ขนาด n
primeArr[0] = 1 # 0 ไม่ใช่จำนวนเฉพาะ
primeArr[1] = 1 # 1 ก็ไม่ใช่

for i in xrange(2, n):
if primeArr[i] == 0: # ถ้าจำนวนนั้นเป็นจำนวนเฉพาะ
for j in xrange(i * 2, n, i): # จำนวนอื่นๆที่จำนวนนั้นหารลงตัว
primeArr[j] = 1 # ..จะไม่ใช่จำนวนเฉพา

prime = []

for i in xrange(2, n):
if primeArr[i] == 0: # เก็บจำนวนเฉพาะไว่ในตัวแปร prime
prime.append(i)
ทดลองเปรียบเทียบความเร็วของทั้งสามตัวอย่าง

poomk@gemini:/tmp$ time ./prime1.py >0

real 0m19.622s
user 0m19.581s
sys 0m0.020s

poomk@gemini:/tmp$ time ./prime2.py >0

real 0m0.675s
user 0m0.676s
sys 0m0.000s

poomk@gemini:/tmp$ time ./prime3.py >0

real 0m0.535s
user 0m0.504s
จะเห็นว่าเร็วขึ้นตามลำดับ

ไอเดียที่สี่ เนื่องจากตัวอย่างที่สามนั้นไม่เหมาะกับการหาจำนวนเฉพาะที่มีขนาดมากๆ (มากๆๆๆๆ...ๆ) ทำให้เราไม่สามารถใช้วิธีของซีฟได้เพราะเรามีหน่วยความจำไม่เพียงพอ วิธีหนึ่งที่(ผมเคย)ใช้ก็คือการหาจำนวนเฉพาะตั้งต้นด้วยซีฟ(ตัวอย่างที่สาม) จากนั้นค่อยน้ำตัวเฉพาะตั้งต้นเหล่านั้นไปหาตัวเฉพาะอื่นๆต่อตามตัวอย่างที่สอง

import numpy

n = 1000000 # หาจำนวนเฉพาะที่มีค่าน้อยกว่า 1000000 (หนึ่งล้าน)

primeArr = numpy.zeros(n)
primeArr[0] = 1
primeArr[1] = 1

for i in xrange(2, n):
if primeArr[i] == 0:
for j in xrange(i * 2, n, i):
primeArr[j] = 1

prime = []

for i in xrange(2, n):
if primeArr[i] == 0:
prime.append(i)

for i in range(n, 2000000): # หาต่อจนถึงตัวที่ 2000000 (สองล้าน)
flag = True
for j in prime:
if (j ** 2 > i):
break
if (i % j == 0):
flag = False
break
if flag == True:
prime.append(i)
เมื่อจับเวลาก็จะเห็นความแตกต่าง
poomk@gemini:/tmp$ time ./prime2.py >0

real 0m27.190s
user 0m27.090s
sys 0m0.096s

poomk@gemini:/tmp$ time ./prime4.py >0

real 0m20.422s
user 0m20.369s
sys 0m0.040s

อนึ่งโปรแกรมตัวอย่างนี้เขียนขึ้นเพื่อความอ่านง่าย (และมักง่าย) มีจุดประสงค์เพื่อบอกแนวโน้มของความเร็วที่เพิ่มขึ้นของแต่ละไอเดีย ซึ่งหากเขียนไปใช้งานจริงๆอาจจะมีลูกเล่นที่ทำให้ทำเวลาได้ดีขึ้นกว่านี้อีก

Monday, November 12, 2007

TV on Debian Etch

ในหอพักที่ผมอยู่ตอนนี้มีช่องสายเคเบิลทีวีให้ใช้ และถึงแม้ว่าการดูทีวีมันทำให้เสียการเสียงาน แต่การเรียนรู้ภาษาและวัฒนธรรมของประเทศหนึ่งๆนั้น ทีวีก็น่าจะช่วยเราได้ในระดับหนึ่ง
แต่ผมไม่ต้องการซื้อทีวีแพงๆมาให้รกห้องน่ะสิ

ผมเลือกที่จะซื้อการ์ดทีวีมาติดตั้งลงใน desktop ของผม ที่ตอนนี้ผมกำลังพยายามเซ็ตมันเป็น server อเนกประสงค์อยู่

การ์ดที่ผมเลือกใช้คือ Hauppauge WinTV Go ที่สามารถใช้บน linux ได้ และมีราคาถูก ผมซื้อมันมาจาก Amazon.de ด้วยราคา 18 Euro (900 บาท) รวมค่าส่งแล้ว



เมื่อเสียบการ์ดลงไปในเครื่อง desktop ที่ใช้ Debian etch แล้วปรากฏว่า video4linux ก็เจอ driver bttv ของการ์ดนี้ทันที ผมไม่ต้องทำอะไรเพิ่มเลย

โปรแกรมที่ใช้ดูทีวีบนคอมพิวเตอร์นั้นมีอยู่หลายโปรแกรม เช่น Mplayer, xawtv, Zapping, KWinTV, และ tvtime ซึ่งจากประสพการณ์ของผม mplayer นั้นใช้งานได้ครอบจักรวาล แต่มีประสิทธิภาพสูงสุดก็ต่อเมื่อดูไฟล์วีดีโอเท่านั้น

ส่วน xawtv นั้นก็มีปัญหาที่ interface มันเส็งเคร็ง Zapping ก็ดันมีบั๊กตั้งแต่ตอนติดตั้ง และผมขี้เกียจไล่ตามลงแพ็คเกจสำหรับ KWinTV (ผมใช้ gnome)
สุดท้ายแล้วตัวเลือกของผมคือ tvtime เพราะผมยังไม่มีเหตุผลอะไรให้ต้องเกลียดมัน การติดตั้งก็ทำได้โดยง่ายแสนง่าย เพราะมันมีข้อมูลอยู่ใน repository อยู่แล้ว

แต่ชีวิตคนเรามันคงไม่สดใสเหมือนในนิยาย

ปัญหาเริ่มเกิดเมื่อผมซื้อสายเคเบิลคุณภาพบัดซบมาจากร้านหนึ่งยูโร ทำให้ผมต้องเสียเวลาไปกับการจูนช่องใหม่หลายรอบ เพราะผมไม่มั่นใจว่ามันมีปัญหาที่การ์ด ที่สาย หรือที่ตัวเคเบิลกลางของหอพัก

จากนั้นเมื่อลองใช้งาน tvtime ปรากฎว่าพบปัญหาว่าการ์ดจอไม่พบ DGA Extenstion สาเหตุเกิดมาจากการที่ไดรเวอร์ของ Nvidia นั้นไม่ซัพพอร์ท DGA (Direct Graphics Access)

เพิ่มข้อความนี้ไปใน Section Module เพื่อยกเลิกการใช้งาน dga

SubSection "extmod"
Option "omit xfree86-dga"
EndSubSection

จากนั้นก็ restart แล้วทำการจูนทีวีอีกครั้งโดยใช้คำสั่ง

tvtime-scanner

เลือกระบบและช่วงคลื่นทีวีด้วย สำหรับผมก็ PAL, europe ระหว่างนี้ก็ไปหาอะไรกินก่อนก็ได้เพราะมันอาจจะนาน

จากนั้นเปิดโปรแกรม tvtime เราก็จะพบ



.. noise บานเลย

update: ไปดูทีวีของเพื่อนคนไทยห้องข้างๆแล้วก็ไม่ชัดเหมือนกัน น่าจะเป็นที่สายเคเบิลกลาง

Friday, October 19, 2007

SSH Tunneling

ห้องที่ผมพักอยู่นี้เป็นหอพักของมหาวิทยาลัย และอินเตอร์เน็ตของหอพักก็เป็นเน็ตในเครือข่ายของมหาวิทยาลัยเช่นเดียวกัน แต่ถึงแม้เน็ตจะมีความเร็วสูงแค่ไหนผมก็ไม่สามารถใช้งานได้เต็มที่ เนื่องจากอินเตอร์เน็ตของหอพักได้จำกัดปริมาณการขนส่งข้อมูลนอกเครือข่ายภายนอกมหาวิทยาลัย (Transfer Volume) ไว้ที่ 3GB ต่อเดือน ซึ่งตัวเลขนี้นั้นนับทั้งดาวน์โหลดและอัพโหลดแล้ว

โชคดีที่ผมมี account อยู่ที่เซิร์ฟเวอร์ที่ใช้ในการพิมพ์งานที่มหาวิทยาลัย ซึ่งผมสามารถต่อ SSH เข้าไปใช้งานได้
ผมจึงเกิดไอเดียว่า ถ้าผมใช้งานอินเตอร์เน็ตผ่านเครื่องเซิร์ฟเวอร์ ผมก็จะไม่เสียโควต้าอินเตอร์เน็ตเลย เพราะเครื่องมหาวิทยาลัยต่างหากที่ทำการส่งข้อมูลออกนอกมหาวิทยาลัย ส่วนผมติดต่อกับเครื่องมหาวิทยาลัยอีกที

สิ่งที่ผมต้องทำก็คือ ทำการส่งต่อข้อมูลผ่านพอร์ท (Port Forwarding) จากเครื่องผมไปยังเครื่องเซิร์ฟเวอร์มหาวิทยาลัย ข้อมูลที่ส่งไปยังอินเตอร์เน็ตทุกข้อมุลก็จะวิ่งผ่านพอร์ทนี้ไปทะลุที่เครื่องปลายทาง และถ้ามีข้อมูลส่งกลับมันก็จะถูกส่งกลับมาทางพอร์ทเดิมนี้เช่นกัน

เริ่มจากการเปิดพอร์ทโดยใช้ ssh ซึ่งรองรับโปรโตคอล SOCKS4 และ SOCKS5
ssh -D 14141 account@server.address # เปิดพอร์ท 14141 ไปยังเครื่องปลายทาง
จากนั้นทำการตั้ง proxy ที่ browser ที่ใช้ให้ยิงไปที่ localhost พอร์ท 14141
แต่เนื่องจาก Opera ไม่รองรับ SOCKS4 หรือ SOCKS5 ทำให้ข้อมุลต้องผ่านโปรแกรมอีกตัวหนึ่งชื่อ Privoxy

ตั้ง proxy ของ Opera ให้ส่งข้อมูลไปที่ localhost พอร์ท 8118 (Privoxy default) และทำการแก้ไขข้อมูลของ Privoxy
sudo vi /etc/privoxy/config
เพิ่มบรรทัดนี้ลงไปในหัวข้อ forward-socks4 and forward-socks4a
forward-socks4 / 127.0.0.1:14141 .
เซฟไฟล์ และทำการ restart ตัว privoxy โดยใช้คำสั่ง
sudo /etc/init.d/privoxy restart
หลังจากนั้น 3GB ก็จะไม่ใช่ปัญหาใหญ่อีกต่อไป ขอบคุณเจสันที่เคยสอน พึ่งได้ใช้ประโยชน์จริงๆก็คราวนี้แหละ

Wednesday, July 18, 2007

Install Python2.5.1 on Solaris 10

1. ดาวน์โหลด python2.5.1 package จากเว็บ sunfreeware.com หากดาวน์โหลดไม่ได้ ให้ลองเข้า http://www.download-ftp-center.com/sunfreeware.com/sparc/10/ แทน

2. คำสั่งติดตั้งมาตรฐาน
gunzip python-2.5.1-sol10-sparc-local.gz 
pkkadd -d python-2.5.1-sol10-sparc-local
3. เมื่อลงเสร็จแล้ว ถ้าต้องการที่จะเรียกโปรแกรมได้โดยไม่ต้องใส่ PATH ให้แก้โดยใช้คำสั่ง
PATH=$PATH:/usr/local/bin
ถ้าต้องการใช้คำสั่งนี้ทุกครั้งที่ทำงาน ให้เพิ่มโค้ดบรรทัดหนึ่ง ลงไปใน .profile
PATH=$PATH:/usr/local/bin
4. ตรวจสอบเวอร์ชันของ python โดยใช้คำสั่ง
python -V
5. ในกรณีที่คำสั่ง python มันไปเรียก python อีกเวอร์ชันหนึ่ง เช่น python2.3 ให้ทำการตามลบ link ที่ชี้ไปยัง python เวอร์ชันเก่า
which python
rm <ไฟล์ที่ which แสดง>
ง่ายเนอะ

Tuesday, July 17, 2007

Running Solaris 10 as root through remote console

หากต้องการใช้งาน root จากเครื่องอื่น เราจำเป็นที่จะต้องเข้าไปแก้ไขไฟล์ /etc/default/login เสียก่อน ไม่เช่นนั้นจะเกิด error ว่า
Not on system console, root login rejected.



แก้ไขได้โดยคอมเมนท์บรรทัดที่ระบุคอนโซลว่า CONSOLE=/dev/console ทิ้ง ก็จะสามารถเข้าใช้งานได้ตามปกติ
(ในรูป เข้าใช้งานผ่าน Xephyr)

Tuesday, July 10, 2007

AIX Toolbox for Linux Applications

เราสามารถลงโปรแกรมของลินิกซ์ใน AIX L5 ได้ง่ายๆโดยใช้ RPM Package Manager.

วิธีการลง RPM บน AIX นั้นค่อนข้างสะดวก เริ่มจากดาวน์โหลดไฟล์ rpm.rte สำหรับโปรแกรม installp ลงในคอมพิวเตอร์ หลังจากนั้นสามารถใช้คำสั่งต่อไปนี้ในการติดตั้ง
installp -qacXgd rpm.rte rpm.rte
แค่นี้เราก็ได้ RPM มาใช้งานแล้ว

ลองใช้ RPM ในการติดตั้ง bash โดยทำการดาวน์โหลด bash RPM มา จากนั้นใช้คำสั่ง
rpm -i bash-3.0-1.aix5.1.ppc.rpm

อ้างอิง - AIX Toolbox for Linux Applications

Backspace in Telnet

ช่วงอาทิตย์นี้ได้มีโอกาสได้เล่น IBM AIX ที่บริษัท
ตัวเครื่องนั้นถูกตั้งไว้ชั้นล่าง เวลาเข้าไปใช้งานจึงต้องใช้งานผ่าน telnet (ซึ่งจริงๆแล้วยังนึกสงสัยอยู่ว่าทำไมมันถึงไม่ใช้ ssh)

ระหว่างที่ใช้ telnet นั้นเจอปัญหารบกวนใจเล็กน้อย คือเมื่อกดปุ่ม backspace พบว่ามีสัญลักษณ์ ^? ออกมาแทนการลบตัวอักษร

เราสามารถแก้ไขได้โดยการใช้คำสั่ง stty ในการตั้งปุ่มที่จะใช้เป็นคำสั่งที่ต้องการ เช่นตั้ง ^? ให้เป็นคำสั่ง erase ซึ่งทำได้ดังนี้
stty erase ^?