#!/usr/bin/ruby
var S = sqrt(1.25)+0.5;
var T = sqrt(1.25)-0.5;
var W = S+T; #=> sqrt(5);
func fib(n) {
pow(S, n) - pow(-T, n) / W -> round;
}
func is_fib (i, fib) {
(((fib * W) + pow(-T, i)).log(S) -> roundf(-i)) == i;
}
#
## log(n*sqrt(5) + (((1-sqrt(5))/2) ^ ((log(n)+(log(5))/2) / (log(1+sqrt(5))-log(2))))) / (log(1+sqrt(5))-log(2))
#
func fib_pos1(n) {
W*n + pow(-T, log(5 * n**2) / (W+1)) -> log(S).round
}
#
## (log((2/(sqrt(5)-1))^(log((1+sqrt(5))/(5 * n^2)))+sqrt(5)*n))/(log(1/2 (1+sqrt(5))))
#
func fib_pos2(n) {
W*n + pow(2 / (W-1), log((1+W) / (5 * n**2))) -> log((1+W) / 2) -> round
}
#
## (log(n*sqrt(5) + (((1-sqrt(5))/2) ^ (log(n * sqrt(5)) / log((1+sqrt(5))/2))))) / log((1+sqrt(5))/2)
#
func fib_pos3(n) {
((n * W) + pow(-T, (((n * W)).log(S)))).log(S).round;
}
#
## log((W*n + ((-T)**((log(n) + log(5)/2) / S)))) / log(S)
#
func fib_pos4(n) {
(log((S+T)*n + ((0.5 * (1-(S+T)))**((log(n) + (log(5)/2)) / (log(1+(S+T))-log(2)))))) /
(log(1+(S+T))-log(2)) -> round;
}
#
## log(n*sqrt(5)) / log(PHI)
#
func fib_pos5(n) {
n * sqrt(5) -> log(S).round
}
var fib_pos_funcs = [fib_pos1, fib_pos2, fib_pos3, fib_pos4, fib_pos5];
func is_prob_fib(n) {
fib(fib_pos_funcs.rand()(n)) == n;
}
[
[12, 144, true],
[12, 143, false],
[12, 145, false],
[13, 233, true],
[49, 1337, false],
[32, 2178309, true],
[100, 354224848179261915074, false],
[100, 354224848179261915076, false],
[100, 354224848179261915075, true],
].each { |group|
var(pos, num, bool) = group...;
is_fib(pos, num) == bool || die "Validation error (1)!";
is_prob_fib(num) == bool || die "Validation error (2)!";
assert_eq(fib_pos_funcs.rand()(num), fib_pos_funcs.rand()(num))
assert_eq(fib_pos_funcs.rand()(num), pos) if bool
"%21s is on position %3s in the fibonacci sequence: %s\n" \
-> printf(num, pos, bool);
}