In number theory, an  **[abundant](https://en.wikipedia.org/wiki/Abundant_number)** number or an **[excessive](https://en.wikipedia.org/wiki/Abundant_number)** number is one for which the sum of it's **[proper divisors](http://mathworld.wolfram.com/ProperDivisor.html)** is greater than the number itself.  The integer **12** is the first abundant number. Its proper divisors are 1, 2, 3, 4 and 6 for a total of **16**. The amount by which the sum exceeds the number is the **abundance**. The number **12** has an abundance of **4**, for example. Other initial abundant numbers are : 12, 18, 20, 24, 30, 36, 40, 42, 48, 54 etc . **Infinitely** many **odd** and **even** abundant numbers exist.    
As you should have guessed by now, in this kata your function will take a positive integer **h** as range input and return a nested array/list that will contain the following informations-    

* Highest available **odd** or **even** abundant number in that range
* It's **abundance**    

Examples
--------
A few examples never hurt nobody, right???    

```rust   
abundant(15)  = [[12], [4]]
abundant(19)  = [[18], [3]]
abundant(100) = [[100], [17]]
abundant(999) = [[996], [360]]
```

Tips
----
The problem involves some pretty big random numbers. So try to optimize your code for performance as far as you can. And yes, the input argument will always be positive integers. So no need to check there.

Good luck!

Source: codewars | Difficulty: EASY
Tags: Fundamentals

Mathematics

Starter code: def abundant(h):
	

Solutions:
def abundant(h):
	for n in range(h, 0, -1):
		s = sum((i for i in range(1, n) if n % i == 0))
		if s > h:
			return [[n], [s - n]]


from operator import itemgetter
from bisect import bisect
LIMIT = 2000
(memo, result) = ([0] * LIMIT, {})
for x in range(1, LIMIT):
	if memo[x] > x:
		result[x] = memo[x] - x
	if x < LIMIT // 2:
		for y in range(x, LIMIT, x):
			memo[y] += x
values = list(result.keys())

def abundant(h):
	x = values[bisect(values, h) - 1]
	return [[x], [result[x]]]


def ab(n):
	s = 1
	for i in range(2, int(n ** 0.5) + 1):
		if n % i == 0:
			s += i
			if i * i != n:
				s += n // i
	return s - n

def abundant(h):
	for i in range(h, 0, -1):
		a = ab(i)
		if a > 0:
			return [[i], [a]]


def abundant(limit):
	for n in range(limit, 0, -1):
		div_sum = sum((x for x in range(1, n // 2 + 1) if n % x == 0))
		if div_sum > n:
			return [[n], [div_sum - n]]


def abundant(h):
	for n in range(h, 0, -1):
		s = sum((d + n // d for d in range(2, int(n ** 0.5) + 1) if not n % d)) - n ** 0.5 * (not n ** 0.5 % 1) + 1
		if s > n:
			return [[n], [s - n]]


def abundant(h):
	for i in range(h + 1)[::-1]:
		sum = 0
		for j in range(1, i):
			if i % j == 0:
				sum += j
		if sum > h:
			return [[i], [sum - i]]


def abundant(h):
	s = sigma(h)
	while s < h:
		h -= 1
		s = sigma(h)
	return [[h], [s - h]]

def sigma(x):
	(sq, s, i) = (x ** 0.5, 1, 2)
	while i <= sq:
		if x % i == 0:
			s += i + x / i
		if i == sq:
			s -= i
		i += 1
	return s


def abundant(n):
	gen_div = lambda a: set(sum([[a // i, i] for i in range(1, int(a ** 0.5) + 1) if a % i == 0], []))
	r = []
	for i in range(n, 0, -1):
		div_sum = sum(gen_div(i))
		if div_sum - i > i:
			return [[i], [div_sum - i * 2]]


def abundant(h):
	for i in range(h, 11, -1):
		temp = set([1])
		for j in range(2, int(i ** 0.5) + 1):
			if i % j == 0:
				temp.add(j)
				temp.add(i // j)
		x = sum(temp)
		if x > i:
			return [[i], [x - i]]
	return 12