คำนวณฟังก์ชัน Carmichael


36

คำอธิบายงาน

ในทฤษฎีจำนวนที่ฟังก์ชั่นคาร์ไมเคิ λใช้เวลาเป็นจำนวนเต็มบวก  nและผลตอบแทนน้อยจำนวนเต็มบวกkเพื่อให้kอำนาจ -th ของแต่ละจำนวนเต็มcoprimeเพื่อnเท่ากับ 1 โมดูโลn

ป.ร. ให้ไว้เป็นจำนวนเต็มบวกn , การแก้ปัญหาของคุณจะต้องคำนวณλ (n) รหัสที่สั้นที่สุดในหน่วยไบต์ชนะ

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

เคล็ดลับ

ลำดับของทุกλ (n)เป็นOEIS A002322

การใช้งาน Python ที่ไม่ได้รับความนิยมจะมีลักษณะเป็น

from fractions import gcd

def carmichael(n):
    coprimes = [x for x in range(1, n) if gcd(x, n) == 1]
    k = 1
    while not all(pow(x, k, n) == 1 for x in coprimes):
        k += 1
    return k

(ใน Python pow(A, B, C)คำนวณอย่างมีประสิทธิภาพpow(A, B) % C)

กรณีทดสอบ

Input    Output
1        1
2        1
3        2
10       4
35       12
101      100
530      52
3010     84
6511     3056
10000    500

ในทางทฤษฎีหมายความว่าอะไรที่นี่? ฉันสามารถสมมติว่าอินพุตnเหมาะสมกับจำนวนเต็ม 16 บิตได้หรือไม่? ฉันสามารถสันนิษฐานได้ว่าn ^ λ (n)เข้ากันได้เป็นสองเท่า
เดนนิส

2
ใช่และใช่ฉันต้องการพูด เช่นเดียวกับในทางทฤษฎีรวมถึงการเสแสร้งประเภทพื้นเมืองของคุณมีความแม่นยำและมีขนาดใหญ่โดยพลการ (ฉันคิดว่านั่นเป็นฉันทามติ แต่ฉันไม่แน่ใจ)
ลินน์

คำตอบ:



29

Python, 76 73 67 ไบต์

f=lambda n,k=1:1-any(a**-~k*~-a**k%n for a in range(n))or-~f(n,k+1)

ลองออนไลน์!

ไบต์ต่อไปอาจจะถูกบันทึกไว้โดยการกลับทรูแทน1

การใช้ทางเลือก

การใช้วิธีการเดียวกันนี้ยังมีการใช้งานต่อไปนี้โดย @feersum ซึ่งไม่ได้ใช้ความเข้าใจในรายการ

f=lambda n,k=1,a=1:a/n or(a**-~k*~-a**k%n<1)*f(n,k,a+1)or-~f(n,k+1)

โปรดทราบว่าการดำเนินการนี้ต้องใช้O (n λ (n) )เวลา ประสิทธิภาพอาจจะดีขึ้นอย่างมากในขณะที่จริงลดลงคะแนนไป66 ไบต์แต่ฟังก์ชั่นจะกลับมาทรูสำหรับใส่2

f=lambda n,k=1,a=1:a/n or~-a**k*a**-~k%n<1==f(n,k,a+1)or-~f(n,k+1)

พื้นหลัง

คำจำกัดความและสัญลักษณ์

ตัวแปรที่ใช้ทั้งหมดจะแสดงถึงจำนวนเต็ม n , kและαจะแสดงในเชิงบวกจำนวนเต็ม; และหน้าจะแสดงเป็นบวกที่สำคัญ

a | ขถ้าคือหารด้วยคือถ้ามีคิวดังกล่าวว่าข = QA

≡ข ( modเมตร)ถ้าและBมีเหมือนกันตกค้าง modulo เมตรเช่นถ้าม | a - b

λ (n)เป็นที่เล็กที่สุดkดังกล่าวว่าk ≡ 1 ( mod n) - คือเช่นว่าn | k - 1 - สำหรับทุกที่มี coprime เพื่อn

f (n)เป็นที่เล็กที่สุดkดังกล่าวว่า2k + 1k + 1 ( mod n) - คือเช่นว่าn | k + 1 (กk - 1) - สำหรับทุก

λ (n) ≤ f (n)

แก้ไขnและให้พ.ศ. coprime เพื่อn

โดยนิยามของf , n | f (n) 1 (กf (n) - 1) ตั้งแต่และnไม่ได้มีปัจจัยสำคัญที่พบบ่อยและก็ไม่f (n) 1และnซึ่งหมายความว่าn | f (n) - 1

เนื่องจากλ (n)เป็นจำนวนเต็มที่น้อยที่สุดkดังนั้นn | k - 1สำหรับจำนวนเต็มทั้งหมดที่มี coprime เพื่อnมันตามที่λ (n) ≤ f (n)

