การสุ่มตัวเลขในภาษา Python

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการสุ่มตัวเลขในภาษา Python เราจะแนะนำให้คุณรู้จักกับฟังก์ชันในไลบรารี่มาตรฐานของภาษาที่ใช้สำหรับการสุ่มตัวเลขแบบต่างๆ ในภาษา Python นี่เป็นเนื้อหาในบทนี้

  • การสุ่มตัวเลขจำนวนเต็ม
  • การสุ่มตัวเลขทศนิยม
  • Random seed
  • การสุ่มตัวเลขแบบ CPRNG

การสุ่มตัวเลข คือการสร้างตัวเลขขึ้นมาแบบสุ่มด้วยวิธีการทางคอมพิวเตอร์เพื่อนำมาใช้งานในโปรแกรม มันมีประโยชน์เมื่อเราต้องการเขียนโปรแกรมที่มีการทำงานแบบสุ่ม เช่น การทอยลูกเต๋า การสับไพ่ หรือการสุ่มสิ่งของในเกม ในภาษา Python นั้นมีโมดูล random ที่ประกอบไปด้วยฟังก์ชันสำหรับสุ่มตัวเลขแบบต่างๆ ที่ใช้อัลกอริทึม Pseudorandom number generator (PRNG) สำหรับสุ่มตัวเลข

การสุ่มตัวเลขจำนวนเต็ม

การสุ่มตัวเลขจำนวนเต็มเป็นรูปแบบการสุ่มตัวเลขที่พบบ่อยที่สุดในการเขียนโปรแกรม สำหรับตัวอย่างแรกในบทนี้ เรามาเขียนโปรแกรมสำหรับสุ่มตัวเลขจำนวนเต็มอย่างง่ายและแสดงผลตัวเลขที่สุ่มได้ออกทางหน้าจอ นี่เป็นตัวอย่าง

random_number.py
from random import randint, getrandbits

# Random integers between 1 - 10
print(randint(1, 10))
print(randint(1, 10))

# 4 bits-sized integers
print(getrandbits(8))
print(getrandbits(8))

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

1
3
28
197

ในตัวอย่าง เราได้แนะนำสองฟังก์ชันสำหรับสุ่มตัวเลขจำนวนเต็มในภาษา Python ฟังก์ชันเหล่านี้เป็นฟังก์ชันจากโมดูล random ดังนั้นเราได้ทำการ import เข้ามาในโปรแกรมก่อนใช้งาน ทั้งสองฟังก์ชันนั้นใช้สำหรับสุ่มตัวเลขจำนวนเต็มเหมือนกัน แต่มีการทำงานที่แตกต่างกันดังนี้

print(randint(1, 10))

ฟังก์ชัน randint() ใช้สำหรับสุ่มตัวเลขจำนวนเต็มจากช่วงของพารามิเตอร์ที่กำหนด ในตัวอย่างเป็นการสุ่มตัวเลขที่มีค่าระหว่าง 1 - 10 คุณสามารถระบุช่วงของตัวเลขใดๆ ที่ต้องการสุ่มได้

print(getrandbits(8))

ฟังก์ชัน getrandbits() ใช้สำหรับสุ่มตัวเลขที่มีขนาดตามจำนวนบิตที่กำหนด ในตัวอย่างเป็นการสุ่มตัวเลขที่มีขนาด 8 บิต นั่นหมายความว่าค่าที่เป็นไปได้ของการสุ่มจะอยู่ระหว่าง 0 - 255

มาดูตัวอย่างเพิ่มเติมสำหรับการสุ่มตัวเลขจำนวนเต็ม ในตัวอย่างนี้เป็นการสุ่มตัวเลขระหว่าง 1 - 100 จากนั้นเก็บเข้าใน List และนำมาหาผลรวมและค่าเฉลี่ยของตัวเลขภายในลิสต์ และแสดงผลออกทางหน้าจอ นี่เป็นตัวอย่าง

ramdom_number2.py
from random import randint

numbers = []

