โมดูลผกผันการคูณแบบแยกส่วน


22

งานของคุณคือกำหนดตัวเลขจำนวนเต็มสองจำนวนaและbคำนวณค่าผกผันการคูณแบบแยกส่วนของโมดูโล b หากมีอยู่

ผกผันแบบแยกส่วนของaโมดูโลbเป็นจำนวนดังกล่าวว่าc ac ≡ 1 (mod b)หมายเลขนี้เป็นโมดูโลที่ไม่ซ้ำกันbสำหรับคู่ใด ๆและa bมันมีอยู่เฉพาะในกรณีที่ตัวหารร่วมมากของaและเป็นb1

หน้าวิกิพีเดียสำหรับผกผัน modular สามารถปรึกษาถ้าคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อ

อินพุตและเอาต์พุต

อินพุตถูกกำหนดเป็นทั้งสองจำนวนเต็มหรือรายการของสองจำนวนเต็ม โปรแกรมของคุณควรส่งออกหมายเลขเดียวอินเวอร์สมัลติคูณแบบแยกส่วนที่อยู่ในช่วงเวลา0 < c < bหรือค่าที่ระบุว่าไม่มีอินเวอร์ส ค่าสามารถเป็นอะไรก็ได้ยกเว้นตัวเลขในช่วง(0,b)และอาจเป็นข้อยกเว้น อย่างไรก็ตามค่าควรจะเหมือนกันสำหรับกรณีที่ไม่มีค่าผกผัน

0 < a < b สามารถสันนิษฐานได้

กฎระเบียบ

  • โปรแกรมควรเสร็จในบางจุดและควรแก้แต่ละกรณีทดสอบในเวลาน้อยกว่า 60 วินาที
  • ช่องโหว่มาตรฐานใช้

กรณีทดสอบ

กรณีทดสอบด้านล่างมีให้ในรูปแบบ a, b -> output

1, 2 -> 1
3, 6 -> Does not exist
7, 87 -> 25
25, 87 -> 7
2, 91 -> 46
13, 91 -> Does not exist
19, 1212393831 -> 701912218
31, 73714876143 -> 45180085378
3, 73714876143 -> Does not exist

เกณฑ์การให้คะแนน

นี่คือรหัสกอล์ฟดังนั้นรหัสที่สั้นที่สุดสำหรับแต่ละภาษาจะชนะ

นี่และนี่เป็นคำถามที่คล้ายกัน แต่ทั้งคู่ถามถึงสถานการณ์ที่เฉพาะเจาะจง


6
มันตามมาจากทฤษฎีบทเล็ก ๆ ของแฟร์มาต์ซึ่งการคูณของ a หากมีอยู่สามารถคำนวณได้อย่างมีประสิทธิภาพในรูปแบบ ^ (phi (b) -1) mod b โดยที่ phi เป็นฟังก์ชัน totient ของออยเลอร์: phi (p0 ^ k0 * p1 ^ k1 * ... ) = (p0-1) * p0 ^ (k0-1) * (p1-1) * p1 ^ (k1-1) * ... ไม่ได้บอกว่ามันจะนำไปสู่รหัสที่สั้นลง :)
ngn

1
@Jenny_mathy ไม่อนุญาตให้ป้อนข้อมูลเพิ่มเติมโดยทั่วไป
Mr. Xcoder

3
ฉันนับหกคำตอบที่ดูเหมือนว่าจะบังคับให้เดรัจฉานและไม่น่าจะเรียกใช้กรณีทดสอบทั้งหมดใน 60 วินาที (บางคำให้สแต็กหรือข้อผิดพลาดของหน่วยความจำก่อน)
Ørjan Johansen

