Skip to content

Commit

Permalink
Merge pull request #9 from FranzDiebold/feat/add-solution-for-problem-48
Browse files Browse the repository at this point in the history
Add solution for problem 48.
  • Loading branch information
FranzDiebold authored Jun 20, 2020
2 parents 388d4c3 + 8ae2e11 commit 959c19b
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# [Project Euler](https://projecteuler.net) Solutions

[![solved: 47 problems](https://img.shields.io/badge/solved-47_problems-f93.svg)](./src)
[![solved: 48 problems](https://img.shields.io/badge/solved-48_problems-f93.svg)](./src)
![Python: 3.8](https://img.shields.io/badge/Python-3.8-3776ab.svg)
[![Lint and Test](https://github.com/FranzDiebold/project-euler-solutions/workflows/Lint%20and%20Test/badge.svg)](https://github.com/FranzDiebold/project-euler-solutions/actions?query=workflow%3A%22Lint+and+Test%22)
[![license: MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](./LICENSE.md)
Expand Down
11 changes: 7 additions & 4 deletions src/common/calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def calculate_large_sum(number_strings: Iterable[str]) -> str:
Returns:
The sum of the numbers as string.
"""
number_strings = list(number_strings)
large_sum = ''
new_digit = True
digit_idx = 1
Expand Down Expand Up @@ -56,20 +57,22 @@ def _multiply_large_number_and_digit(number: str, digit: int) -> str:
return large_product


def calculate_large_product(number1: str, number2: str) -> str:
def calculate_large_product(number1: str, number2: str, last_n_digits_only: int = 0) -> str:
"""Multiply two large numbers given as string. The result will be a string as well."""
number1 = number1[-last_n_digits_only:]
number2 = number2[-last_n_digits_only:]
partial_products = []
for digit_idx, digit_value in enumerate(reversed(number2)):
partial_product = _multiply_large_number_and_digit(number1, int(digit_value)) + \
('0' * digit_idx)
partial_products.append(partial_product)
return calculate_large_sum(partial_products)
return calculate_large_sum(partial_products)[-last_n_digits_only:]


def calculate_large_power(base: int, exponent: int) -> str:
def calculate_large_power(base: int, exponent: int, last_n_digits_only: int = 0) -> str:
"""Calculate `base` to the power of `exponent` for large numbers given as strings."""
base = str(base)
power = '1'
for _ in range(exponent):
power = calculate_large_product(power, base)
power = calculate_large_product(power, base, last_n_digits_only)[-last_n_digits_only:]
return power
40 changes: 40 additions & 0 deletions src/p048_self_powers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
Problem 48: Self powers
https://projecteuler.net/problem=48
The series, 1^1 + 2^2 + 3^3 + ... + 10^10 = 10405071317.
Find the last ten digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000.
"""

from typing import Iterable
import itertools

from src.common.calculations import calculate_large_power, calculate_large_sum


# pylint: disable=invalid-name
def get_self_powers(last_n_digits_only: int = 0) -> Iterable[str]:
"""Get increasing self powers `n^n` (`1^1`, `2^2`, ...) as an Iterable."""
n = 1
while True:
yield calculate_large_power(n, n, last_n_digits_only)
n += 1


def get_self_powers_sum(max_n: int, last_n_digits_only: int = 0) -> str:
"""Get the series, `1^1 + 2^2 + ... + max_n^max_n`."""
return calculate_large_sum(itertools.islice(get_self_powers(last_n_digits_only), max_n))


def main() -> None:
"""Main function."""
max_n = 1000
last_n_digits_only = 10
self_powers_sum = get_self_powers_sum(max_n, last_n_digits_only)
print(f'The last ten digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000 ' \
f'are {self_powers_sum[-last_n_digits_only:]}.')


if __name__ == '__main__':
main()
26 changes: 26 additions & 0 deletions test/common/test_calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ def test_calculate_large_product(test_input_number1, test_input_number2, expecte
assert actual_result == expected_result


def test_calculate_large_product_with_last_n_digits_only():
# arrange
from src.common.calculations import calculate_large_product

# act
actual_result = calculate_large_product('7365827', '92890273', 6)

# assert
# 7365827 * 92890273 = 684.213.680.900.771
expected_result = '900771'
assert actual_result == expected_result


@pytest.mark.parametrize('test_input_base,test_input_exponent,expected_result', [
(2, 3, '8'),
(42, 2, '1764'),
Expand All @@ -69,3 +82,16 @@ def test_calculate_large_power(test_input_base, test_input_exponent, expected_re

# assert
assert actual_result == expected_result


def test_calculate_large_power_with_last_n_digits_only():
# arrange
from src.common.calculations import calculate_large_power

# act
actual_result = calculate_large_power(8, 9, 5)

# assert
# 8^9 = 134.217.728
expected_result = '17728'
assert actual_result == expected_result
45 changes: 45 additions & 0 deletions test/test_p048_self_powers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Problem 48: Self powers
https://projecteuler.net/problem=48
The series, 1^1 + 2^2 + 3^3 + ... + 10^10 = 10405071317.
Find the last ten digits of the series, 1^1 + 2^2 + 3^3 + ... + 1000^1000.
"""


def test_get_self_powers():
# arrange
from src.p048_self_powers import get_self_powers

# act
actual_result_iter = get_self_powers()

# assert
expected_result = ['1', '4', '27', '256', '3125', '46656', '823543', '16777216']
for expected_self_power in expected_result:
assert next(actual_result_iter) == expected_self_power


def test_get_self_powers_sum():
# arrange
from src.p048_self_powers import get_self_powers_sum

# act
actual_result = get_self_powers_sum(10)

# assert
expected_result = '10405071317'
assert actual_result == expected_result


def test_get_self_powers_sum_with_last_n_digits_only():
# arrange
from src.p048_self_powers import get_self_powers_sum

# act
actual_result = get_self_powers_sum(10, 5)

# assert
expected_result = '71317'
assert actual_result.endswith(expected_result)

0 comments on commit 959c19b

Please sign in to comment.