print("Random numbers:")
for i in range(10):
    n = randint(1, 100)
    print(n, end =' ')
    numbers.append(n)

s = sum(numbers)
a = s / len(numbers)
print("\nSum = %d" % s)
print("Average = %f" % a)

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Random numbers:
58 8 73 82 85 6 9 19 27 19
Sum = 386
Average = 38.600000

ในตัวอย่าง เป็นโปรแกรมสำหรับสุ่มตัวเลขจาก 1 - 100 เป็นจำนวน 10 ตัวเลขและเก็บไว้ในลิสต์ ในตอนแรกเราได้ประกาศตัวแปรลิสต์ numbers สำหรับเก็บตัวเลขทั้งหมดที่จะได้มาจากการสุ่ม

for i in range(10):
    n = randint(1, 100)
    print(n, end =' ')
    numbers.append(n)

เราใช้คำสั่งวนซ้ำ for loop สำหรับวนสุ่มตัวเลขที่มีค่าระหว่าง 1 -100 จากนั้นเก็บเข้าไปในตัวแปรลิสต์ด้วยเมธอด append() นอกจากนี้เรายังแสดงตัวเลขที่สุ่มมาได้ภายในลูปเพื่อแสดงการทำงานของตัวเลขที่สุ่มได้ในแต่รอบ

s = sum(numbers)
a = s / len(numbers)

จากนั้นนำมาตัวเลขที่สุ่มได้ในลิสต์มาหาผลรวมด้วยฟังก์ชัน sum() และหาค่าเฉลี่ยของตัวเลขจากผลรวมหารด้วยจำนวนของตัวเลขทั้งหมดและแสดงผลลัพธ์ที่ได้ออกทางหน้าจอ

การสุ่มตัวเลขทศนิยม

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

นี่เป็นตัวอย่างของโปรแกรมที่สุ่มตัวเลขทศนิยมจากช่วงต่างๆ ในภาษา Python โดยการใช้ฟังก์ชันจากไลบรารี่มาตรฐาน random

ramdom_float.py
from random import random, uniform

# Random numbers between [0.0, 1.0)
print(random())
print(random())

# Random numbers between [0.0, 20.0]
print(uniform(0, 20))
print(uniform(0, 20))

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

0.2312618740781729
0.6039213323707252
13.375267975292829
6.3944059358623555

ในตัวอย่างนี้ แนะนำให้คุณรู้จักกับสองฟังก์ชันที่ใช้สำหรับสุ่มตัวเลขจำนวนจริงในภาษา Python ฟังก์ชันเหล่านี้อยู่ในไลบรารี่ random ดังนั้นเราทำการ import มันเข้ามาก่อนการใช้งานในโปรแกรม

print(random())

ฟังก์ชัน random() ใช้สำหรับสุ่มตัวเลขที่มีจาก 0.0 แต่ไม่เกิน 1.0 นั่นหมายความว่าค่าที่ได้จากการสุ่มจะมีช่วงอยู่ระหว่าง 0.0 - 0.9999... นี่เป็นฟังก์ชันพื้นฐานที่ใช้ในการสุ่มตัวเลขทุกแบบในภาษา Python

print(uniform(0, 20))

ส่วนฟังก์ชัน uniform() นั้นใช้สำหรับสุ่มตัวเลขทศนิยมจากช่วงที่กำหนด ในตัวอย่างเราใช้มันสำหรับสุ่มตัวเลขที่มีค่าอยู่ระหว่าง 0.0 - 20.0 สำหรับฟังก์ชัน uniform() นั้นผลลัพธ์ที่ได้จากการสุ่มจะรวมกับพารามิเตอร์ที่สองเสมอ

Random seed

ฟังก์ชันสุ่มตัวเลขพื้นฐานในภาษา Python ใช้อัลกอริทึม Pseudorandom number generator (PRNG) เป็นวิธีการสุ่มหลัก ซึ่งอัลกอริทึม PRNG นั้นใช้สมการทางคณิตศาสตร์สำหรับสร้างลำดับของตัวเลขในการสุ่ม และมันใช้ Random seed ในการกำหนดการทำงาน

