简体   繁体   中英

why is my function not always returning the correct list?

I have a function that takes two inputs, and will return an array of tuples where the two numbers in a given tuple have the exact same ratio as the two numbers given to the function!

So everything was working fine, but for some reason in some instances, it is not picking up every tuple. Here is an example of it, and I don't know why:

In [52]: def find_r(num1,num2):
   ....:         ratio = num1/float(num2)
   ....:         ratio = 1/ratio
   ....:         my_list = [(a,int(a * ratio)) for a in range(1,num1) if float(a * ratio).is_integer()] #and a * 1/float(ratio) + a <= num1]
   ....:         return my_list
   ....: 

In [53]: find_r(100,364)
Out[53]: [(75, 273)]

so it returned just one tuple, but if you divide both 75 and 273 by 3, you get a tuple of 25 and 91, which have the same ratio! Why did my function not pick up this instance?

If it helps, I do suspect it has something to do with the is_integer() method, but I am not too sure.

Thanks!

It is due to the imprecision of floating point arithmetic:

>>> ((100/364)*364).is_integer()
False
>>> ((25/91)*91).is_integer()
False

Instead of doing what you're doing, you should check for equivalence of fractions by cross-multiplying. That is, given a fraction a/b , to check if it is equivalent to another c/d , check whether ad == bc . This will avoid division and keep everything as integers.

You can do this:

def find_r(num1,num2):
    return [(a, a*num2//num1) for a in range(1, num1) if (a*num2) % num1 == 0]

>>> find_r(100, 364)
[(25, 91), (50, 182), (75, 273)]

(There are other ways to accomplish your task, but this is the most similar to your original approach.)

I think that you get the answer you expect

>>> r=100/float(364)
>>> r
0.27472527472527475
>>> r=1/r
>>> r
3.6399999999999997
>>> r*25
90.99999999999999
>>> r*75
273.0

To make your integer check, you can use

if(int(a*ratio) == a*ratio) like in

def find_r(num1,num2):
       ratio = num1/float(num2)
       ratio = 1/ratio
       my_list = [(a,int(a * ratio)) for a in range(1,num1) if int(a * ratio) == a * ratio] 
       for a in range(1,num1):
           if int(a * ratio) == a * ratio:
               print a * ratio
       return my_list


print find_r(100,364)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM