简体   繁体   中英

Python error from rounding float value of fraction

I am attempting project Euler question #214 ( https://projecteuler.net/problem=214 ) and after a while playing with things I have the functionality working but unfortunately, due to the error where fractions can not be represented exactly, the program outputs some incorrect responses.

The task is essentially to use Euler's totient function ( phi ), which determines the number of co-primes of a number, k , from 1 to k inclusive. Find phi(x) , then x = phi(x) and so on until x = 1 , forming a chain, and find the sum of all primes less than 40 million which form a chain of length 25.

The method of finding phi I have chosen involves multiplying a number, k , by 1 - 1/p for each of its prime factors (represented by p ). Unfortunately, with certain values such as 3322 , the correct phi value is 1500 , but due to pythons storage of primes, the total rounds to 1499 instead. As the numbers grow, the disparity between the correct and outputted answer also grows.

I have tried using Decimal to give a more accurate value but this hasn't worked.

Any advice is appreciated,

def phi(n, phi_values):
    if n in phi_values:
        return phi_values[n]
    else:
        if test_prime(n):
            phi_values[n] = n - 1
            return n - 1
        else:
            factors = prime_factors(n)
            val = int(n * reduce((lambda x, y: x * y), factors))
            phi_values[n] = val
            return val

def prime_factors(n):
    i = 2
    factors = []
    while i * i <= n:
        if n % i:
            i += 1
        else:
            n //= i
            hold = Decimal(1 - (1 / i))
            if not hold in factors: factors.append(hold)
    if n > 1:
        hold = Decimal(1 - (1 / n))
        if not hold in factors: factors.append(hold)
    return factors

Sadly I can't just comment, it might help to use this function float.as_integer_ratio() , it should reduce the rounding error, if you know what kind of precision you want you could also use math.isclose() and give a rounded number yourself.

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