Random seed คือตัวเลขที่ใช้กำหนดการทำงานของตัวสุ่มตัวเลข โดยปกติแล้วเราจะต้องกำหนด Random seed ให้กับตัวสุ่มก่อนเสมอ อย่างไรก็ตามในภาษา Python ได้ทำขั้นตอนนี้ให้อัติโนมัติ โดยใช้ค่าใช้ที่เปลี่ยนไปตลอดเวลา เช่น ค่า Timestamp ปัจจุบันของระบบ ดังนั้นเราไม่จำเป็นต้องกำหนดมันด้วยตัวเอง

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

random_seed.py
from random import seed, randint

seed(12)

for i in range(10):
    print(randint(1, 100), end = " ")

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

61 35 85 68 86 45 19 49 2 48
61 35 85 68 86 45 19 49 2 48

จะเห็นว่าไม่ว่าเราจะรันโปรแกรมกี่ครั้งกับค่า Random seed ที่มีค่าเป็น 12 ลำดับของการสุ่มจะยังคงเป็นเหมือนเดิมเสมอ นั่นหมายความว่าทุกๆ ค่าของ Random seed จะมีลำดับการสุ่มที่ตายตัวเสมอ ซึ่งนี่เป็นวิธีการทำงานพื้นฐานของ PRNG

เพื่อทำให้ลำดับของการสุ่มแตกต่างกัน เราจะต้องกำหนดค่า Random seed ที่แตกต่างกันออกไปในการรันโปรแกรมแต่ละครั้ง ซึ่งนี่สามารถทำได้โดยการใช้เวลา Timestamp เป็น Random seed ซึ่งนี่เองเป็นวิธีที่ Python ทำให้กับเราอัตโนมัติเมื่อเราไม้ได้กำหนดค่า Random seed ให้กับโปรแกรม

time_as_seed.py
from random import seed, randint
from datetime import datetime

seed(datetime.now().microsecond)

for i in range(10):
    print(randint(1, 100), end = " ")

นี่เป็นผลลัพธ์การทำงานของโปรแกรมจากการรันสองครั้ง

83 47 39 85 97 42 18 46 45 34
54 59 31 17 7 39 87 71 25 62

ในตัวอย่าง เราได้กำหนดค่า Random seed ด้วยเวลา Timestamp ที่รับค่ามาจากฟังก์ชัน datetime.now() ในไลบรารี่ datetime ดังนั้นเมื่อรันโปรแกรมในแต่ละครั้งผลลัพธ์ของการสุ่มนั้นจะแตกต่างกัน เนื่องจาก Timestamp ในขณะที่รันแตกต่างกันนั่นเอง

การสุ่มตัวเลขแบบ CPRNG

Pseudorandom number generator (PRNG) เป็นวิธีพื้นฐานสำหรับการสุ่มตัวเลข แต่มันอาจไม่เหมาะสำหรับทุกวัตถุประสงค์ เพราะการสุ่มนั้นถูกกำหนดการทำงานด้วย Random seed และลำดับของการสุ่มง่ายต่อการคาดเดา ดังนั้นถ้าหากใครบางคนสามารถจำลำดับการสุ่มของ Random seed = 12 ได้ มันเป็นไปได้ที่เขาจะรู้ว่าตัวเลขถัดไปจากการสุ่มจะเป็นอะไร

อีกวิธีหนึ่งของการสุ่มตัวเลข; Cryptographically secure pseudorandom number generator (CPRNG) เป็นการสุ่มที่ปลอดภัยด้วยวิธีการเข้ารหัสทางคอมพิวเตอร์ โดยใช้เอนโทรปีที่ได้รับจากแหล่งคุณภาพสูง เช่น จากระบบปฏิบัติ การสุ่มด้วยวิธีนี้จะไม่ขึ้นอยู่กับ Random seed และเป็นการสุ่มที่เหมือนกับการสุ่มในธรรมชาติ เช่น การทอยลูกเต๋า หรือการสับไพ่ เป็นต้น ดังนั้นเมื่อโปรแกรมของคุณต้องการการสุ่มที่มีความปลอดภัยและไม่สามารถคาดเดาได้ เราแนะนำให้ใช้การสุ่มแบบ CPRNG