λ (n) = f (n)

เนื่องจากเราได้สร้างความไม่เท่าเทียมกันแล้วλ (n) ≤ f (n)มันก็เพียงพอแล้วที่จะตรวจสอบว่าk = λ (n)เป็นไปตามเงื่อนไขที่กำหนดfคือ ie | λ (n) 1 (กλ (n) - 1)สำหรับทุก เพื่อจุดประสงค์นี้เราจะสร้างp α | a λ (n) +1 (a λ (n) - 1)เมื่อใดก็ตามที่p α | n .

λ (k) | λ (n)เมื่อใดก็ตามที่k | n ( แหล่งที่มา ) ดังนั้น(a λ (k) - 1) (a λ (n) -λ (k) + a λ (n) -2λ (k) + ⋯ + a λ (k) + 1) = a λ (n) - 1และดังนั้นa λ (k) - 1 | a λ (n) - 1 | λ (n) 1 (กλ (n) - 1)

หากและP αมี coprime โดยความหมายของλและข้างต้นP α | a λ (p α ) - 1 | a λ (n) +1 (a λ (n) - 1)ติดตามตามที่ต้องการ

ถ้าa = 0ดังนั้นa λ (n) +1 (a λ (n) - 1) = 0ซึ่งหารด้วยจำนวนเต็มทั้งหมด

ในที่สุดเราต้องพิจารณากรณีที่aและp αมีปัจจัยสำคัญร่วมกัน เนื่องจากpเป็นนายกนี่ก็หมายความว่าp | ก . ทฤษฎีบทของคาร์ไมเคิลกำหนดว่าλ (p α ) = (p - 1) p α - 1ถ้าp> 2หรือα <3และλ (p α ) = p α - 2 เป็นอย่างอื่น ในทุกกรณีλ (P α ) ≥ P α - 2 ≥ 2 α - 2 > α - 2

ดังนั้นλ (n) + 1 ≥λ (p α ) + 1> α - 1ดังนั้นλ (n) + 1 ≥αและp α | p λ (n) +1 | a λ (n) +1 | λ (n) 1 (กλ (n) - 1) นี่เป็นการพิสูจน์ที่สมบูรณ์

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

ในขณะที่คำจำกัดความของf (n)และλ (n)พิจารณาค่าที่เป็นไปได้ทั้งหมดของมันจะเพียงพอที่จะทดสอบผู้ที่โกหกใน[0, ... , n - 1]

เมื่อf (n, k)จะเรียกว่ามันคำนวณk + 1 (กk - 1) n%สำหรับค่าทั้งหมดของในช่วงนั้นซึ่งเป็น0ถ้าหากว่าn | k + 1 (กk - 1)

หากตกค้างคำนวณทั้งหมดเป็นศูนย์K = λ (n)และanyผลตอบแทนที่เป็นเท็จดังนั้นf (n, k)ผลตอบแทนที่1

บนมืออื่น ๆ ในขณะที่k <λ (n) , 1-any(...)จะกลับ0ดังนั้นเรียกว่าซ้ำมีมูลค่าเพิ่มขึ้นของk การนำหน้าจะ-~เพิ่มค่าส่งคืนของf (n, k + 1)ดังนั้นเราจึงเพิ่ม1ถึงf (n, λ (n)) = 1หนึ่งครั้งสำหรับทุกจำนวนเต็มใน[1, ... , λ (n) - 1 ] . ผลสุดท้ายจึงλ (n)


คุณสามารถบันทึกอย่างน้อย 4 ด้วยการเรียกซ้ำได้แทนที่จะเข้าใจรายการ: f=lambda n,k=1,a=1:a/n or(a**k*~-a**k%n<1)*f(n,k,a+2-n%2)or-~f(n,k+1)(เพิ่มกลับหนึ่งไบต์หากคุณไม่ต้องการใช้เวลา n ** λ (n))
feersum

1
ขอบคุณ! ในระหว่างนี้ฉันพบว่าการปรับปรุงอัลกอริทึมของฉันดูเหมือนจะลบล้างประโยชน์ของการเรียกซ้ำแทนที่จะใช้ความเข้าใจในรายการ
Dennis

14

Mathematica ที่ไม่มีในตัว58 57 ไบต์

ขอบคุณ Martin Ender สำหรับการค้นหาข้อผิดพลาดจากนั้นบันทึกไบต์ที่ฉันใช้เพื่อแก้ไข!

ขอบคุณไมล์สำหรับการบันทึก 1 ไบต์! (ซึ่งดูเหมือน 2 ถึงฉัน)

Built-ins สมบูรณ์ดี ... แต่สำหรับผู้ที่ต้องการใช้งานโดยไม่ต้องใช้กำลังดุร้ายนี่เป็นสูตรสำหรับฟังก์ชั่น Carmichael:

