Reputation: 171
In python I need a function that takes an integer and returns the absolute value of n minus the nearest triangle number to n. The way I'm doing it now is by generating a list of all the triangle numbers up to n. Then using:
def closest(myList, myNumber):
c = min(myList, key=lambda x:abs(x-myNumber))
To find the closest triangle number.
The end result list should look like:
[0, 0, 1 , 0 , 1 ,1 , 0 , 1, 2 , 1, 0 , 1, 2, 2, 1, 0, etc.]
If you have another method of generating the same result that's faster go for it.
Upvotes: 2
Views: 3458
Reputation: 155
In my solution I have used the fact that let K = sqrt(2*N) if N is a triangular number then it will be Kth triangular number We know Kth triangular number will be K*(K+1)/2
Here is my solution in Python
from math import sqrt
from math import floor
def close_triangle(n):
m = floor(sqrt(2*n))
t1 = m*(m+1)/2 #next triangular number to n
m = m-1
t2 = m*(m+1)/2 #previous triangular number to n
diff1 = t1-n
diff2 = n - t2
if diff1 < diff2 :
return t1
else:
return t2
print "Nearest trianguler number";
print close_triangle(13)
Upvotes: 2
Reputation: 54380
A little bit of math will bring a more analytical solution:
from math import sqrt
def close_triangle2(n):
m=int(0.5*(-1+sqrt(1+8*n))) #solve it for the explicit formula
tan0=(m*m+m)/2 #the closest one is either this
tan1=(m*m+3*m+2)/2 #or this
if (n-tan0)>(tan1-n):
return tan1-n
else:
return n-tan0
It will become slightly faster than the loop version from @perreal when the number is large:
In [87]:
%timeit close_triangle(111111111)
100000 loops, best of 3: 5 µs per loop
In [86]:
%timeit close_triangle2(111111111)
100000 loops, best of 3: 4.13 µs per loop
If you wonders:
In [94]:
close_triangle2((30**10 * (30**10+1)) / 2 + 100)
Out[94]:
100L
In [95]:
close_triangle((30**10 * (30**10+1)) / 2 + 100)
Out[95]:
100L
In [102]:
%timeit close_triangle((30**10 * (30**10+1)) / 2 + 100)
10000 loops, best of 3: 17.9 µs per loop
In [103]:
%timeit close_triangle2((30**10 * (30**10+1)) / 2 + 100)
100000 loops, best of 3: 12 µs per loop
Upvotes: 4
Reputation: 9105
You can leverage the triangle-root property to quickly calculate the nearest triangle number to a number, and from there easily calculate your value
from math import sqrt
def triangle_number(tnumber):
'''
returns the tnumberth triangle number (I.E 3 = 6)
'''
return (tnumber*(tnumber+1))/2
def triangle_root(number):
'''
returns the triangle root of a number (I.E 6 = 3)
'''
return (sqrt(8*number+1)-1)/2
def nearest_root(number):
'''
Calculates the nearest whole triangle root to a number (I.E. 5 = 3)
'''
t_root = triangle_root(number)
return round(t_root)
def find_delta(number):
'''
Given a number, returns abs(n-nearest_triangle)
'''
return abs(number - triangle_number(nearest_root(number)))
Of course you could condense this into a single function for efficiency, I just spaced it out for clarity.
Upvotes: 2
Reputation: 2620
I have one solution that doesn't need calculate every triangle number first, but I am not sure whether it's best.
As formula of triange number is
A(n) = n*(n-1)/2 (n is integer)
For input x, it should be in middle of A(n) and A(n+1)
A(n) <= x <= A(n+1)
For A(n) we have:
n * (n - 1) / 2 <= x
(n - 1)^2 < n * (n-1) <= 2*x
n < sqrt(2*x) + 1
For A(n+1) we have:
(n + 1)^2 > (n + 1) * n >= 2*x
n > sqrt(2*x) - 1
Now, if we have input number x, we could rapidly find n that makes x in [A(n),A(n+1)], then we only need to calculate distance of [abs(A(n) - x),abs(A(n+1) - x)] and make smallar one as real output.
Upvotes: 0
Reputation: 98088
May not be the best way but should be faster than your method:
def triangle_around(n):
k = int((2*n)**0.5)
p = (k**2 + k) / 2
while p < n:
k, p = k + 1, p + k + 1
return (p - k, p)
def close_triangle(n):
t = triangle_around(n)
return min(t[1] - n, n - t[0])
print close_triangle(8) # gives 2
Upvotes: 1