• Coding
  • [Exercise] Triangle numbers divisors

@rahmu can you please explain every byte in this?
def prime_factors(n):
d = 2
while (n > 1):
while (n%d==0):
yield d # Especially those
n /= d # two lines
d = d + 1
Thanks in advance rahmu, i just love learning programming.
Ra8 wrote
arithma wrote@Ra8: That trick you have is pretty neat. How'd you think about it? (Referring to the }while(divs(n1)*divs(n2)<500);)
Well this works only in this case since n and n+1 will never have a common divisor.
if you had for example 4 ={1,2,4} and 6={1,2,3,6} 24={1,2,3,4,6,8,12,24} in this case it will not work because 2 is a common divisor
The smart thing about it is notices how i & i+1 are coprime, and hence all their divisors are coprime as well.
Very observant is the least I can say.

I tried to beat its performance by keeping a set of already visited primes (while iterating through triangle numbers) but it' not helping at all.
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
using namespace std;

int count_reused = 0;
int count_explord = 0;
set<int> primes;

int primePower(int64_t& n, int prime){
    int count = 0;
    
    while(n % prime == 0){
        
        int64_t multi = prime;
        int c = 1;
        while(n % (multi*multi) == 0){
            multi *= multi;
            c *= 2;
        }
        
        count += c;
        n /= multi;
    }
    
    return count;
}

int divs(int64_t n){
    int result = 1;
    int sqr = sqrt(n);
    
    set<int>::iterator itr = lower_bound(primes.begin(), primes.end(), sqr);
    if(itr == primes.end())
        itr--;
    
    while(n > 1){
        int prime = *itr;
        if(n % prime == 0){
            count_reused++;
            result *= primePower(n, prime) + 1;
        }
        
        if(itr == primes.begin())
            break;
        
        itr--;
    }
    
    int div = 2;
    while(n > 1 && div < n){
        if(n % div == 0){
            count_explord++;
            primes.insert(div);
            result *= primePower(n, div) + 1;
        }
        
        div++;
    }
    
    return result;
}

