Fibonacci matrix-exponentiation: Difference between revisions
Content added Content deleted
m (→{{header|Phix}}: added syntax colouring the hard way) |
(Added Wren) |
||
Line 1,499: | Line 1,499: | ||
F(2^32) = 61999319689381859818 ... 39623735538208076347 |
F(2^32) = 61999319689381859818 ... 39623735538208076347 |
||
F(2^64) = 11175807536929528424 ... 17529800348089840187 |
F(2^64) = 11175807536929528424 ... 17529800348089840187 |
||
</pre> |
|||
=={{header|Wren}}== |
|||
===Matrix exponentation=== |
|||
{{trans|Go}} |
|||
{{libheader|Wren-big}} |
|||
{{libheader|Wren-fmt}} |
|||
A tough task for Wren which takes just under 3 minutes to process even the 1 millionth Fibonacci number. Judging by the times for the compiled, statically typed languages using GMP, the 10 millionth would likely take north of 4 hours so I haven't attempted it. |
|||
<lang ecmascript>import "/big" for BigInt |
|||
import "/fmt" for Fmt |
|||
var mul = Fn.new { |m1, m2| |
|||
var rows1 = m1.count |
|||
var cols1 = m1[0].count |
|||
var rows2 = m2.count |
|||
var cols2 = m2[0].count |
|||
if (cols1 != rows2) Fiber.abort("Matrices cannot be multiplied.") |
|||
var result = List.filled(rows1, null) |
|||
for (i in 0...rows1) { |
|||
result[i] = List.filled(cols2, null) |
|||
for (j in 0...cols2) { |
|||
result[i][j] = BigInt.zero |
|||
for (k in 0...rows2) { |
|||
var temp = m1[i][k] * m2[k][j] |
|||
result[i][j] = result[i][j] + temp |
|||
} |
|||
} |
|||
} |
|||
return result |
|||
} |
|||
var identityMatrix = Fn.new { |n| |
|||
if (n < 1) Fiber.abort("Size of identity matrix can't be less than 1") |
|||
var ident = List.filled(n, 0) |
|||
for (i in 0...n) { |
|||
ident[i] = List.filled(n, null) |
|||
for(j in 0...n) ident[i][j] = (i != j) ? BigInt.zero : BigInt.one |
|||
} |
|||
return ident |
|||
} |
|||
var pow = Fn.new { |m, n| |
|||
var le = m.count |
|||
if (le != m[0].count) Fiber.abort("Not a square matrix") |
|||
if (n < 0) Fiber.abort("Negative exponents not supported") |
|||
if (n == 0) return identityMatrix.call(le) |
|||
if (n == 1) return m |
|||
var pow = identityMatrix.call(le) |
|||
var base = m |
|||
var e = n |
|||
while (e > 0) { |
|||
var temp = e & BigInt.one |
|||
if (temp == BigInt.one) pow = mul.call(pow, base) |
|||
e = e >> 1 |
|||
base = mul.call(base, base) |
|||
} |
|||
return pow |
|||
} |
|||
var fibonacci = Fn.new { |n| |
|||
if (n == 0) return BigInt.zero |
|||
var m = [[BigInt.one, BigInt.one], [BigInt.one, BigInt.zero]] |
|||
m = pow.call(m, n - 1) |
|||
return m[0][0] |
|||
} |
|||
var n = BigInt.zero |
|||
var i = 10 |
|||
while (i <= 1e6) { |
|||
n = BigInt.new(i) |
|||
var s = fibonacci.call(n).toString |
|||
Fmt.print("The digits of the $,sth Fibonacci number ($,s) are:", i, s.count) |
|||
if (s.count > 20) { |
|||
Fmt.print(" First 20 : $s", s[0...20]) |
|||
if (s.count < 40) { |
|||
Fmt.print(" Final $-2d : $s", s.count-20, s[20..-1]) |
|||
} else { |
|||
Fmt.print(" Final 20 : $s", s[s.count-20..-1]) |
|||
} |
|||
} else { |
|||
Fmt.print(" All $-2d : $s", s.count, s) |
|||
} |
|||
System.print() |
|||
i = i * 10 |
|||
} |
|||
n = BigInt.one << 16 |
|||
var s = fibonacci.call(n).toString |
|||
Fmt.print("The digits of the 2^16th Fibonacci number ($,s) are:", s.count) |
|||
Fmt.print(" First 20 : $s", s[0...20]) |
|||
Fmt.print(" Final 20 : $s", s[s.count-20..-1])</lang> |
|||
{{out}} |
|||
<pre> |
|||
The digits of the 10th Fibonacci number (2) are: |
|||
All 2 : 55 |
|||
The digits of the 100th Fibonacci number (21) are: |
|||
First 20 : 35422484817926191507 |
|||
Final 1 : 5 |
|||
The digits of the 1,000th Fibonacci number (209) are: |
|||
First 20 : 43466557686937456435 |
|||
Final 20 : 76137795166849228875 |
|||
The digits of the 10,000th Fibonacci number (2,090) are: |
|||
First 20 : 33644764876431783266 |
|||
Final 20 : 66073310059947366875 |
|||
The digits of the 100,000th Fibonacci number (20,899) are: |
|||
First 20 : 25974069347221724166 |
|||
Final 20 : 49895374653428746875 |
|||
The digits of the 1,000,000th Fibonacci number (208,988) are: |
|||
First 20 : 19532821287077577316 |
|||
Final 20 : 68996526838242546875 |
|||
The digits of the 2^16th Fibonacci number (13,696) are: |
|||
First 20 : 73199214460290552832 |
|||
Final 20 : 97270190955307463227 |
|||
</pre> |
|||
<br> |
|||
===Lucas method=== |
|||
{{trans|Go}} |
|||
Much quicker than the matrix exponentiation method taking about 23 seconds to process the 1 millionth Fibonacci number and around 32 minutes to reach the 10 millionth. |
|||
Apart from the 2^16th number, the extra credit is still out of reach using this approach and unfortunately the Fibmod method is not available as Wren doesn't currently have a suitable library for arbitrary precision floating point calculations. |
|||
<lang ecmascript>import "/big" for BigInt |
|||
import "/fmt" for Fmt |
|||
var lucas = Fn.new { |n| |
|||
var inner // recursive function |
|||
inner = Fn.new { |n| |
|||
if (n == BigInt.zero) return [BigInt.zero, BigInt.one] |
|||
var t = n >> 1 |
|||
var res = inner.call(t) |
|||
var u = res[0] |
|||
var v = res[1] |
|||
t = n & BigInt.two |
|||
var q = t - BigInt.one |
|||
var r = BigInt.zero |
|||
u = u.square |
|||
v = v.square |
|||
t = n & BigInt.one |
|||
if (t == BigInt.one) { |
|||
t = u - q |
|||
t = BigInt.two * t |
|||
r = BigInt.three * v |
|||
return [u + v, r - t] |
|||
} else { |
|||
t = BigInt.three * u |
|||
r = v + q |
|||
r = BigInt.two * r |
|||
return [r - t, u + v] |
|||
} |
|||
} |
|||
var t = n >> 1 |
|||
var res = inner.call(t) |
|||
var u = res[0] |
|||
var v = res[1] |
|||
var l = BigInt.two * v |
|||
l = l - u // Lucas function |
|||
t = n & BigInt.one |
|||
if (t == BigInt.one) { |
|||
var q = n & BigInt.two |
|||
q = q - BigInt.one |
|||
t = v * l |
|||
return t + q |
|||
} |
|||
return u * l |
|||
} |
|||
var n = BigInt.zero |
|||
var i = 10 |
|||
while (i <= 1e7) { |
|||
n = BigInt.new(i) |
|||
var s = lucas.call(n).toString |
|||
Fmt.print("The digits of the $,sth Fibonacci number ($,s) are:", i, s.count) |
|||
if (s.count > 20) { |
|||
Fmt.print(" First 20 : $s", s[0...20]) |
|||
if (s.count < 40) { |
|||
Fmt.print(" Final $-2d : $s", s.count-20, s[20..-1]) |
|||
} else { |
|||
Fmt.print(" Final 20 : $s", s[s.count-20..-1]) |
|||
} |
|||
} else { |
|||
Fmt.print(" All $-2d : $s", s.count, s) |
|||
} |
|||
System.print() |
|||
i = i * 10 |
|||
} |
|||
n = BigInt.one << 16 |
|||
var s = lucas.call(n).toString |
|||
Fmt.print("The digits of the 2^16th Fibonacci number ($,s) are:", s.count) |
|||
Fmt.print(" First 20 : $s", s[0...20]) |
|||
Fmt.print(" Final 20 : $s", s[s.count-20..-1])</lang> |
|||
{{out}} |
|||
As matrix exponentiation method, plus: |
|||
<pre> |
|||
The digits of the 10,000,000th Fibonacci number (2,089,877) are: |
|||
First 20 : 11298343782253997603 |
|||
Final 20 : 86998673686380546875 |
|||
</pre> |
</pre> |