ในภาษา Python มีฟังก์ชันในโมดูล secrets สำหรับสุ่มตัวเลขแบบ CPRNG ในการใช้งานฟังก์ชันนี้เพื่อสุ่มตัวเลข ค่าทีี่ได้จากการสุ่มแต่ละครั้งจากการเรียกฟังก์ชันจะเป็นอิสระต่อกัน และไม่สามารถคาดเดาได้เนื่องจากมันไม่ขึ้นกับ Random seed นั่นเอง นี่เป็นตัวอย่างการใช้งาน

cprng_random.js
from secrets import randbelow, randbits

# Random numbers 0 - 9
print(randbelow(10))
print(randbelow(10))

# 4 bits-sized integers (0 - 255)
print(randbits(8))
print(randbits(8))

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

4
8
215
122

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

print(randbelow(10))

ฟังก์ชัน randbelow() ใช้สำหรับสุ่มตัวเลขจำนวนเต็มที่มีค่าจาก 0 และไม่เกินค่าของพารามิเตอร์ ในตัวอย่างเป็นการใช้ฟังก์ชันเพื่อสุ่มตัวเลขจาก 0 - 9 สองครั้ง

print(randbits(8))

ฟังก์ชัน randbits() ใช้สำหรับสุ่มตัวเลขที่มีขนาดตามจำนวนบิตที่กำหนด ในตัวอย่างเป็นการสุ่มตัวเลขที่มีขนาด 8 บิต นั่นหมายความว่าค่าที่เป็นไปได้ของการสุ่มจะอยู่ระหว่าง 0 - 255

สำหรับตัวอย่างสุดท้ายในบทนี้ มาดูตัวอย่างของโปรแกรมในการทอยลูกเต๋า โดยการใช้ฟังก์ชันการสุ่มจากโมดูล secrets นี่เป็นโค้ดของการทำงานของโปรแกรม

roll_dice.py
from secrets import randbelow
from time import sleep

print("Rolling dice...")

time = 320

for i in range(8):
    n = randbelow(6) + 1
    print("\r%d" % n, end = "")
    sleep(time / 1000)
    time = time - 40

print("\nDone")

นี่เป็นผลลัพธ์การทำงานของโปรแกรม ซึ่งการรันโปรแกรมนั้นเปรียบเสมือนกับการที่เราทอยลูกเต๋าจริงๆ

Rolling dice...
3
Done

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

for i in range(8):
    ...

เพืื่อแสดงแอนิเมชันของการทอยลูกเต๋า เราใช้คำสั่ง for loop ในการสุ่มตัวเลขเป็นจำนวน 8 ครั้งและแสดงมันออกทางหน้าจอ สำหรับการแสดงครั้งถัดไปเราได้ลบการแสดงครั้งก่อนหน้าออกไป ด้วยตัวอักษรพิเศษ \r ที่กำหนดในฟังก์ชัน print()

sleep(time / 1000)
time = time - 40

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

n = randbelow(6) + 1

เนื่องจากลูกเต๋านั้นมี 6 หน้า ดังนั้นเราใช้ฟังก์ชัน randbelow() ในการสุ่มตัวเลขจำนวนเต็มจาก 1 - 6 ซึ่งหมายถึงแต่ละหน้าของลูกเต๋า

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการสุ่มตัวเลขในภาษา Python เราได้พูดถึงการใช้ฟังก์ชันสำหรับสุ่มตัวเลขในรูปแบบต่างๆ การสุ่มแบบ PSRNG ซึ่งเป็นวิธีการสุ่มพื้นฐานที่ใช้ Random seed ในการสุ่ม และการสุ่มตัวเลขแบบ CPRNG สำหรับการสุ่มตัวเลขแบบธรรมชาติ