Project Euler 80 : Summing the decimals of continued fractions of irrational square roots

by Rob on December 28, 2011

in Code Samples,Project Euler,programming

http://projecteuler.net/problem=80
You could probably do this really fast by importing some scientific library to get the square roots at a very high precision (like bigfloat), but I think the spirit of Euler is to do the calculations yourself.

So we can reuse our code from Project Euler 64 on continued fractions. Then you need to reduce those continued fractions into one big numerator and one big denominator (sort of like a backpropagation algorithm). I expanded out the continued fraction using a counter variable (I set it really big at 500).

Be careful, as the question asks for 100 decimal digits. I thought it meant 100 digits after the decimal point, but they want to include the digit before the decimal point.

#euler 80

import math
from decimal import *
getcontext().prec = 110

#let's use our code from Euler 64
def cfRoot(n):
    answer = []
    #step 1: find nearest square root
    first = int(math.sqrt(n))
    if n == first * first:
        return [first]
    else:
        m = first
        answer.append(m)
    #step 2 - reduce to new numerator and denom
    last = answer[-1]
    denom = n - last*last
    numRem = last
    while denom != 1:
        coef = (first + numRem) / denom
        answer.append(coef)
        tempNum = denom
        tempRem = coef * denom - numRem
        tempDenom = n - int(math.pow((tempRem),2))
        tempDenom /= tempNum
        denom = tempDenom
        numRem = tempRem
    final = numRem + answer[0]
    answer.append(final)
    return answer

def fPart(n):  # this is the fractional part of cfRoot
    return cfRoot(n)[1:]   #omit the first number of list

def fractionalize(n):
    fList = fPart(n)
    length = len(fList)
    counter = 500
    indexNew = counter % length
    if indexNew == 0:
        indexNew = length
    indexOld = indexNew - 1
    if indexOld < 1:
        indexOld = length
##    print indexNew, indexOld
    tempNumerator = fList[indexOld-1] * fList[indexNew-1] + 1 #python indices start at 0
    tempDenominator = fList[indexNew-1]
##    print tempNumerator, tempDenominator
    denominator, numerator = tempNumerator, tempDenominator  #reciprocal
##    print numerator, denominator
    counter -= 2   #we reduced the n and n-1 of the repeated continued fraction
    index = indexOld - 1
    while counter >= 1:
        if index == 0:
            index = length
##        print "counter", counter
        tempNumerator = fList[index-1] * denominator + numerator
        denominator, numerator = tempNumerator, denominator
##        print numerator, denominator
        index -= 1
        counter -= 1
    return numerator, denominator

def decimalize(n):
    numerator, denominator = fractionalize(n)
    return Decimal(numerator)/Decimal(denominator)

def truncate(n):  #project euler wants you to calculate to 99 decimal places and add the number preceding
    temp = str(decimalize(n))[2:101]
##    print temp
##    print len(temp)
    return sum(int(x) for x in temp)

def sumDigits(n):
    return cfRoot(n)[0] + truncate(n)  #add the first digit

testList = [x for x in range(2,100)]
for y in range(2,10):
    testList.remove(y*y)

total = 0
for j in testList:
    temp = sumDigits(j)
    total += sumDigits(j)
    print j, temp, total

print total

Leave a Comment

Previous post:

Next post: