หมายเลขคริสตจักรเป็นการเข้ารหัสตัวเลขธรรมชาติเป็นฟังก์ชัน
(\ f x → (f x)) -- church number 1
(\ f x → (f (f (f x)))) -- church number 3
(\ f x → (f (f (f (f x))))) -- church number 4
อย่างเรียบร้อยคุณสามารถยกกำลัง 2 หมายเลขคริสตจักรได้โดยใช้มัน นั่นคือถ้าคุณใช้ 4-2 คุณจะได้รับจำนวนคริสตจักรหรือ16
2^4
เห็นได้ชัดว่านั่นเป็นเรื่องที่ไม่สามารถเกิดขึ้นได้จริง จำนวนคริสตจักรต้องการหน่วยความจำเชิงเส้นและช้ามากจริงๆ การประมวลผลสิ่ง10^10
ที่ GHCI ตอบได้อย่างรวดเร็วจะใช้เวลานานและไม่สามารถใส่หน่วยความจำบนคอมพิวเตอร์ของคุณได้
ฉันได้ทำการทดลองกับผู้ประเมินที่เหมาะสมที่สุดเมื่อเร็ว ๆ นี้ ในการทดสอบของฉันฉันบังเอิญพิมพ์สิ่งต่อไปนี้ใน calculator-Calculator ที่ดีที่สุดของฉัน:
10 ^ 10 % 13
มันควรจะเป็นการคูณไม่ใช่การยกกำลัง ก่อนที่ฉันจะขยับนิ้วเพื่อยกเลิกโปรแกรมที่ทำงานตลอดไปด้วยความสิ้นหวังมันตอบคำขอของฉัน:
3
{ iterations: 11523, applications: 5748, used_memory: 27729 }
real 0m0.104s
user 0m0.086s
sys 0m0.019s
เมื่อ "การแจ้งเตือนข้อบกพร่อง" ของฉันกะพริบฉันจึงไปที่ Google และได้รับการยืนยัน10^10%13 == 3
แล้ว แต่เครื่องคิดเลขλไม่ควรจะหาผลลัพธ์นั้นมันแทบจะไม่สามารถเก็บ 10 ^ 10 ได้ ฉันเริ่มเครียดสำหรับวิทยาศาสตร์ มันทันทีตอบฉัน20^20%13 == 3
, ,50^50%13 == 4
60^60%3 == 0
ฉันต้องใช้เครื่องมือภายนอกเพื่อตรวจสอบผลลัพธ์เหล่านั้นเนื่องจากHaskell เองไม่สามารถคำนวณได้ (เนื่องจากจำนวนเต็มล้น) (แน่นอนว่าถ้าคุณใช้จำนวนเต็มไม่ใช่ Ints!) ผลักดันให้ถึงขีด จำกัด นี่คือคำตอบของ200^200%31
:
5
{ iterations: 10351327, applications: 5175644, used_memory: 23754870 }
real 0m4.025s
user 0m3.686s
sys 0m0.341s
ถ้าเรามีจักรวาลหนึ่งสำเนาสำหรับแต่ละอะตอมในจักรวาลและเรามีคอมพิวเตอร์สำหรับแต่ละอะตอมที่เรามีทั้งหมดเราไม่สามารถจัดเก็บหมายเลขคริสตจักร200^200
ได้ สิ่งนี้ทำให้ฉันตั้งคำถามว่า mac ของฉันมีประสิทธิภาพขนาดนั้นจริงๆหรือ บางทีผู้ประเมินที่เหมาะสมที่สุดก็สามารถข้ามสาขาที่ไม่จำเป็นและมาถึงคำตอบได้ในแบบเดียวกับที่ Haskell ทำด้วยการประเมินแบบขี้เกียจ เพื่อทดสอบสิ่งนี้ฉันรวบรวมโปรแกรมλไปที่ Haskell:
data Term = F !(Term -> Term) | N !Double
instance Show Term where {
show (N x) = "(N "++(if fromIntegral (floor x) == x then show (floor x) else show x)++")";
show (F _) = "(λ...)"}
infixl 0 #
(F f) # x = f x
churchNum = F(\(N n)->F(\f->F(\x->if n<=0 then x else (f#(churchNum#(N(n-1))#f#x)))))
expMod = (F(\v0->(F(\v1->(F(\v2->((((((churchNum # v2) # (F(\v3->(F(\v4->(v3 # (F(\v5->((v4 # (F(\v6->(F(\v7->(v6 # ((v5 # v6) # v7))))))) # v5))))))))) # (F(\v3->(v3 # (F(\v4->(F(\v5->v5)))))))) # (F(\v3->((((churchNum # v1) # (churchNum # v0)) # ((((churchNum # v2) # (F(\v4->(F(\v5->(F(\v6->(v4 # (F(\v7->((v5 # v7) # v6))))))))))) # (F(\v4->v4))) # (F(\v4->(F(\v5->(v5 # v4))))))) # ((((churchNum # v2) # (F(\v4->(F(\v5->v4))))) # (F(\v4->v4))) # (F(\v4->v4))))))) # (F(\v3->(((F(\(N x)->F(\(N y)->N(x+y)))) # v3) # (N 1))))) # (N 0))))))))
main = print $ (expMod # N 5 # N 5 # N 4)
สิ่งนี้ได้ผลลัพธ์ที่ถูกต้อง1
( 5 ^ 5 % 4
) - แต่โยนอะไรไว้ข้างบน10^10
แล้วมันจะค้างทำให้กำจัดสมมติฐานออกไป
ตัวประเมินที่ดีที่สุดที่ฉันใช้คือโปรแกรม JavaScript ยาว 160 บรรทัดที่ไม่ได้เพิ่มประสิทธิภาพซึ่งไม่มีคณิตศาสตร์โมดูลัสเอกซ์โพเนนเชียลใด ๆ และฟังก์ชันโมดูลัสแลมดูลัสแคลคูลัสที่ฉันใช้ก็ง่ายพอ ๆ กัน:
(λab.(b(λcd.(c(λe.(d(λfg.(f(efg)))e))))(λc.(c(λde.e)))(λc.(a(b(λdef.(d(λg.(egf))))(λd.d)(λde.(ed)))(b(λde.d)(λd.d)(λd.d))))))
ฉันไม่ได้ใช้อัลกอริทึมหรือสูตรเลขคณิตแบบแยกส่วนเฉพาะ ดังนั้นผู้ประเมินที่เหมาะสมจะได้รับคำตอบที่ถูกต้องได้อย่างไร