คำนวณผกผันแบบแยกส่วน


16

ได้รับสองตัวเลขบวกxและnมีเขียนฟังก์ชั่นที่สั้นที่สุดในการคำนวณx<2^n x^-1 mod 2^nในคำอื่น ๆ พบดังกล่าวว่าyx*y=1 mod 2^n

ฟังก์ชั่นของคุณจะต้องเสร็จสิ้นในเวลาที่เหมาะสมสำหรับอย่างน้อยการn=64ค้นหาที่ละเอียดถี่ถ้วนจะไม่ทำงาน

หากไม่มีค่าผกผันคุณจะต้องระบุให้ผู้โทรทราบ (ส่งข้อยกเว้นส่งคืนค่า Sentinel และอื่น ๆ )

หากคุณสงสัยว่าจะเริ่มต้นลองขยายยุคลิดอัลกอริทึม


นี่จะเป็นคำแถลงเดียวในโปรแกรมคณิตศาสตร์บางตัว
4477 st0le

1
@ st0le: ถูกต้องและคุณจะไม่ได้รับอนุญาตให้ใช้ฟังก์ชั่นดังกล่าวในระบบดังกล่าว :-D
Chris Jester-Young

คำตอบ:


2

Python 95 89

cเป็นหน้าที่ของคุณ ส่งกลับค่า 0 หากไม่มีการผกผัน (เช่นเมื่อ x เป็นเลขคู่)

p=lambda x,y,m:y and p(x,y/2,m)**2*x**(y&1)%m or 1
c=lambda x,n:[0,p(x,2**n-1,2**n)][x%2]

3

Python ขนาด 29 ไบต์

lambda x,n:pow(x,2**n-1,2**n)

ผลตอบแทน 0 สำหรับแม้แต่x มันใช้ทฤษฎีบทของออยเลอร์โดยมีการสังเกตว่า 2 ^ n - 1 สามารถหารด้วย 2 ^ ( n - 1) - 1, ผ่าน Python ในการยกกำลังแบบแยกส่วนที่รวดเร็ว นี่เร็วพอสำหรับnมากถึง 7000 หรือมากกว่านั้นซึ่งมันเริ่มใช้เวลานานกว่าหนึ่งวินาที


2

Mathematica - 22

f=PowerMod[#,-1,2^#2]&

f[x,n]กลับมาyพร้อมกับx*y=1 mod 2^nมิฉะนั้นx is not invertible modulo 2^n


2

GolfScript (23 ตัวอักษร)

{:^((1${\.**2^?%}+*}:f;

0ผลแมวมองหาผกผันไม่ได้มีอยู่คือ

นี้เป็นโปรแกรมที่เรียบง่ายของทฤษฎีบทออยเลอร์ ดังนั้น x - 1x 2 n - 1 - 1xφ(2n)1(mod2n)x1x2n11(mod2n)

น่าเสียดายที่มันค่อนข้างใหญ่เกินกว่าจะเป็นเลขชี้กำลังในการคำนวณโดยตรงดังนั้นเราต้องใช้การวนซ้ำและทำการลดแบบแยกส่วนภายในวง ขั้นตอนซ้ำคือและเรามีตัวเลือกฐานกรณี: ทั้งที่มีx2k1=(x2k11)2×xk=1

{1\:^(@{\.**2^?%}+*}:f;

หรือk=2กับ

{:^((1${\.**2^?%}+*}:f;

ฉันกำลังทำงานในแนวทางอื่น แต่แมวมองนั้นยากกว่า

การสังเกตที่สำคัญคือเราสามารถสร้างสิ่งที่ตรงกันข้ามได้ทีละนิด: ถ้าxy1(mod2k1)xy{1,1+2k1}(mod2k)xx(y+xy1)1(mod2k)y=(x+1)y1

0x1(mod20)

x(1(x+1)nx)1(mod2n)

x+1

นั่นให้ฟังก์ชัน 19-char

{1$)1$?@/~)2@?%}:f;

xx&11

{1$.1&+1$?@/~)2@?%}:f;

02n1

01(x+1)n11n

{1$.1&*)1$?@/~)2@?%}:f;

nn x f

{..1&*)2$?\/~)2@?%}:f;

1

Ruby - 88 ตัวอักษร

fใช้ฟังก์ชั่น

def e a,b;a%b==0?[0,1]:(x,y=e(b,a%b);[y,x-(y*(a/b))])end
def f x,n;e(x,2**n)[0]*(x%2)end

เพียงแค่ฟังก์ชั่นวนซ้ำจากหน้าวิกิที่เชื่อมโยงแล้วส่งคืนข้อผิดพลาด 0


คุณสามารถบันทึกตัวอักษรบางตัวโดย inlining (e=->a,b{...})[x,2**n][0]E: ยังสามารถบันทึกตัวอักษรโดยการทดสอบแทนa%b<1 a%b==0
ประวัติศาสตร์ 24

1

Haskell, 42 ไบต์

_!1=1
x!n|r<-x!div(n+1)2=(2-r*x)*r`mod`2^n

ใช้อัลกอริธึมตามบทแทรกของ Henselที่เพิ่มจำนวนตัวเลขเป็นสองเท่าในการวนซ้ำทุกครั้งการดำเนินการนี้ใช้เวลาไม่เกินหนึ่งวินาทีสำหรับnสูงถึงประมาณ 30 ล้าน !


1

Pyth , 9 ไบต์

.^Et^2Q^2

ลองที่นี่!

รับอินพุตในลำดับย้อนกลับ หรือ 9 .^EtK^2QKไบต์เกินไป:

คำอธิบาย

. ^ Et ^ 2Q ^ 2 - โปรแกรมเต็มรูปแบบ

. ^ - ฟังก์ชั่น Pow เหมือนกันใน Python (pow)
  E - อินพุตที่สอง
    ^ 2Q - และ 2 ^ อินพุตแรก
   t - ลดลง
       ^ 2 - และ 2 ^ ป้อนข้อมูลครั้งแรกอีกครั้ง

0

GAP, 39 ไบต์

f:=function(x,n)return 1/x mod 2^n;end;

f(x,n)ส่งคืนค่าผกผันของxโมดูโล2^nและให้ข้อความแสดงข้อผิดพลาด

Error, ModRat: for <r>/<s> mod <n>, <s>/gcd(<r>,<s>) and <n> must be coprime

ถ้าไม่มีสิ่งที่ตรงกันข้าม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.