如何确定数字是否是Fibonacci序列的一部分?

时间:2013-05-14 17:23:47

标签: ruby

我有一个编写一个方法的赋值,该方法确定一个数字是否是Fibonacci序列的一部分。

同时使用公式:

  

正整数z是斐波那契数,当且仅当5z ^ 2 + 4或5z ^ 2 - 4中的一个是完美的正方形时

我定义了以下适用于小数和大Fibonacci数的方法,但是,无论出于何种原因,我的赋值规范在处理大的非Fibonacci数时会抛出错误,特别是在运行is_fibonacci?(927372692193078999171)时。显然,该方法返回true而不是false。其他一切似乎都是正确的,所以我有点拉扯我的头发为什么这不起作用。有什么建议?

def is_fibonacci?(i)
  bigNumber1 = Math.sqrt((5*(i**2)+4))
  bigNumber2 = Math.sqrt((5*(i**2)-4))
  if bigNumber1 == bigNumber1.round || bigNumber2 == bigNumber2.round
    return true
  else 
    return false
  end
end

4 个答案:

答案 0 :(得分:8)

如其他地方所述,问题在于Floats的精确度。 BigDecimal提供任意精度算术:

require 'bigdecimal'

def is_fibonacci?(i)
  i = BigDecimal.new(i)
  bigNumber1 = (5*(i**2)+4).sqrt(0)
  bigNumber2 = (5*(i**2)-4).sqrt(0)
  return (bigNumber1 == bigNumber1.round || bigNumber2 == bigNumber2.round)
end

is_fibonacci? 927372692193078999171 # => false
is_fibonacci? 927372692193078999176 # => true

答案 1 :(得分:3)

问题是Math.sqrt返回一个浮点值,通常只是对实平方根的估计。对于大数字,您只需获得类似1234567600000.0的内容,您的代码将始终将其视为整数。

实现自己的任意精度,整数平方根函数。一个天真的方法可能是这样的:

def is_fibonacci?(i)
  n1 = 5 * i**2 + 4
  n2 = n1 - 8
  is_square?(n1) or is_square?(n2)
end

# find floor(sqrt(i)) by nesting intervals
def sqrt(i)
  a, b = 0, i
  while a + 1 < b
    m = (a + b) / 2
    if m**2 > i
      b = m
    else
      a = m
    end
  end
  a
end

def is_square?(i)
  s = sqrt(i)
  s ** 2 == i
end

答案 2 :(得分:0)

比奈的公式需要计算平方根。这是我的解决方案,使用内置的Bignum和Newton的方法来检查平方根。

def isSQRT(x)
  return true if [0,1,4,9,16,25,36,49,64,81,100].include?x
  z = x / 10  #first guess
  z=z-(z*z-x)/(2*z) while (z-1)**2 > x
  return true if (z-1)**2 == x
  false
end

def is_fibonacci?(num)
  isSQRT(5*num**2+4) || isSQRT(5*num**2-4)
end

此外,有一种方法可以在不使用Binet的情况下弄清楚,如Kenneth's memoization method by Hash所示。所以你可以通过内置的has_value方法检查一个数字?(数字)。

fibo = Hash.new{ |h,k| h[k] = ( k<=2 ? 1 : h[k-2] + h[k-1] ) }
fibo[500] #=> instant result of Fibonacci! 

答案 3 :(得分:0)

这是一种仅适用于 Ruby 的核心 API 方法的方法。它返回一个布尔值

def fibonacci?(number_sought)
  num = 2
  result = [1, 1]  until num >= number_sought
    result << result[-1] + result[-2]
    if result.include?(number_sought) then break 
    elsif result[-1] > number_sought then return false
    else next
    end
    num += 1
  end
  !!result
end

p fibonacci?(10946)
p fibonacci?(927372692193078999176)

如果你想返回数组:

def fibonacci(number_sought)
  num = 2
  result = [1, 1]  until num >= number_sought
    result << result[-1] + result[-2]
    if result.include?(number_sought) then break 
    elsif result[-1] > number_sought then return result
    else next
    end
    num += 1
  end
  result
end