fibonacci_validation.pl 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/perl
  2. # Fibonacci tests
  3. use 5.010;
  4. use strict;
  5. use warnings;
  6. use lib qw(../lib);
  7. use Math::AnyNum qw(:overload);
  8. my $S = sqrt(1.25) + 0.5;
  9. my $T = sqrt(1.25) - 0.5;
  10. my $W = $S + $T; #=> sqrt(5);
  11. my @fib_pos_funcs = (
  12. \&fib_pos1, # requires complex numbers
  13. \&fib_pos2,
  14. \&fib_pos3, # requires complex numbers
  15. \&fib_pos4, # requires complex numbers
  16. \&fib_pos5
  17. );
  18. # Returns the nth Fibonacci number
  19. sub fib {
  20. my ($n) = @_;
  21. (($S**$n - (-$T)**$n) / $W)->round(0);
  22. }
  23. # Returns true if a given number if the nth-Fibonacci number
  24. sub is_fib {
  25. my ($i, $fib) = @_;
  26. ((($fib * $W) + (-$T)**$i)->log($S)->round(-$i / 4)) == $i;
  27. }
  28. # Returns true if a given number is probably a Fibonacci number
  29. sub is_prob_fib {
  30. my ($n) = @_;
  31. fib($fib_pos_funcs[rand @fib_pos_funcs]->($n)) == $n;
  32. }
  33. #
  34. ## 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))
  35. #
  36. sub fib_pos1 {
  37. my ($n) = @_;
  38. ($W * $n + $T->neg->pow(log(5 * $n**2) / ($W + 1)))->log($S)->round;
  39. }
  40. #
  41. ## (log((2/(sqrt(5)-1))^(log((1+sqrt(5))/(5 * n^2)))+sqrt(5)*n))/(log(1/2 (1+sqrt(5))))
  42. #
  43. sub fib_pos2 {
  44. my ($n) = @_;
  45. ($W * $n + (2 / ($W - 1))->pow(log((1 + $W) / (5 * $n**2))))->log((1 + $W) / 2)->round;
  46. }
  47. #
  48. ## (log(n*sqrt(5) + (((1-sqrt(5))/2) ^ (log(n * sqrt(5)) / log((1+sqrt(5))/2))))) / log((1+sqrt(5))/2)
  49. #
  50. sub fib_pos3 {
  51. my ($n) = @_;
  52. (($n * $W) + (-$T)**((($n * $W))->log($S)))->log($S)->round;
  53. }
  54. #
  55. ## log((W*n + ((-T)**((log(n) + log(5)/2) / S)))) / log(S)
  56. #
  57. sub fib_pos4 {
  58. my ($n) = @_;
  59. (
  60. log(($S + $T) * $n + ((0.5 * (1 - ($S + $T)))**((log($n) + (log(5) / 2)) / (log(1 + ($S + $T)) - log(2))))) /
  61. (log(1 + ($S + $T)) - log(2)))->round;
  62. }
  63. #
  64. ## log(n*sqrt(5)) / log(PHI)
  65. #
  66. sub fib_pos5 {
  67. my ($n) = @_;
  68. ($n * sqrt(5))->log($S)->round(0);
  69. }
  70. foreach my $group (
  71. [12, 144, 1],
  72. [12, 143, 0],
  73. [12, 145, 0],
  74. [13, 233, 1],
  75. [49, 1337, 0],
  76. [32, 2178309, 1],
  77. [100, 354224848179261915074, 0],
  78. [100, 354224848179261915076, 0],
  79. [100, 354224848179261915075, 1],
  80. ) {
  81. my ($pos, $num, $bool) = @{$group};
  82. is_fib($pos, $num) == $bool or say "Validation error (1)!";
  83. is_prob_fib($num) == $bool or say "Validation error (2)!";
  84. $fib_pos_funcs[rand @fib_pos_funcs]->($num) == $fib_pos_funcs[rand @fib_pos_funcs]->($num)
  85. or say "Error in rand pos 1";
  86. if ($bool) {
  87. $fib_pos_funcs[rand @fib_pos_funcs]->($num) == $pos
  88. or say "Error in rand pos 2";
  89. }
  90. printf("%21s is on position %3s in the fibonacci sequence: %s\n", $num, $pos, $bool);
  91. }