LCM@@(EulerPhi[#^#2]/If[#==2<#2,2,1]&@@@FactorInteger@#)&

ถ้า p เป็นนายกฟังก์ชัน Carmichael λ (p ^ r) เท่ากับφ (p ^ r) = (p-1) * p ^ (r-1) - ยกเว้นเมื่อ p = 2 และr≥3ซึ่งในกรณีนี้ ครึ่งหนึ่งคือ 2 ^ (r-2)

และถ้าการแยกตัวประกอบกำลังพิเศษของ n เท่ากับ p1 ^ r1 * p2 ^ r2 * ... , ดังนั้นλ (n) เท่ากับตัวคูณร่วมที่น้อยที่สุดของ {λ (p1 ^ r1), λ (p2 ^ r2), .. .}

รันไทม์เป็นหนึ่งในทันทีมากกว่าการรับจำนวนเต็มตั้งแต่แรก


คุณสามารถใช้EulerPhiเพื่อรับLCM@@(EulerPhi[#^#2]/If[#==2<#2,2,1]&@@@FactorInteger@#)&57 ไบต์
ไมล์

@ ไมล์เห็นได้ชัด! ฉันนับ 56 ไบต์คุณตรวจสอบได้ไหม
Greg Martin

ใช่มัน 57 ไบต์
ไมล์

เห็นได้ชัดว่าฉันพยายามตีนับของฉัน .... : /
Greg Martin

12

เทมเพลตถือว่าเป็นอันตราย 246 ไบต์

Fun<Ap<Fun<If<Eq<A<2>,T>,A<1>,And<Eq<Ap<Fun<If<A<1>,Ap<A<0>,Rem<A<2>,A<1>>,A<1>>,A<2>>>,A<1,1>,A<2>>,T>,Sub<Ap<Fun<Rem<If<A<1>,Mul<A<2,1>,Ap<A<0>,Sub<A<1>,T>>>,T>,A<1,2>>>,A<1>>,T>>,Ap<A<0>,Add<A<1>,T>,A<1,1>>,Ap<A<0>,A<1>,Sub<A<2>,T>>>>,T,A<1>>>

ฟังก์ชั่นที่ไม่มีชื่อ (ไม่ใช่ว่ามีฟังก์ชั่นที่มีชื่อ)

นี่คือ esolang ที่ถูกลืมของฉันซึ่งแปลโดยแม่แบบการแปลอินเทอร์เฟซ C ++ ด้วยความลึกสูงสุดของเทมเพลตเริ่มต้นของg++มันสามารถทำ can (35) แต่ทำไม่ได้ can't (101) (การประเมินแบบขี้เกียจทำให้เรื่องแย่ลง)



8

31
............. ._
Maltysen

10
ฉันไม่เคยเข้าใจจุดประสงค์ของการติดตั้งบิวด์อินเฉพาะที่น่าขัน
ทำให้เสียชีวิต

31
นี่คือเกือบนอกจากภาษาที่ทำขึ้นเป็นพิเศษสำหรับความท้าทายนี้ กระทำโดย Lynn 2 วันที่ผ่านมาท้าทายโดย @Lynn วันนี้
edc65

5
@ edc65 ไม่ต้องพูดถึงว่าตัวในตัวนี้ไม่มีประโยชน์อะไรนอกจากความท้าทายและอนุพันธ์ของมัน
ทำให้เสียชีวิต

3
ฟังก์ชั่นคาร์ไมเคิลมีความสำคัญในทฤษฎีเชิงตัวเลข
Greg Martin

6

Pyth - 19 18 17 ไบต์

บันทึกหนึ่งไบต์ด้วย @TheBikingViking

ตั้งกำลังดุร้ายขึ้น

f!sm*t.^dTQq1iQdQ

ลองมันออนไลน์ได้ที่นี่


f!smtสั้นลงหนึ่งไบต์
TheBikingViking

@ TheBikingViking โอ้ใช่แล้วขอบคุณ
Maltysen

เจ็บฉันสิงูตัวนี้เป็นยังไง .. รักมันมากฮ่าฮ่า :)
โยฮันโอบาเดีย


5

J, 28 27 ไบต์

[:*./@(5&p:%2^0=8&|)2^/@p:]

ฟังก์ชัน Carmichael คือλ ( n ) และฟังก์ชัน totient คือ ient ( n )

ใช้คำจำกัดความที่λ ( p k ) = φ ( p k ) / 2 ถ้าp = 2 และk > 2 อื่นφ ( p k ) จากนั้นสำหรับทั่วไปn = p 1 k 1 p 2 k 2p i k i , λ ( n ) = LCM [λ ( p 1 k 1 ) λ ( p 2 k 2 ) ⋯λ ( p i k i )] .

การใช้

คำสั่งพิเศษที่ใช้ในการจัดรูปแบบอินพุต / เอาท์พุตหลายรายการ

   f =: [:*./@(5&p:%2^0=8&|)2^/@p:]
   f 530
52
   (,.f"0) 1 2 3 10 35 101 530 3010 6511 10000
    1    1
    2    1
    3    2
   10    4
   35   12
  101  100
  530   52
 3010   84
 6511 3056
10000  500

คำอธิบาย

[:*./@(5&p:%2^0=8&|)2^/@p:]  Input: integer n
                          ]  Identity function, get n
                    2   p:   Get a table of prime/exponent values for n
                     ^/@     Raise each prime to its exponent to get the prime powers of n
[:    (            )         Operate on the prime powers
                8&|            Take each modulo 8
              0=               Test if its equal to 0, 1 if true else 0
            2^                 Raise 2 to the power of each
       5&p:                    Apply the totient function to each prime power
           %                   Divide it by the powers of 2
  *./@                       Reduce using LCM and return

นี่จะให้คำตอบที่ผิดสำหรับ 10,000 (1,000 แทนที่จะเป็น 500 ที่ถูกต้อง) และแน่นอนสำหรับทุก ๆ 8 8 2 เป็นนายกที่แปลกประหลาดและλ (2 ^ a) = 2 ^ {a-2} (ไม่ใช่ 2 ^ { a-1}) เมื่อa≥3
Greg Martin

ขอบคุณสำหรับการจับที่ดูเหมือนว่าฉันไม่สามารถอ่านผลลัพธ์ของตัวเอง
ไมล์

บางครั้งคุณก็ไม่ได้อยู่คนเดียว .... :)
Greg Martin

5

ที่จริงแล้ว30 28 25 19 26 ไบต์

ฟังก์ชั่นคาร์ไมเคิλ(n)ที่n = p_0**k_0 * p_1**k_1 * ... * p_a**k_aถูกกำหนดให้เป็นอย่างน้อยหลายที่พบบ่อย (LCM) ของλ(p_i**k_i)สำหรับอำนาจที่สำคัญสูงสุดที่แบ่งออกเป็นp_i**k_i nระบุว่าสำหรับทุกพลังพิเศษยกเว้นตำแหน่งที่สำคัญคือ2ฟังก์ชั่น Carmichael เทียบเท่ากับฟังก์ชัน Totient ของ Euler λ(n) == φ(n)เราใช้φ(n)แทน สำหรับกรณีพิเศษ2**kที่k ≥ 3เราเพียงแค่ตรวจสอบว่า2**3 = 8แบ่งออกเป็นnจุดเริ่มต้นของโปรแกรมและหารด้วย 2 ถ้ามัน

น่าเสียดายจริง ๆ แล้วในปัจจุบันไม่มี LCM ในตัวดังนั้นฉันจึงสร้าง LCM ที่ดุร้าย ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ ลองออนไลน์!

;7&Yu@\w`iⁿ▒`M╗2`╜@♀%ΣY`╓N

Ungolfing

         Implicit input n.
;        Duplicate n.
7&       n&7 == n%8.
Yu       Logical NOT and increment. If n%8 == 0, return 2. Else, return 1.
@\       Integer divide n by 2 if n%8==0, by 1 otherwise.
          Thus, we have dealt with the special case where p_i == 2 and e_i >= 3.
w        Full prime factorization of n as a list of [prime, exponent] lists.
`...`M   Map the following function over the prime factorization.
  i        Flatten the array, pushing exponent, then prime to the stack.
  ⁿ▒       totient(pow(prime, exponent)).
╗        Save that list of totients in register 0.
2`...`╓  Get the first two values of n where the following function f(n) is truthy.
         Those two numbers will be 0 and our LCM.
  ╜@       Push the list in register 0 and swap with our n.
  ♀%       Get n mod (every number in the list)
  Σ        Sum the modulos. This sum will be 0, if and only if this number is 0 or LCM.
  Y        Logical NOT, so that we only get a truthy if the sum of modulos is 0.
N        Grab the second number, our LCM. Implicit return.

2
ที่จริงแล้วฉันไม่รู้ว่าคุณทำสิ่งนี้ได้ในเวลาเพียง 19 ไบต์
บัฟเฟอร์อ่านมากกว่า

@TheBitByte ด้วยการใช้งานtotientและgcdbuiltins นี่จะสั้นลงถ้าจริง ๆ แล้วมีlcmโดยตรง แต่ฉันไม่คิดว่ามันจะมากและนั่นจะทำให้ได้แค่ 4 ไบต์เท่านั้น
Sherlock9

1
การยืนยันว่า lcm (* a) = product (* a) / gcd (* a) เป็นจริงเมื่อ * a เป็นรายการของตัวเลขสองตัว อย่างไรก็ตามเป็นเท็จโดยทั่วไปสำหรับรายการที่ยาวกว่า (ตัวอย่าง: ถ้า * a คือ {6,10,15} จะให้ 900 แทนคำตอบที่ถูกต้องที่ 60) [สำหรับเรื่องนั้นมันผิดคือ * a คือรายการของตัวเลขหนึ่งตัว!] และคุณสามารถตรวจสอบว่าคุณได้รับคำตอบที่ผิดสำหรับกรณีทดสอบมากกว่าครึ่งที่อยู่ใน OP
Greg Martin

@GregMartin ขอบคุณสำหรับหัวขึ้น คงที่
Sherlock9

4

JavaScript (ES6), 143 135 ไบต์

แก้ไข: บันทึกไว้ 8 ไบต์ด้วย Neil

การใช้งานโดยใช้การเขียนโปรแกรมฟังก์ชั่น

n=>(A=[...Array(n).keys()]).find(k=>k&&!c.some(c=>A.slice(0,k).reduce(y=>y*c%n,1)-1),c=A.filter(x=>(g=(x,y)=>x?g(y%x,x):y)(x,n)==1))||1

Ungolfed และแสดงความคิดเห็น

n =>                                          // Given a positive integer n:
  (A = [...Array(n).keys()])                  // Build A = [0 ... n-1].
  .find(k =>                                  // Try to find k in [1 ... n-1] such as
    k && !c.some(c =>                         // for each coprime c: c^k ≡ 1 (mod n).
      A.slice(0, k).reduce(y =>               // We use reduce() to compute
        y * c % n, 1                          // c^k mod n.
      ) - 1                                   // Compare it with 1.
    ),                                        // The list of coprimes is precomputed
    c = A.filter(x =>                         // before the find() loop is executed:
      (                                       // for each x in [0 ... n-1], keep
        g = (x, y) => x ? g(y % x, x) : y     // only integers that verify:
      )(x, n) == 1                            // gcd(x, n) = 1
    )                                         // (computed recursively)
  ) || 1                                      // Default result is 1 (for n = 1)

การสาธิต

แม้ว่ามันจะไม่ทำงาน6511และ10000ฉันจะไม่รวมไว้ที่นี่ก็มีแนวโน้มที่จะเป็นบิตช้า

let f =
n=>(A=[...Array(n).keys()]).find(k=>k&&!c.some(c=>A.slice(0,k).reduce(y=>y*c%n,1)-1),c=A.filter(x=>(g=(x,y)=>x?g(y%x,x):y)(x,n)==1))||1

console.log(f(1));     // 1
console.log(f(2));     // 1
console.log(f(3));     // 2
console.log(f(10));    // 4
console.log(f(35));    // 12
console.log(f(101));   // 100
console.log(f(530));   // 52
console.log(f(3010));  // 84


1
JS สามารถทำช่วงค่อนข้างง่าย:0..n-1 [...Array(n).keys()]สิ่งนี้ไม่จำเป็นต้องมีเพียงหนึ่งกรณีพิเศษ แต่ฉันยังรออยู่ข้างหน้า:n=>(a=[...Array(n).keys()]).find(k=>k&&!c.some(c=>a.slice(0,k).reduce(y=>y*c%n,1)-1),c=a.filter(x=>(g=(x,y)=>x?g(y%x,x):y)(x,n)==1))||1
Neil

2

ทับทิม101 86 91 90 ไบต์

พอร์ตทับทิมของคำตอบจริงของฉัน ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ

แก้ไข: -4 ไบต์จากลบaแต่ 9 ไบต์จากซ่อมข้อผิดพลาดที่ส่งกลับ1 nil-1 ไบต์ขอบคุณ Cyoce

require'prime'
->n{((n%8<1?n/2:n).prime_division<<[2,1]).map{|x,y|x**~-y*~-x}.reduce :lcm}

Ungolfing

require 'prime'
def carmichael(n)
  if n%8 < 1
    n /= 2
  end
  a = []
  n.prime_division.do each |x,y|
    a << x**(y-1)*(x-1)
  end
  return a.reduce :lcm
end

a=คุณไม่จำเป็นต้อง แต่น่าเสียดายที่คุณกลับnilสำหรับ n = 1 :(. (n.prime_division<<[2,1])การแก้ไขที่ไม่แน่ใจว่ามีวิธีที่ golfier..
M-Chrzan

(n%8<1?n/2:n).prime_division...บันทึกอีก 2 ไบต์
m-chrzan

@ m-chrzan aเป็นส่วนที่เหลือของความพยายามในการเล่นกอล์ฟก่อนหน้านี้ ขอขอบคุณสำหรับการแจ้งเตือนเกี่ยวกับและสำหรับหัวขึ้นบนa 1
Sherlock9

คุณสามารถบันทึกไบต์โดยใช้แทน.reduce :lcm .reduce(:lcm)
Cyoce

1

JavaScript (ES 2016) 149

การประยุกต์ใช้การอ้างอิง Python ถูกย้ายไปยัง JS Pyhton ในตัวแฟนซีบางตัวนั้นขาดหายไปใน js, like gcdand pow, และ array comprehension ไม่ได้มาตรฐานใน ES 6 สิ่งนี้ใช้ได้ใน Firefox

n=>eval('for(g=(a,b)=>b?g(b,a%b):a,p=(a,b,c)=>eval("for(r=1;b--;)r=r*a%c"),c=[for(_ of Array(i=n))if(g(i--,n)<2)i+1],k=1;c.some(x=>p(x,k,n)-1);)++k')

น้อย golfed

n=>{
  g=(a,b)=>b?g(b,a%b):a
  p=(a,b,c)=>{ 
    for(r=1;b--;)
      r=r*a%c
    return r
  }
  c=[for(_ of Array(i=n)) if(g(i--,n)<2) i+1]
  for(k=1;c.some(x=>p(x,k,n)-1);)
    ++k
  return k
} 

modpow แบบเรียกซ้ำนั้นสั้นกว่า:p=(a,b,c)=>b?a*p(a,b-1,c)%c:1;
Olivier Grégoire

1

ชวา 209 207 202 194 192 ไบต์

รหัส (96 ไบต์):

n->{for(int x,k=1,a;;k++){for(a=1,x=0;++x<=n&&a<2;)a=g(x,n)<2?p(x,k,n):1;if(a<2||n<2)return k;}}

ฟังก์ชั่นพิเศษ (96 ไบต์):

int g(int a,int b){return b<1?a:g(b,a%b);}int p(int n,int p,int m){return p<2?n:n*p(n,p-1,m)%m;}

การทดสอบและไม่อัปโหลด

import java.util.Arrays;
import java.util.function.IntUnaryOperator;

public class Main2 {

  static int g(int a,int b) { // recursive gcd
    return b < 1
        ? a
        : g(b,a%b);
  }

  static int p(int n, int p, int m) { // recursive modpow
    return p < 2
      ? n
      : n * p(n, p - 1, m) % m;
  }

  public static void main(String[] args) {

    IntUnaryOperator f = n -> {
      for(int x,k=1,a;;k++) { // for each k
        for(a=1,x=0;++x<=n&&a<2;) // for each x
          a=g(x,n)<2?p(x,k,n):1; // compute modpow(x,k,n) if g(x,n)
        if(a<2||n<2) // if all modpow(x,k,n)=1. Also check for weird result for n=1.
          return k;
      }
    };

    Arrays.stream(new int[]{1, 2, 3, 10, 35, 101, 530, 3010, 6511, 10000})
        .map(f)
        .forEach(System.out::println);
  }
}

หมายเหตุ

  • การใช้aเป็นintจะสั้นกว่าถ้าฉันต้องใช้ a booleanเพื่อทำการทดสอบ
  • ใช่มันสั้นกว่าของvalueOfใหม่ทั้งหมดBigIntegerกว่าสร้างฟังก์ชั่นแยกต่างหาก (มี 5 บวกONEค่าคงที่เป็น freebie)
  • อัลกอริทึมนั้นแตกต่างจากอัลกอริทึมของ @Master_ex ดังนั้นจึงไม่ใช่เพียง repost golfed นอกจากนี้อัลกอริทึมนี้มีประสิทธิภาพน้อยกว่ามากตามที่gcdคำนวณซ้ำแล้วซ้ำอีกสำหรับค่าเดียวกัน

โกน

  1. 209 -> 207 ไบต์:
    • if(...)a=...; -> a=...?...:1;
    • a==1 -> a<2
  2. 207 -> 202 ไบต์
    • ได้กำจัดBigIntegerโดยการเล่นกอล์ฟgcdและสำหรับmodPowint
  3. 202 -> 194 ไบต์
    • วนซ้ำmodPow-> เรียกซ้ำ
  4. 194 -> 192 ไบต์
    • ==1-> <2(ดูเหมือนจะใช้ได้กับทุกกรณีทดสอบไม่ทราบหมายเลขอื่น)

เฮ้! ฉันสังเกตเห็นว่าผลลัพธ์ไม่เป็นไปตามที่คาดไว้ ดูคำถามสำหรับผลลัพธ์ที่คาดหวัง โดยส่วนตัวแล้วฉันมักจะเขียนบททดสอบก่อนที่จะเริ่มเล่นกอล์ฟรหัสของฉันช่วยได้! ฉันเดาว่าปัญหาอาจเป็น modPow กับจำนวนเต็มฉันมีปัญหานี้ด้วยและนั่นคือสาเหตุที่ฉันใช้ BigInteger ในตอนท้าย
Master_ex

อืม ... ฉันประหลาดใจฉันให้การทดสอบของฉันทำงานทุกครั้งที่เปลี่ยนแปลง ฉันจะตรวจสอบสิ่งที่ผิด
Olivier Grégoire

1
@Master_ex ฉันแก้ไขมันแล้ว การย้อนกลับไปใช้เวอร์ชั่นก่อนหน้าก็โอเค
Olivier Grégoire

ฉันพบว่าวิธี modpow ซ้ำ ๆ ของคุณpค่อนข้างฉลาด ฉันพยายามที่จะใช้จำนวนเต็มเท่านั้นในตอนแรกเช่นกัน แต่เมื่อฉันได้พูดถึงคำตอบของฉันฉันมีปัญหาที่แม่นยำและนั่นเป็นสาเหตุที่ฉันย้ายไปที่BigInteger(เช่นMath.pow(3, 100)%101ส่งคืน60.0แทน1) การติดตั้งของคุณนั้นไม่คุ้มกับสิ่งนี้เพราะมันทำการปรับเปลี่ยนในแต่ละการวนซ้ำ อย่างไรก็ตามมันยังคงมีปัญหาจากบั๊ก สำหรับขนาดใหญ่m pอาจยังคงส่งคืนผลลัพธ์ที่ผิด นอกจากนี้เนื่องจากการเรียกซ้ำStackOverflowErrorอาจเกิดขึ้นได้ง่ายสำหรับอินพุตขนาดใหญ่ที่มีขนาดสแต็คเริ่มต้น
Master_ex

@Master_ex ใช่นั่นเป็นผลมาจากการ จำกัดintประเภท ฉันสามารถใช้ longs แทน ints ได้นั่นคือ 8 ไบต์พิเศษ แต่ในทัศนะของฉันทุกกรณีการทดสอบนั้นถูกต้อง StackOverflowErrorสามารถเกิดขึ้นได้ แต่นั่นเป็นวิธีการทำงานแบบวนซ้ำ วิธีการที่มีอยู่เพื่อ จำกัด ถึง 32 กอง แต่สิ่งเหล่านี้ใช้หลายไบต์มากขึ้น การใช้งานนี้มีความเปราะบางใช่คุณมีสิทธิ์ทั้งหมด แต่ก็แข็งแรงพอสำหรับกรณีทดสอบ
Olivier Grégoire

1

Java8 38 19 + 287 295 253 248 241 = 325 333 272 267 260 ไบต์

BigInteger B(int i){return new BigInteger(""+i);}int c(int...k){int n=k[0];for(k[0]=1;n>1&!java.util.stream.IntStream.range(0,n).filter(i->B(n).gcd(B(i)).equals(B(1))).allMatch(x->B(x).modPow(B(k[0]),B(n)).equals(B(1)));k[0]++);return k[0];}

นำเข้า 19 ไบต์

import java.math.*;

คำอธิบาย

มันคือการดำเนินการตรงไปตรงมา co-primes จะถูกคำนวณในSet pและ kth ของทุกคนใช้เพื่อตรวจสอบว่ามันเท่ากับ 1 โมดูโล n

ฉันต้องใช้BigIntegerเพราะปัญหาความแม่นยำ

การใช้

public static void main(String[] args) {
    Carmichael c = new Carmichael();
    System.out.println(c.c(3)); // prints 2
}

Ungolfed

// returns the BigInteger representation of the given interger
BigInteger B(int i) {
    return new BigInteger(""+i);
}
// for a given integer it returns the result of the carmichael function again as interger
// so the return value cannot be larger
int c(int... k) {
    int n = k[0];
    // iterate k[0] until for all co-primes this is true: (x^n) mod n == 1, if n==1 skip the loop
    for (k[0]=1;n > 1 && !java.util.stream.IntStream.range(0, n)
                .filter(i -> B(n).gcd(B(i)).equals(B(1)))
                .allMatch(x -> B((int) x).modPow(B(k[0]), B(n)).equals(B(1)));k[0]++);
    return k[0];
}

ข้อเสนอแนะใด ๆ ในการเล่นกอล์ฟมากขึ้นยินดีต้อนรับ :-)

ปรับปรุง

  • ไม่มีองค์ประกอบนอกฟังก์ชั่นที่รักษาสถานะ
  • ปฏิบัติตามคำแนะนำของ Olivier Grégoireและได้ช่วย 1 ไบต์จาก B()
  • ลบk()วิธีการและpการตั้งค่า (co-primes)
  • นำออกไม่จำเป็นต้องทำการร่ายเป็น int
  • เพิ่ม varags และใช้แทนในขณะที่

คุณมีเวอร์ชั่นที่ไม่ได้อัปโหลดได้หรือไม่ (พร้อมการกระจายความคิดเห็นที่นี่และที่นั่น ฯลฯ )
OldBunny2800

@ OldBunny2800: ใช่แน่นอน อย่างไรก็ตามฉันจะทำทีหลังวันนี้เพราะตอนนี้ฉันไม่ว่าง!
Master_ex

@ OldBunny2800: ฉันเพิ่มรุ่นที่ไม่อัปโหลด :-)
Master_ex

อืม ... ฉันไม่แน่ใจว่านี่จะนับว่าเป็นฟังก์ชั่นหรือโปรแกรม หากเป็นฟังก์ชั่นจะมีองค์ประกอบอยู่ด้านนอกซึ่งทำให้สถานะนั้นเป็นวิธีการโดยพฤตินัย (ฟังก์ชั่นเป็นอินพุทบริสุทธิ์ -> ไม่มีสถานะภายนอก) หากเป็นโปรแกรมวิธีหลักทั้งหมดจะหายไป หากการตีความของฉันไม่ถูกต้องโปรดบอกฉันอย่างนั้น! ฉันคิดว่าการรวมk(int)ไว้ในลูปจะดีกว่าเพราะเป็นหนึ่งซับและสามารถทำได้ นอกจากนี้ยังสามารถใส่ O คงที่ในcวิธีการเช่นกัน ฉันเดาว่าคุณจะชนะด้วยการทำเช่นนี้!
Olivier Grégoire

รูปธรรมwhile(n>1&&!p.stream().allMatch(x->B((int)x).modPow(B(k), B(n)).equals(O)))โกนไบต์และการแก้ไขปัญหาที่ผมกล่าวถึงถ้าคุณใส่ชุดและด้านหลังอย่างต่อเนื่องเข้าสู่วิธีการที่ นอกจากนี้คุณใช้Oสองครั้งแทนที่ด้วยB(1)เพื่อโกนหนวดไบต์
Olivier Grégoire



0

แร็กเก็ต 218 ไบต์

(λ(n)(let((fl #f)(cl(for/list((i n) #:when(coprime? n i))i)))(for/sum((k(range 1 n))#:break fl)(set! fl #t)
(for((i(length cl))#:break(not fl))(when(not(= 1(modulo(expt(list-ref cl i)k)n)))(set! fl #f)))(if fl k 0))))

เวอร์ชันที่ไม่ถูกปรับแต่ง:

(require math)
(define f
  (λ(n)
    (let ((fl #f)
          (cl (for/list ((i n) #:when (coprime? n i))
                i)))
             (for/sum ((k (range 1 n)) #:break fl)
               (set! fl #t)
               (for ((i (length cl)) #:break (not fl))
                 (when (not (= 1 (modulo (expt (list-ref cl i) k) n)))
                   (set! fl #f)))
               (if fl k 0)))))

การทดสอบ:

(f 2) 
(f 3)
(f 10)
(f 35)
(f 101)
(f 530)
(f 3010)
(f 6511)
(f 10000)

เอาท์พุท:

1
2
4
12
100
52
84
3056
500

0

C, 278 276 272 265 256 243 140 134 125 ไบต์

k,x,a,b,t,d;l(n){for(k=d=1;d;)for(d=x=0;++x<n;d=a<2&t>1?k++:d){for(a=x,b=n;t=b;a=t)b=a%b;for(t=1,b=k;b--;t=t*x%n);}return k;}

วิธีนี้ใช้อัลกอริธึมการยกกำลังแบบแยกส่วนช้าคำนวณ GCD บ่อยเกินไปและไม่มีหน่วยความจำรั่วอีกต่อไป!

Ungolfed:

int gcd( int a, int b ) {
  int t;
  while( b ) {
    t = b;
    b = a%b;
    a = t;
  }
  return a;
}
int pw(int a,int b,int c){
  int t=1;
  for( int e=0; e<b; e++ ) {
    t=(t*a)%c;
  }
  return t;
}
int carmichael(int n) {
  int k = 1;
  for( ;; ) {
    int done = 1;
    for( int x=1; x<n; x++ ) {
      if( gcd(x,n)==1 && pw(x,k,n) != 1 ) {
        done = 0;
        k++;
      }
    }
    if( done ) break;
  }
  return k;
}

ลองใช้กับ Ideone


0

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

c(n)==(r:=[x for x in 1..n|gcd(x,n)=1];(v,k):=(1,1);repeat(for a in r repeat(v:=powmod(a,k,n);v~=1=>break);v<=1=>break;k:=k+1);k)

golfed น้อย

cml(n)==
 r:=[x for x in 1..n|gcd(x,n)=1];(v,k):=(1,1)
 repeat 
   for a in r repeat(v:=powmod(a,k,n);v~=1=>break)
   v<=1=>break
   k:=k+1
 k

ผล

(3) -> [i,c(i)] for i in [1,2,3,10,35,101,530,3010,6511,10000]
   Compiling function c with type PositiveInteger -> PositiveInteger

   (3)
   [[1,1], [2,1], [3,2], [10,4], [35,12], [101,100], [530,52], [3010,84],
    [6511,3056], [10000,500]]
                                             Type: Tuple List PositiveInteger
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.