int main(){
    primes.insert(2);
    
    int64_t sum = 0;
    int i = 1;
    int64_t d;
    do {
        sum += i;
//        d = divs(sum);
        d = i % 2 == 0 ? divs(i/2)*divs(i+1) : divs((i+1)/2)*divs(i);
        if(i%1000==0){
            cout << i << " triangle numbers tried so far" << endl;
            cout << sum << " << triangle number max" << endl;
        }
        i++;
    } while (d < 1000);
    cout << "reused " << count_reused << endl;
    cout << "explored " << count_explord << endl;
    cout << "triangle# = " << sum << " & divisors = " << d << endl;
    cout << "largest prime " << *(primes.rbegin()) << endl;
    cout << "primes explored so far = " << primes.size() << endl;
    return 0;
}
Analyzing through, this is what I came up with:
The first advantage for Ra8's approach is the fact that for triangle number n, it only need to find divisors for its square root. For odd i for example, n=i*(i+1)/2. i in this case is comparable to square root of n. The algorithm for finding the number of divisors for i only has to go up to sqrt(i].
So the complexity of finding divisors for a triangle number in this case is only: O(sqrt(sqrt(n))

I would have sworn before trying it that keeping aside prime numbers for later would even beat the above asymptotically, but it doesn't. It returns almost instantly for finding a triangle number with more than 500 divisors. But checking how it starts to behave near the larger numbers, it's no where near as performant. I have no idea why.
NuclearVision wrote@rahmu can you please explain every byte in this?
Sorry for the late answer. It behaves a little bit like this:
def pf(n):
    d = 2
    primes = []
    while (n>1):
        while (n%d == 0):
            primes.append(d)
            n /= d
        d = d + 1

    return primes
The difference between the two pieces of code are subtle and a bit difficult to grasp, but take a look anyway at this very good explanation of Python yield keyword.
@rahmu i understood that yield creates a generator of the form [ func(j) for j in sequence ], that can be used once.
But i still don't get the n/=d., which probably means n=d/n, but we can't change the value of n, and let's say we changed it, is this some type of recursion?

Thanks for the explanation anyway.
8 days later
NuclearVision wrotei still don't get the n/=d., which probably means n=d/n,
No.

In Python the two following expressions are equivalent:

• a (op)= b
• a = a (op) b

Thus n /= d is equivalent to n = n/d.
NuclearVision wrotebut we can't change the value of n
The function is not changing the value of n, it's changing the value of a copy of n. What do you think the output of the following code will be?
def foo(n):
    n = 5
    return n

n = 10
foo(n)
print(n)
Answer: 10.
This is because the variable n is never passed to function foo. Instead a copy of n, containing the same value, is sent.

Note that this behavior is specific to Python, and you cannot make the same assumptions about other languages. You can learn more by reading the Wikipedia article on Evaluation Strategy.

Also note that Python has a somewhat complex evaluation strategy (similar to the ones used by Java or - surprise - Ruby). You can read more about it here.

Understanding the code better
My favorite way of understanding a piece of code I cannot immediately understand, is to add print() calls. So I modified the code to be like this:
def pf(n):
    d = 2
    primes = []
    while (n > 1):
        while (n % d == 0):
            print d, n, primes
            primes.append(d)
            n /= d
        d = d + 1

    return primes
(Notice the print call on line 6)

You can now experiment with different input inside the python interpreter. I'm assuming you work on Windows, and I don't know how to launch the interpreter there, so maybe somebody else can help you with that. In any case, here are some sample outputs:
>>> pf(24)
2 24 []
2 12 [2]
2 6 [2, 2]
3 3 [2, 2, 2]
[2, 2, 2, 3]

>>> pf(38)
2 38 []
19 19 [2]
[2, 19]

>>> pf(236)
2 236 []
2 118 [2]
59 59 [2, 2]
[2, 2, 59]
3 months later
so i did mine in java
public class TriangleNumber {
    public static boolean divNumber(int n){
        int counter=0;
        int sum=0;
        int end =(int) Math.sqrt(n);
        end++;//because looping to i<end is faster than looping to i<=end
        for(int i = 1 ; i < end; i++){
            if(n%i==0){
                counter+=2;
                sum+=i;
            }
        }
       
        if((counter>500)){
            System.out.println("the result is: "+n);
            return false;
        }

        else
            return true;
    }
    public static void main(String[] args){
       int val=0;
        int inc =0;
        boolean iterrate=true;
        while(iterrate){
            val+=inc;
            iterrate=divNumber(val);
            inc++;

        }

}
}
a year later
ok here's what i got to, finally. Inspired from Ra8's
from math import sqrt
def t(n):
    return n*(n+1)/2
def div(n):
    j=0
    for i in xrange(1,int(sqrt(n))):
        if n%i==0:
            j+=1
    if sqrt(n)-int(sqrt(n))==0:
        return j*2 +1
    else:
        return j*2
i=1
while True:
    i+=1
    if div(t(i))>500:
        print t(i)
        break
5 days later
My solution in C++, takes 1/3 of a second to solve the exercise. Ra8's solution looks interesting, I'll check it out later.
#include <iostream>
#include <cmath>
using namespace std;

int number_of_divisors(int n) {

    int count = 2;
    int square_root = sqrt(n);

    for (int i = 2; i <= square_root; i++)
        if (n%i == 0)
            count++; 

    return (n%square_root == 0) ? count*2-1 : count*2;

}

int main() {

    long n = 1; 
    for (int i = 2; number_of_divisors(n) <= 500; i++)
        n += i;

    cout << n << endl;
    return 0;

}
5 months later
#include <iostream>
#include <math.h>
using namespace std;
long t(int n)
{  return n*(n+1)/2;
}
int divcount( long n)
{ int j=2,i=2,lim=sqrt(n); // the number it self and 1.
    for(i;i<lim;i++)
      { if (n%i==0)
	  {j+=2;
	  }
      }
  return j;
}
int main()
{ int n=1;
  while (true)
    { n++;
      if (divcount(t(n))>500)
	{ cout<<t(n);
          break;
	}
    }
  return 0;
} 
public class triangle {
	public static void main(String [] args){
		int count=0;
		int triangle=0;
		int factors=1;
		int test;
		while (factors <= 500){
                        count=count+1;
                        triangle=triangle+count;
                        factors=1;
                        for(int a=1;a<(Math.sqrt(triangle));a++){
                                test=triangle%a;
				if ( test == 0){
                                   factors=factors+2;
				}
			}
		}
	System.out.print(+triangle);
	}
}
2 years later
Hey guys I'm new here so I don't really know how to post code the way you do, but anyway I've been trying to solve this for some time now and I can't figure out what's wrong, maybe one of you can help me :) here's my Java code :
public class Problem12
{
  public static void main(String[] args)
  {
    long i = 1L;
    long triangle = 0L;
    int nbrOfDiv = 0;
    int highestNbrOfDiv = 0;
    while (highestNbrOfDiv <= 500)
    {
      triangle = newTriangle(triangle, i);
      nbrOfDiv = divisors(triangle);
      if (highestNbrOfDiv < nbrOfDiv) highestNbrOfDiv = nbrOfDiv;      
      i++;
    }
    System.out.print(triangle);
  }
  
  public static long newTriangle(long triangle, long i)
  {
    return triangle+i;
  }
  
  public static int divisors(long number)
  {
    int nbrOfDiv = 0;
    for (long i = 1; i <= (long)(Math.sqrt(number))+1; i++)
    {
      if (number%i == 0) nbrOfDiv++;
    }
    return nbrOfDiv+1;
  }
}
I get 842161320 but this is apparently incorrect.

Would anyone happen to know what's wrong?

Thanks !