Skip to content

Commit 32e611f

Browse files
author
Srishtik2310
committed
Added solution for probelm_686 of project_euler
1 parent 672a0c8 commit 32e611f

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

project_euler/problem_686/__init__.py

Whitespace-only changes.

project_euler/problem_686/sol1.py

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""
2+
Project Euler Problem 686: https://projecteuler.net/problem=686
3+
4+
2**7 = 128 is the first power of two whose leading digits are "12".
5+
The next power of two whose leading digits are "12" is 2**80.
6+
7+
Define p(L,n) to be the nth-smallest value of j such that
8+
the base 10 representation of 2**j begins with the digits of L.
9+
10+
So p(12, 1) = 7 and p(12, 2) = 80.
11+
12+
You are given that p(123, 45) = 12710.
13+
14+
Find p(123, 678910).
15+
"""
16+
17+
import math
18+
19+
20+
def log_difference(number: int) -> float:
21+
"""
22+
This function returns the decimal value of a number multiplied with log(2)
23+
Since the problem is on powers of two, finding the powers of two with
24+
large exponents is time consuming. Hence we use log to reduce compute time.
25+
26+
We can find out that the first power of 2 with starting digits 123 is 90.
27+
Computing 2**90 is time consuming.
28+
Hence we find log(2**90) = 90*log(2) = 27.092699609758302
29+
But we require only the decimal part to determine whether the power starts with 123.
30+
SO we just return the decimal part of the log product.
31+
Therefore we return 0.092699609758302
32+
33+
>>> log_difference(90)
34+
0.092699609758302
35+
>>> log_difference(379)
36+
0.090368356648852
37+
38+
"""
39+
40+
log_number = math.log(2, 10) * number
41+
difference = round((log_number - int(log_number)), 15)
42+
43+
return difference
44+
45+
46+
# series = 90, 379, 575, 864, 1060, 1545, 1741, 2030, 2226, 2515
47+
48+
49+
def solution(number: int = 678910) -> int:
50+
"""
51+
This function calculates the power of two which is nth (n = number)
52+
smallest value of power of 2
53+
such that the starting digits of the 2**power is 123.
54+
55+
For example the powers of 2 for which starting digits is 123 are:
56+
90, 379, 575, 864, 1060, 1545, 1741, 2030, 2226, 2515 and so on.
57+
90 is the first power of 2 whose starting digits are 123,
58+
379 is second power of 2 whose starting digits are 123,
59+
and so on.
60+
61+
So if number = 10, then solution returns 2515 as we observe from above series.
62+
63+
Wwe will define a lowerbound and upperbound.
64+
lowerbound = log(1.23), upperbound = log(1.24)
65+
because we need to find the powers that yield 123 as starting digits.
66+
67+
log(1.23) = 08990511143939792, log(1,24) = 09342168516223506.
68+
We use 1.23 and not 12.3 or 123, because log(1.23) yields only decimal value
69+
which is less than 1.
70+
log(12.3) will be same decimal vale but 1 added to it
71+
which is log(12.3) = 1.093421685162235.
72+
We observe that decimal value remains same no matter 1.23 or 12.3
73+
Since we use the function log_difference(),
74+
which returns the value that is only decimal part, using 1.23 is logical.
75+
76+
If we see, 90*log(2) = 27.092699609758302,
77+
decimal part = 0.092699609758302, which is inside the range of lowerbound
78+
and upperbound.
79+
80+
If we compute the difference between all the powers which lead to 123
81+
starting digits is as follows:
82+
83+
379 - 90 = 289
84+
575 - 379 = 196
85+
864 - 575 = 289
86+
1060 - 864 = 196
87+
88+
We see a pattern here. The difference is either 196 or 289 = 196 + 93.
89+
90+
Hence to optimize the algorithm we will increment by 196 or 93 depending upon the
91+
log_difference() value.
92+
93+
Lets take for example 90.
94+
Since 90 is the first power leading to staring digits as 123,
95+
we will increment iterator by 196.
96+
Because the difference between any two powers leading to 123
97+
as staring digits is greater than or equal to 196.
98+
After incrementing by 196 we get 286.
99+
100+
log_difference(286) = 0.09457875989861 which is greater than upperbound.
101+
The next power is 379, and we need to add 93 to get there.
102+
The iterator will now become 379,
103+
which is the next power leading to 123 as starting digits.
104+
105+
Lets take 1060. We increment by 196, we get 1256.
106+
log_difference(1256) = 0.09367455396034,
107+
Which is greater than upperbound hence we increment by 93. Now iterator is 1349.
108+
log_difference(1349) = 0.08946415071057 which is less than lowerbound.
109+
The next power is 1545 and we need to add 196 to get 1545.
110+
111+
Conditions are as follows:
112+
113+
1) If we find a power, whose log_difference() is in the range of
114+
lower and upperbound, we will increment by 196.
115+
which implies that the power is a number which will lead to 123 as starting digits.
116+
2) If we find a power, whose log_difference() is greater than or equal upperbound,
117+
we will increment by 93.
118+
3) if log_difference() < lowerbound, we increment by 196.
119+
120+
>>> solution(1000)
121+
284168
122+
123+
>>> solution(56000)
124+
15924915
125+
126+
>>> solution(678910)
127+
193060223
128+
129+
"""
130+
131+
power_iterator = 90
132+
position = 0
133+
134+
lower_limit = math.log(1.23, 10)
135+
upper_limit = math.log(1.24, 10)
136+
previous_power = 0
137+
138+
while position < number:
139+
difference = log_difference(power_iterator)
140+
141+
if difference >= upper_limit:
142+
power_iterator += 93
143+
144+
elif difference < lower_limit:
145+
power_iterator += 196
146+
147+
else:
148+
previous_power = power_iterator
149+
power_iterator += 196
150+
position += 1
151+
152+
return previous_power
153+
154+
155+
if __name__ == "__main__":
156+
import doctest
157+
158+
doctest.testmod()
159+
160+
print(f"{solution() = }")

0 commit comments

Comments
 (0)