k.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. package kata
  2. import (
  3. "math"
  4. )
  5. var sqrt5 = math.Sqrt(5)
  6. var Phi1 = (1.0 + sqrt5) / 2
  7. var Phi2 = (1.0 - sqrt5) / 2
  8. /*
  9. Binet returns the n-th element of the Fibonacci suite using Binet's formula.
  10. */
  11. func Binet(n uint64) uint64 {
  12. fn := float64(n)
  13. fl := (math.Pow(Phi1, fn) - math.Pow(Phi2, fn)) / sqrt5
  14. res := uint64(math.Round(fl))
  15. return res
  16. }
  17. /*
  18. Prod return Fibonacci(n)*Fibonacci(n+1).
  19. */
  20. func Prod(n uint64) uint64 {
  21. return Binet(n) * Binet(n+1)
  22. }
  23. /*
  24. Near returns an integer n such as Fib(n)*Fib(n+1) be close to be the argument received.
  25. The approximation used is based on Binet's formula for Fibonacci.
  26. */
  27. func Near(prod uint64) (n uint64, ok bool) {
  28. // fn is within 1 of the actual value if it exists.
  29. fn := math.Log(math.Sqrt(5*float64(prod)/Phi1)) / math.Log(Phi1)
  30. b, c := uint64(math.Floor(fn)), uint64(math.Ceil(fn))
  31. a, d := b-1, c+1
  32. for _, x := range [...]uint64{a, b, c, d} {
  33. if Prod(x) == prod {
  34. return x, true
  35. }
  36. }
  37. for _, x := range [...]uint64{a, b, c, d} {
  38. if Prod(x) > prod {
  39. return x, false
  40. }
  41. }
  42. return d+1, false
  43. }
  44. func ProductFib(prod uint64) [3]uint64 {
  45. // n is within 1 of the actual potential solution.
  46. n, ok := Near(prod)
  47. return [3]uint64{Binet(n), Binet(n + 1), map[bool]uint64{false: 0, true: 1}[ok]}
  48. }