1

for some reason I have to determine if a big number is a fibonacci number, so I copy some code from internet and modified it a little, it seems not operate well when it's big input. here is code:

# python program to check if x is a perfect square

import math

# A utility function that returns true if x is perfect square
def isPerfectSquare(x):
    s = int(math.sqrt(x))
    boo = (s*s == x);
    return boo

# Returns true if n is a Fibinacci Number, else false
def isFibonacci(n):

    # n is Fibinacci if one of 5*n*n + 4 or 5*n*n - 4 or both
    # is a perferct square
    b = 5*n*n+4;
    c = 5*n*n-4;
    return isPerfectSquare(b) or isPerfectSquare(c)

# A utility function to test above functions

a = int(input("give me the number"));
print(isFibonacci(a))

when I input 610, it output true as planed, but when I input

"215414832505658809004682396169711233230800418578767753330908886771798637" 

which I know is the 343rd fibonacci number from another java program I made. it output false surprisingly. So is it because the number is too large so it makes mistakes? but I think python should be able to handle enormous big number because it is based on the memory you have? is the problem in my program or is it because it's too big input? Thx!

furas
  • 95,376
  • 7
  • 74
  • 111
Tony Chen
  • 185
  • 1
  • 15
  • 1
    use `print()` to see what you have in variables and which part of code is execeuted - it helps to find problem . Or learn how to use debugger ;) – furas Dec 31 '16 at 08:23
  • @furas oh yeah I don't know how to debug in python... I'll figure it out tnt :P – Tony Chen Dec 31 '16 at 08:26
  • Have a look at this: https://docs.python.org/3/library/pdb.html – shuttle87 Dec 31 '16 at 08:27
  • 1
    Use the Newton's method of calculating `sqrt()` for large numbers like in this post: http://stackoverflow.com/a/15391420/3160529 – Shubham Dec 31 '16 at 10:26

4 Answers4

5

You have a loss of precision. For n > 1e45 (approximately), (n**0.5)**2 != n. Try using gmpy2.isqrt() and gmpy2.square() from module gmpy2 - they are designed to work with very large integer numbers.

DYZ
  • 45,526
  • 9
  • 47
  • 76
1

I checked it with Fibonacci numbers produced from mupad in Matlab(use numlib::fibonacci(n)) . It's because of precision. Python can't detect more than 52 precision, so for numbers larger than 2^52, precision will be lost. You can checked it with 76th fibonacci number and 77th fibonacci number to see the probelm. 76th fibonacci number: 3416454622906707 77th fibonacci number: 5527939700884757

1

As already pointed out, the problem arise solely from math.sqrt, which is a floating point operation, meaning not exactly precise (unlike integer operations). The precision of floats in python is about 16, meaning that precision float operations on a number with more than 16 digits always goes bad.

Instead of using floats (math.sqrt converts your integer to float implicitly), you can use the Decimal type from the decimal module, included in the standard library. This is a floating point type with variable, controllable precision. To fix your program, simply replace your isPerfectSquare function with this:

import decimal
def isPerfectSquare(x):
    # Set decimal precision and convert x to Decimal type
    decimal.getcontext().prec = len(str(x))
    x = decimal.Decimal(x)
    # Check if perfect square
    s = int(x.sqrt())
    boo = (s*s == x);
    return boo

Here the precision is set equal to the number of digits of the input number, which is given by the length of the str representation of the input number.

jmd_dk
  • 8,399
  • 4
  • 48
  • 72
0

It is related to the fact that python loose precision after 52 digits (in total before and after the dot). You have to use gmpy2.square() imported from module gmpy2 this is the only way you can handle big numbers.

scugn1zz0
  • 151
  • 1
  • 1
  • 11
  • Certainly not *the only* way. For starters, what about the decimal module, included in the standard library? – jmd_dk Dec 31 '16 at 09:35