1
@ngn: คุณได้พูดถึงทฤษฎีบทเล็ก ๆ น้อย ๆ ของแฟร์มาต์ด้วยการปรับปรุงของออยเลอร์ แฟร์มาต์ไม่ทราบเกี่ยวกับฟังก์ชั่นออยเลอร์พี นอกจากนี้การปรับปรุง FLT และออยเลอร์จะใช้เฉพาะถ้า gcd (a, b) = 1 ในที่สุดในรูปแบบที่คุณเขียนว่า "a ^ (\ phi (b) -1) mod b" สอดคล้องกับ 1 ไม่ใช่ ^ (- 1) ในการรับ ^ (- 1) ให้ใช้ ^ (\ phi (b) -2) mod b
Eric Towers

1
@EricTowers ออยเลอร์เป็นผลมาจาก เกี่ยวกับ "gcd (a, b) = 1" - ฉันพูดว่า "ถ้ามัน [การผกผัน] มีอยู่" คุณแน่ใจเกี่ยวกับ phi (b) -2 หรือไม่
ngn

คำตอบ:


11

Mathematica ขนาด 14 ไบต์

บังคับ Mathematica builtin :

ModularInverse

เป็นฟังก์ชันที่รับอาร์กิวเมนต์สองตัว ( aและb) และส่งกลับค่าผกผันของ mod b หากมีอยู่ ModularInverse: a is not invertible modulo b.ถ้าไม่ได้ก็จะส่งกลับข้อผิดพลาด


7

JavaScript (ES6), 79 73 62 61 ไบต์

ส่งคืนfalseถ้าไม่มีค่าผกผัน

มันใช้อัลกอริทึมแบบยุคลิดแบบขยายและแก้กรณีทดสอบเกือบทั้งหมดในทันที

f=(a,b,c=!(n=b),d=1)=>a?f(b%a,a,d,c-(b-b%a)/a*d):b<2&&(c+n)%n

กรณีทดสอบ


เหตุใดจึงไม่สามารถเขียนชื่อของฟังก์ชัน f เช่นเดียวกับใน f (c, a, b = 0, d = 1, n = a) => c? f (a% c, c, d, b- ( aa% c) / c * d, n): a <2 && (b + n)% n?
RosLuP

@RosLup f(x,y)มีการแยกวิเคราะห์เป็นการเรียกใช้ฟังก์ชันเสมอยกเว้นว่าfunctionคำหลักนั้นนำหน้าอย่างชัดเจน ในทางตรงกันข้ามฟังก์ชั่นลูกศรที่ไม่ระบุชื่อจะถูกประกาศเป็น(x,y)=>somethingและf=(x,y)=>somethingกำหนดฟังก์ชั่นให้กับfตัวแปร
Arnauld

4

เยลลี่ 2 ไบต์

æi

ลองออนไลน์!

สิ่งนี้ใช้ builtin สำหรับโมดุลผกผันและส่งกลับค่า 0 สำหรับไม่มีการผกผันโมดูลาร์

เยลลี่ขนาด 7 ไบต์

R×%⁸’¬T

ลองออนไลน์!

เอาต์พุตชุดว่าง (แสดงเป็นสตริงว่าง) บนไม่มีการกลับกันแบบแยกส่วน หน่วยความจำหมดใน TIO สำหรับกรณีทดสอบที่ใหญ่ที่สุด แต่ควรได้รับหน่วยความจำเพียงพอ

มันทำงานอย่างไร

R×%⁸’¬T  
R        Generate range of b
 ×       Multiply each by a
  %⁸     Mod each by b
    ’    Decrement (Map 1 to 0 and all else to truthy)
     ¬   Logical NOT
      T  Get the index of the truthy element.

หากคุณต้องการทำงานสำหรับกรณีทดสอบที่ใหญ่กว่าให้ลองรุ่น (ค่อนข้างไม่ได้รับการดูแล) ซึ่งต้องใช้เวลามากกว่าหน่วยความจำ:

เยลลี่ขนาด 9 ไบต์

×⁴%³’¬ø1#

ลองออนไลน์!

มันทำงานอย่างไร

