2

I'm a new at programming, I like solving this euler questions and I know there are solutions for this problem but it's not about the problem at all actually.

enter image description here

So, i managed to create a working function for finding example: 33. triangular number. It works but i couldn't manage to properly desing my while loop. I wanted to make it like, it starts from first triangular checks it's divisors make list of it's divisors, checks the length of the divisors, because problem wants "What is the value of the first triangle number to have over five hundred divisors?" . But i never managed to work the while loop. Thank you for reading.

nums = [1]
triangles = [1]
divisors = []

def triangularcreator(x):
    if x == 1:
        return 1
    n = 1
    sum = 0
    while n!=0:
        n += 1
        nums.append(n)
        for i in range(len(nums)):
            sum += nums[i]
        triangles.append(sum)
        sum = 0
        if x == len(triangles):
            n = 0
    return triangles[-1]


counter = 1
while True:
    for i in range(1, triangularcreator(counter) + 1):
        if triangularcreator(counter) % i == 0:
            divisors.append(i)
    if len(divisors) == 500:
        print(triangularcreator(counter))
        break
    counter +=1
    divisors.clear()
Ignacio Alorre
  • 7,307
  • 8
  • 57
  • 94

2 Answers2

1

You should try to change a few things, starting with calculating just once the value of triangularcreator(counter) and assigning this value to a variable that you can use in different points of your code.

Second, you create a loop which will be calculate always triangularcreator(1). At the end of each iteration you increase the value of counter+=1, but then at the beginign of the new iteration you assignt it again value 1, so it will not progress as you expect. Try this few things:

counter = 1

while True: 
    triangle = triangularcreator(counter)
    for i in range(1, triangle  + 1):
        if triangle  % i == 0:
            divisors.append(i)
    if len(divisors) == 500:
        print(triangle )
        break
    counter +=1

Also these two arrays nums = [1], triangles = [1] should be declared and initialized inside the def triangularcreator. Otherwise you would be appending elements in each iteration

Edit: I believe it is better to give you my own answer to the problem, since you are doing some expensive operations which will make code to run for a long time. Try this solution:

import numpy as np

factor_num = 0
n = 0

def factors(n):
    cnt = 0
    # You dont need to iterate through all the numbers from 1 to n
    # Just to the sqrt, and multiply by two. 
    for i in range(1,int(np.sqrt(n)+1)):
        if n % i == 0:
            cnt += 1
    # If n is perfect square, it will exist a middle number
    if (np.sqrt(n)).is_integer():
      return (cnt*2)-1
    else:
      return (cnt*2)-1

while factor_num < 500:
    # Here you generate the triangle, by summing all elements from 1 to n
    triangle = sum(list(range(n)))
    # Here you calculate the number of factors of the triangle
    factor_num = factors(triangle)
    n += 1

print(triangle)
Ignacio Alorre
  • 7,307
  • 8
  • 57
  • 94
  • Yes, thank you, i realized counter = 1 inside while loop after i posted silly me. I tried your way but while loop continues, did the full code worked for you with your correction ? – Ahmet Özgür Jan 07 '21 at 20:04
  • @AhmetÖzgür what is the result you are expecting to get? – Ignacio Alorre Jan 07 '21 at 20:07
  • Well at least something, it never stops, i expect to get the "first triangle number to have over five hundred divisors" – Ahmet Özgür Jan 07 '21 at 20:10
  • @AhmetÖzgür I wrote my own solution to the problem, it completes in a few seconds. – Ignacio Alorre Jan 07 '21 at 20:59
  • Hello, thank you i understand everything except why we multiply by two after sqrt ? – Ahmet Özgür Jan 07 '21 at 23:03
  • @AhmetÖzgür regarding factors, the reason is most of the factors come in pais, for example to get 28, if 1 is a factor then 28 also, if 2 is a factor, then 14 also, if 4 is a factor then 7 also... so you dont need to inspect from 1 to 28, only from 1 to sqrt(28), then you multiply by 2. But there is an exception, number which are a square root, since they have like a middle number. For example 36: 1 and 36, 2 and 18, 3 and 12, 4 and 9 but... 6*6 is also 36. Since you count factors only one you need to do a -1 for square numbers. Let me know if you if it is clear now – Ignacio Alorre Jan 08 '21 at 07:36
0

Turns out that both of your while loop are infinite either in triangularcreatorin the other while loop:

nums = [1]
triangles = [1]
divisors = []

def triangularcreator(x):
    if x == 1:
        return 1
    n = 1
    sum = 0
    while n:

        n += 1
        nums.append(n)
        for i in range(len(nums)):
            sum += nums[i]
        triangles.append(sum)
        sum = 0
        if len(triangles) >= x:
            return triangles[-1]
    return triangles[-1]


counter = 1
while True:
    check = triangularcreator(counter)
    for i in range(1, check + 1):
        if check % i == 0:
            divisors.append(i)

    if len(divisors) >= 500:
        tr = triangularcreator(counter)
        print(tr)
        break
    counter +=1

Solution

Disclaimer: This is not my solution but is @TamoghnaChowdhury, as it seems the most clean one in the web. I wanted to solve it my self but really run out of time today!

import math


def count_factors(num):
    # One and itself are included now
    count = 2
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            count += 2
    return count


def triangle_number(num):
    return (num * (num + 1) // 2)


def divisors_of_triangle_number(num):
    if num % 2 == 0:
        return count_factors(num // 2) * count_factors(num + 1)
    else:
        return count_factors((num + 1) // 2) * count_factors(num)


def factors_greater_than_triangular_number(n):
    x = n
    while divisors_of_triangle_number(x) <= n:
        x += 1
    return triangle_number(x)


print('The answer is', factors_greater_than_triangular_number(500))
Federico Baù
  • 6,013
  • 5
  • 30
  • 38