#!/usr/bin/ruby # Tests for Lucas sequences U_n(P, Q) and V_n(P, Q). func is(Number a, b) { if (a.is_nan) { return __FUNC__(a.to_s, b.to_s) } assert_eq(a, b) } func is(a, b){ assert_eq(a, b) } is(lucas(-1), NaN) is(lucas(0), 2) is(lucas(1), 1) is(lucas(15), 1364) is(lucas(15), 1364) is(lucas(-4), NaN) is(lucasU(4, 4, 13), 53248) is(lucasV(4, 4, 13), 16384) is(lucasV(-4, 4, 24), 33554432) is(lucasV(4, -4, 24), 25783171895263232) is(lucasV(4, -4, 25), 124492166541082624) is(lucasV(-4, 4, 25), -67108864) is(lucasV(-4, 4, 26), 134217728) is(lucasV(-4, -4, 16), 87275208704) is(lucasV(-4, -4, 48), 664771952980691802270648617664512) is(lucasU(4, -4, 24), 4557863921909760) is(lucasU(-4, 4, 24), -201326592) is(lucasU(4, -4, 25), 22007313791451136) is(lucasU(-4, 4, 25), 419430400) is(lucasU(-4, 4, 26), -872415232) is(lucasU(-4, -4, 16), -15428222976) is(lucasU(-4, -4, 48), -117516188973817974394087349944320) is(lucasUmod(-4, -4, 48, 700237709), 424976705) is(lucasUmod(4, -4, 4171, 619442071), 93411036) is(lucasUmod(4, -4, 54223, 1238884142), 793124222) is(lucasUmod(5, 3, 1234, 789347), 134939) is(lucasUmod(5, 3, 1234, -789347), 134939) # maybe this should be: 134939 - 789347 = -654408 is({ lucasUmod(3, -2, _, 24) }.map(0 .. 9), %n[0, 1, 3, 11, 15, 19, 15, 11, 15, 19]) is({ lucasVmod(3, -2, _, 24) }.map(0 .. 9), %n[2, 3, 13, 21, 17, 21, 1, 21, 17, 21]) is({ [lucasUVmod(3, -2, _, 24)] }.map(0 .. 9), %n[0, 1, 3, 11, 15, 19, 15, 11, 15, 19] ~Z %n[2, 3, 13, 21, 17, 21, 1, 21, 17, 21]) is({ lucasUmod(4, 4, _, 25) }.map(0 .. 9), %n[0, 1, 4, 12, 7, 5, 17, 23, 24, 4]) is({ lucasVmod(4, 4, _, 25) }.map(0 .. 9), %n[2, 4, 8, 16, 7, 14, 3, 6, 12, 24]) is({ [lucasUVmod(4, 4, _, 25)] }.map(0 .. 9), %n[0, 1, 4, 12, 7, 5, 17, 23, 24, 4] ~Z %n[2, 4, 8, 16, 7, 14, 3, 6, 12, 24]) is({ lucasUmod(-5, -3, _, 48) }.map(0 .. 9), %n[0, 1, 43, 28, 37, 43, 40, 25, 43, 4]) is({ lucasVmod(-5, -3, _, 48) }.map(0 .. 9), %n[2, 43, 31, 22, 31, 7, 10, 19, 31, 46]) is({ [lucasUVmod(-5, -3, _, 48)] }.map(0 .. 9), %n[0, 1, 43, 28, 37, 43, 40, 25, 43, 4] ~Z %n[2, 43, 31, 22, 31, 7, 10, 19, 31, 46]) is({ lucasUmod( 5, 3, _, 789347) }.map(0 .. 14), %n[0, 1, 5, 22, 95, 409, 1760, 7573, 32585, 140206, 603275, 227716, 118102, 696709, 761198]) is({ lucasUmod(-5, 3, _, 789347) }.map(0 .. 14), %n[0, 1, 789342, 22, 789252, 409, 787587, 7573, 756762, 140206, 186072, 227716, 671245, 696709, 28149]) is({ lucasUmod( 5, 3, _, 789347) }.map(0 .. 14), { lucasU( 5, 3, _) % 789347 }.map(0 .. 14)) is({ lucasUmod(-5, 3, _, 789347) }.map(0 .. 14), { lucasU(-5, 3, _) % 789347 }.map(0 .. 14)) is({ lucasVmod( 5, 3, _, 789347) }.map(0 .. 14), { lucasV( 5, 3, _) % 789347 }.map(0 .. 14)) is({ lucasVmod(-5, 3, _, 789347) }.map(0 .. 14), { lucasV(-5, 3, _) % 789347 }.map(0 .. 14)) is(fibmod(0, 100), 0) is(fibmod(1, 100), 1) is(lucasmod(0, 100), 2) is(lucasmod(1, 100), 1) is(lucasUmod(1, -1, 0, 100), 0) is(lucasUmod(1, -1, 1, 100), 1) is(lucasVmod(1, -1, 0, 100), 2) is(lucasVmod(1, -1, 1, 100), 1) is(lucasUmod(4, 4, 0, 100), 0) is(lucasUmod(4, 4, 1, 100), 1) is(lucasUmod(4, 4, 50, 1000), lucasU(4, 4, 50) % 1000) is(lucasUmod(4, -4, 50, 1000), lucasU(4, -4, 50) % 1000) is(lucasVmod(4, 4, 0, 100), 2) is(lucasVmod(4, 4, 1, 100), 4) is(lucasVmod(4, 4, 0, 100), lucasV(4, 4, 0) % 100) is(lucasVmod(4, 4, 1, 100), lucasV(4, 4, 1) % 100) is(lucasVmod( 4, 4, 50, 1000), 248) is(lucasVmod(-4, 4, 50, 1000), 248) is(lucasVmod( 4, 4, 50, 1000), lucasV(4, 4, 50) % 1000) is(lucasVmod(-4, 4, 50, 1000), lucasV(4, 4, 50) % 1000) is(lucasVmod( 4, 4, 50, 1001), lucasV( 4, 4, 50) % 1001) is(lucasVmod(-4, 4, 50, 1001), lucasV(-4, 4, 50) % 1001) is(lucasUmod( 4, 4, 50, 1001), lucasU( 4, 4, 50) % 1001) is(lucasUmod(-4, 4, 50, 1001), lucasU(-4, 4, 50) % 1001) is(lucasVmod( 4, -4, 50, 1000), 624) is(lucasVmod(-4, -4, 50, 1000), 624) is(lucasVmod( 4, -4, 50, 1000), lucasV( 4, -4, 50) % 1000) is(lucasVmod(-4, -4, 50, 1000), lucasV(-4, -4, 50) % 1000) is(lucasVmod(3, -4, 50, 1000), lucasV(3, -4, 50) % 1000) is(lucasUmod(3, -4, 50, 1000), lucasU(3, -4, 50) % 1000) is(fibmod(1234, 987654), fibonacci(1234) % 987654) is(lucasmod(1234, 987654), lucas(1234) % 987654) is(lucasUmod(1, -1, -43, 42), NaN) is(lucasUmod(1, -1, -2, 43), NaN) is(lucasVmod(1, -1, -43, 42), NaN) is(lucasVmod(1, -1, -2, 43), NaN) is([lucasUVmod(1, -1, -41, 97)].join(' '), [NaN, NaN].join(' ')) is([lucasUVmod(1, -1, -12, 42)].join(' '), [NaN, NaN].join(' ')) is(fibmod(-1, 1234), NaN) is(lucasmod(-1, 1234), NaN) is(fibmod(42, 0), NaN) is(lucasmod(42, 0), NaN) is(lucasUmod(2**95 + 1, 2**75 - 1, 1234, 98765), 35621) is(lucasVmod(2**95 + 1, 2**75 - 1, 1234, 98765), 3022) is(lucasUmod(2**95 + 1, 2**75 - 1, 98765, 1234), 477) is(lucasVmod(2**95 + 1, 2**75 - 1, 98765, 1234), 29) is([lucasUVmod(2**95 + 1, 2**75 - 1, 1234, 98765)], [35621, 3022]) is([lucasUVmod(2**95 + 1, 2**75 - 1, 98765, 1234)], [477, 29]) func pisano_period_pp(P, Q, p, k=1) { (p - kronecker(P*P - 4*Q, p)).divisors.first_by {|d| lucasUmod(P, Q, d, p) == 0 } * p**(k-1) } func pisano_period(n, P=1, Q=-1) { return 0 if (n <= 0) return 1 if (n == 1) var d = n.factor_map {|p,k| pisano_period_pp(P, Q, p, k) }.lcm 3.times {|k| var t = d<<k if ((lucasUmod(P, Q, t, n) == 0) && (lucasUmod(P, Q, t+1, n) == 1)) { return t } } die "Error for n = #{n} with P = #{P} and Q = #{Q}" } {|n| pisano_period(n, 1, -1) }.map(1..30) # Periods of Fibonacci numbers {|n| pisano_period(n, 2, -1) }.map(1..30) # Periods of Pell numbers {|n| pisano_period(n, 3, -1) }.map(1..30) # Periods of 3-Fibonacci numbers for k in (0..10) { var m = 43*97 assert_eq(20.of { .fibmod(k, m) }, 20.of { .fib(k) % m }) } assert_eq(fibmod(43, 3, 2**128 + 1), fib(43, 3) % (2**128 + 1)) assert_eq(fibmod(2**128 + 1, 3, 2**128 - 1), 220193395512101899249036009241856381864) assert_eq(fibmod(2**128 + 1, 3, 2**127 - 1), 21277636584740672870826766395962370082) assert_eq(fibmod(2**127 - 1, 3, 2**128 + 1), 85447148131207702798335464791538973804) assert_eq(fibmod(2**127 - 1, 4, 2**128 + 1), 279405613631561682761560761315872506950) assert_eq(fibmod(2**128 + 1, 2, 2**128 - 1), fibmod(2**128 + 1, 2**128 - 1)) assert(%n[913, 150267335403, 430558874533, 14760229232131, 936916995253453].all { .is_bfw_psp }) assert(%n[7056721, 79397009999, 443372888629441, 582920080863121, 2491924062668039, 14522256850701599, 39671149333495681, 242208715337316001, 729921147126771599, 842526563598720001, 1881405190466524799, 2380296518909971201, 3188618003602886401, 33711266676317630401, 54764632857801026161, 55470688965343048319, 72631455338727028799, 122762671289519184001, 361266866679292635601, 734097107648270852639].all{.is_chebyshev_psp}) assert(is_strong_fibonacci_pseudoprime(443372888629441)) assert(is_strong_fibonacci_pseudoprime(39671149333495681)) say "** Test passed!"