×⁴%³’¬ø1#
        #   Get the first
      ø1      one integer
            which meets:
×⁴            When multiplied by a
  %³          And modulo-d by b
    ’         Decrement
     ¬        Is falsy

4

Python 2 , 34 ไบต์

f=lambda a,b:a==1or-~b*f(-b%a,a)/a

ลองออนไลน์!

ฟังก์ชั่นที่ช่วยให้ซ้ำTrueสำหรับprint f(1,2)ซึ่งผมเชื่อว่าจะได้รับการยอมรับและข้อผิดพลาดสำหรับปัจจัยการผลิตที่ไม่ถูกต้อง

เรากำลังพยายามที่จะหาxในx 1ax1(modb) )

นี้สามารถเขียนเป็นx - 1 = k ที่kเป็นจำนวนเต็มax1=kbk

สละ modaนี้ให้1kb(moda) . ) การย้ายเครื่องหมายลบให้kb1(moda)ที่เราต้องแก้ปัญหาสำหรับkk

การเห็นว่ามันคล้ายกับสถานการณ์เริ่มต้นทำให้เราสามารถแก้ปัญหาkด้วยการเรียกใช้ฟังก์ชันด้วยf(b%a,a) (ใช้งานได้เพราะ Python ให้ค่าบวกสำหรับโมดูโลที่มีอาร์กิวเมนต์เป็นลบ)

โปรแกรมจะเรียกใช้ซ้ำจนกระทั่งaกลายเป็น 1 ซึ่งจะเกิดขึ้นหากaและbดั้งเดิมเป็น coprime ซึ่งกันและกัน (เช่นมีการคูณแบบผกผัน) หรือสิ้นสุดลงในข้อผิดพลาดที่เกิดจากการหารด้วย 0

ค่าkนี้สามารถทดแทนได้ในสมการax1=kbเพื่อให้xเป็นkb+1a .


3

หมายเลขR + 15 ไบต์

numbers::modinv

ผลตอบแทนNAสำหรับผู้ที่โดยไม่ต้องแปรผกผันกันพอควรab

ลองเล่น R-Fiddle กัน!

R , 33 ไบต์ (ไม่ใช่การแข่งขัน)

สิ่งนี้จะล้มเหลวในขนาดที่ใหญ่มากbเพราะมันสร้างเวกเตอร์ขนาด32*bบิต

function(a,b)which((1:b*a)%%b==1)

ลองออนไลน์!

ผลตอบแทนinteger(0)(รายการที่ว่างเปล่า) สำหรับผู้ที่โดยไม่ต้องแปรผกผันกันพอควรab



3

Python 2 , 51 49 54 53 51 49 ไบต์

-1 ไบต์ขอบคุณอย่างเป็นทางการข้อมูล
-1 ไบต์ขอบคุณกับ Shaggy

a,b=input()
i=a<2
while(a*i%b-1)*b%a:i+=1
print+i

ลองออนไลน์!

พิมพ์0เมื่อไม่มีวิธีแก้ไข


1
ผลลัพธ์0สำหรับa=1และb=2; 1จากกรณีทดสอบก็ควรเอาท์พุท
Shaggy


1
ในฐานะที่เป็น Shaggy ชี้ให้เห็นว่าล้มเหลวสำหรับ2, 1
นาย Xcoder

@Shaggy ควรทำงานตอนนี้
Rod

นี้ล้มเหลวที่จะกลับคำตอบใน 60 วินาที (เมื่อ TIO) 31,73714876143สำหรับการป้อนข้อมูล
Ilmari Karonen

3

Japt , 9 8 ไบต์

รับอินพุตในลำดับย้อนกลับ เอาต์พุต-1ไม่ตรง เล่นลูกเต๋าชนิดหนึ่งออกมาเป็นจำนวนเต็มขนาดใหญ่ที่ใหญ่กว่า

Ç*V%UÃb1

ทดสอบมัน

  • บันทึก 1 ไบต์ขอบคุณ ETH ที่ชี้ให้เห็นว่ามีพื้นที่ว่างเปล่าและชัดเจนมาก

อินพุตทดสอบ73714876143,31ดูเหมือนว่าจะทำให้เกิดข้อผิดพลาดหน่วยความจำไม่เพียงพอใน Firefox (และขัดข้องกับ Chromium) ฉันไม่คิดว่านี่เป็นคำตอบที่ถูกต้อง
Ilmari Karonen

@IlmariKaronen: ฉันชี้ให้เห็นอย่างชัดเจนว่าความจริงในการแก้ปัญหาของฉัน เราสามารถใช้หน่วยความจำที่ไม่มีที่สิ้นสุดสำหรับจุดประสงค์ของการเขียนโค้ดดังนั้นปัญหาหน่วยความจำและการล่มจึงไม่ทำให้การแก้ไขนี้เป็นโมฆะ
ปุย

1
น่าเสียดายที่ปัญหาด้านหน่วยความจำทำให้มันเป็นไปไม่ได้ที่จะบอกว่ารหัสของคุณจะแก้ปัญหากรณีทดสอบภายใน 60 วินาทีตามที่กำหนดโดยการท้าทาย ฉันสงสัยว่ามันจะไม่แม้ว่าจะมีหน่วยความจำเพียงพอที่จะทำให้มันล้มเหลว แต่ไม่มีคอมพิวเตอร์ที่สามารถใช้งานโปรแกรมได้ในระยะเวลานานจริง ๆ ไม่มีวิธีที่จะบอกได้อย่างแน่นอน
Ilmari Karonen


2

Python 3 , 49 ไบต์

lambda a,b:[c for c in range(b)if-~c*a%b==1][0]+1

ลองออนไลน์!

Python 3 , 50 ไบต์

lambda a,b:[c for c in range(1,b+1)if c*a%b==1][0]

ลองออนไลน์!

สิ่งนี้จะเกิดขึ้นIndexError: list index out of rangeในกรณีที่ไม่มีการผกผันแบบแยกส่วนโมดูลาร์เนื่องจากได้รับอนุญาตจากกฎ


สิ่งนี้ล้มเหลวในการส่งคืนผลลัพธ์สำหรับอินพุต31,73714876143ใน 60 วินาที (บน TIO)
Ilmari Karonen

@IlmariKaronen ดูเหมือนว่าจะเสร็จใน 56 วินาทีบนเครื่องของฉัน (Macbook Pro '15)
Mr. Xcoder

2

8th , 6 ไบต์

รหัส

invmod

คำอธิบาย

invmodเป็นคำที่ 8 ที่คำนวณค่าผกผันของa, bโมดูโล มันกลับมาnullจากการล้นหรือข้อผิดพลาดอื่น ๆ

กรณีการใช้งานและการทดสอบ

ok> 1 2 invmod .
1
ok> 3 6 invmod .
null
ok> 7 87 invmod .
25
ok> 25 87 invmod .
7
ok> 2 91 invmod .
46
ok> 13 91 invmod .
null
ok> 19 1212393831 invmod .
701912218
ok> 31 73714876143 invmod .
45180085378
ok> 3 73714876143 invmod .
null


2

J , 28 ไบต์

4 :'(1=x+.y)*x y&|@^<:5 p:y'

ลองออนไลน์!

ใช้ทฤษฎีบทออยเลอร์ ส่งคืนค่า 0 หากไม่มีอินเวิร์สต์อยู่

คำอธิบาย

4 :'(1=x+.y)*x y&|@^<:5 p:y'  Input: a (LHS), b (RHS)
4 :'                       '  Define an explicit dyad - this is to use the special
                              form `m&|@^` to perform modular exponentiation
                          y   Get b
                      5 p:    Euler totient
                    <:        Decrement
             x                Get a
                   ^          Exponentiate
               y&|@             Modulo b
       x+.y                   GCD of a and b
     1=                       Equals 1
            *                 Multiply

2

Pyth , 10 ไบต์

3 ไบต์บันทึกขอบคุณที่ @Jakube

xm%*szdQQ1

ลองที่นี่!

ส่งคืน-1สำหรับการไม่ผกผันทวีคูณ

การแยกรหัส

xm%*szdQQ1      Let Q be the first input.
 m      Q       This maps over [0 ... Q) with a variable d.
   *szd         Now d is multiplied by the evaluated second input.
  %    Q        Now the remained modulo Q is retrieved.
x        1      Then, the first index of 1 is retrieved from that mapping.

Pyth , 15 13 ไบต์

KEhfq1%*QTKSK

ส่งข้อยกเว้นในกรณีที่ไม่มีการผกผันทวีคูณ

ลองที่นี่!

Pyth , 15 ไบต์

Iq1iQKEfq1%*QTK

เพิ่มจำนวนไบต์สำหรับการจัดการกรณีที่ไม่มีหมายเลขดังกล่าว โปรแกรมสามารถย่อให้สั้นลงได้อย่างมากหากกรณีนั้นไม่จำเป็นต้องจัดการ:

fq1%*QTK

ลองที่นี่!


บันทึก 2 ไบต์ด้วยKExm%*QdKK1
Jakube

หรือ 3 ไบต์หากคุณสลับลำดับของอินพุต:xm%*szdQQ1
Jakube

@Jakube ขอบคุณมากการแก้ไข!
Mr. Xcoder

มันทำงานอย่างไร
Kritixi Lithos

@ Cowquack ฉันได้เพิ่มการแบ่งรหัสดั้งเดิมทั้งหมด แต่ rn ฉันไม่มีเวลาที่จะรวมคำอธิบายที่สมบูรณ์ หวังว่าจะชัดเจนเพียงพอในตอนนี้ แต่ฉันจะพยายามเพิ่มคำอธิบายที่สมบูรณ์ยิ่งขึ้นในไม่ช้า
Mr. Xcoder

1

C (gcc) , 115 ไบต์

#define L long long
L g(L a,L b,L c,L d){return a?g(b%a,a,d-b/a*c,c):b-1?0:d;}L f(L a,L b){return(g(a,b,1,0)+b)%b;}

ลองออนไลน์!

อัลกอริทึมแบบยุคลิดแบบขยาย, เวอร์ชั่นแบบเรียกซ้ำ

C (gcc) , 119 ไบต์

long long f(a,b,c,d,t,n)long long a,b,c,d,t,n;{for(c=1,d=0,n=b;a;a=t)t=d-b/a*c,d=c,c=t,t=b%a,b=a;return b-1?0:(d+n)%n;}

ลองออนไลน์!

อัลกอริธึมแบบขยายแบบยุคลิดรุ่นซ้ำ


1

C (gcc) , 48 110 104 ไบต์

#define f(a,b)g(a,b,!b,1,b)
long g(a,b,c,d,n)long a,b,c,d,n;{a=a?g(b%a,a,d,c-(b-b%a)/a*d):!--b*(c+n)%n;}

ลองออนไลน์!

สิ่งนี้จะทำงานกับอินพุตทั้งหมด (ที่พอดีภายในเวลานาน) ภายใน 60 วินาที

แก้ไข ฉันได้เหยียดหยามnตัวแปรดังนั้นฉันเช่นกันอาจจะคิดว่า GCC %raxทำให้การกำหนดครั้งแรกใน


1
อนิจจาสิ่งนี้ให้ผลที่ผิดแม้สำหรับอินพุตที่ค่อนข้างเล็กเนื่องจากจำนวนเต็มล้นภายในลูป ตัวอย่างเช่นf(3,1000001)ส่งคืน 717 ซึ่งเห็นได้ชัดว่าไร้สาระ (คำตอบที่ถูกต้องคือ 333334) ยิ่งไปกว่านั้นแม้ว่าข้อผิดพลาดนี้ได้รับการแก้ไขโดยการใช้ประเภทจำนวนเต็มที่กว้างขึ้นวิธีการบังคับแบบเดรัจฉานนี้จะหมดเวลาสำหรับกรณีทดสอบที่มีขนาดใหญ่กว่าที่กำหนดในการท้าทาย
Ilmari Karonen


0

ความจริง 45 ไบต์

f(x:PI,y:PI):NNI==(gcd(x,y)=1=>invmod(x,y);0)

0 สำหรับข้อผิดพลาดอื่นส่งคืน z ด้วย x * z Mod y = 1


0

Python 2 , 52 ไบต์

-3 ไบต์ขอบคุณ Mr. Xcoder

f=lambda a,b,i=1:i*a%b==1and i or i<b and f(a,b,i+1)

ลองออนไลน์!

เอาต์พุตFalseไม่มีการแก้ปัญหาและข้อผิดพลาดตามที่bได้รับที่ใหญ่ขึ้น

สมองกลฝังตัว TIO

ฉันแค่ทดสอบ iframes ใน Stack Snippets และมันก็ทำงานได้อย่างยอดเยี่ยม


ฉันไม่แน่ใจงานนี้ไม่สามารถi*a%bจะเป็น0?
ข้าวสาลีตัวช่วยสร้าง

ล้มเหลวด้วย "ความลึก recursion สูงสุดเกินข้อผิดพลาด" (31,73714876143)สำหรับการป้อนข้อมูล
Ilmari Karonen

0

JavaScript (ES6), 42 41 39 38 ไบต์

เอาต์พุตfalseไม่ตรง จะส่งข้อผิดพลาดมากเกินไปเนื่องจากหมายเลขที่สองจะใหญ่เกินไป

x=>y=>(g=z=>x*z%y==1?z:z<y&&g(++z))(1)

0

เยลลี่ , 27 ไบต์

²%³
⁴Ç⁹Сx⁸
ÆṪ’BṚçL$P%³×gỊ¥

ลองออนไลน์!

ใช้ทฤษฎีบทของออยเลอร์พร้อมการยกกำลังแบบแยกส่วน เนื่องจากเจลลี่ไม่มีบิวอินเพื่อดำเนินการยกกำลังแบบแยกส่วนจึงต้องมีการติดตั้งและใช้เวลาส่วนใหญ่เป็นไบต์


0

ความจริง 99 ไบต์

w(a,b,x,u)==(a=0=>(b*b=1=>b*x;0);w(b rem a,a,u,x-u*(b quo a)));h(a,b)==(b=0=>0;(b+w(a,b,0,1))rem b)

มันใช้ฟังก์ชั่น h (); h (a, b) return 0 ถ้า error [ไม่มีอยู่ inverse] มิฉะนั้นมันจะคืนค่า z ที่ a * z mod b = 1 สิ่งนี้จะใช้ได้แม้ว่าอาร์กิวเมนต์จะเป็นลบ ...

นี่จะเป็นฟังก์ชัน egcd () ทั่วไปที่ retunr รายการของ int (เพื่อให้พวกเขาสามารถลบเกินไป)

egcd(aa:INT,bb:INT):List INT==
   x:=u:=-1   -- because the type is INT
   (a,b,x,u):=(aa,bb,0,1)
   repeat
      a=0=>break
      (q,r):=(b quo a, b rem a)
      (b,a,x,u):=(a,r,u,x-u*q)
   [b,x, (b-x*aa)quo bb]

นี่คือวิธีการใช้งาน

(7) -> h(31,73714876143)
   (7)  45180085378
                                                    Type: PositiveInteger

ฉันค้นหาฐานในอินเทอร์เน็ตจากhttps://pastebin.com/A13ybryc

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