Just a quick random one…
A friend recently proposed the following problem as part of their coursework (which I’ve changed to not give away the answers to others):
A sequence of numbers are defined as:
You are to define a function
find_x(target)
that returns the smallest value of where is greater than or equal to thetarget
value.If implemented correctly, you should expect to see:
Not too complicated - and I was really just helping with their debugging process as a new Python programmer.
Given how quickly something like this can be coded, I decided to whip something up so that I could test the correctness of their solution:
0001 def find_x(target) : 0002 x = 1 0003 z_x = 1 0004 while z_x < target : 0005 z_x = (13 * z_x) + 7 0006 x += 1 0007 return x
Testing:
0008 print(find_x(1)) 0009 print(find_x(10)) 0010 print(find_x(100)) 0011 print(find_x(1000)) 0012 print(find_x(10000)) 0013 print(find_x(100000))
And the results of the program:
0014 1 0015 2 0016 3 0017 4 0018 5 0019 6
Passes the sniff test.
So that is kind of boring, but probably of help for others. Let’s dissect this a little and make it more interesting…
Firstly, what problems does this current version have? I.e. What traps are there for new players?
For the first two, we can do something like (we’d likely pre-calculate max_z_x
):
0020 def find_x_v2(target) : 0021 max_z_x = (sys.maxint - 5) / 13 0022 assert(target >= 1) 0023 x = 1 0024 z_x = 1 0025 while z_x < target : 0026 assert(z_x < max_z_x) 0027 z_x = (13 * z_x) + 7 0028 x += 1 0029 return x
And for testing:
0030 print(find_x_v2(1)) # 1 0031 print(find_x_v2(10)) # 2 0032 print(find_x_v2(100)) # 3 0033 print(find_x_v2(1000)) # 4 0034 print(find_x_v2(10000)) # 5 0035 print(find_x_v2(100000)) # 6 0036 print(find_x_v2(1000000)) # 7 0037 print(find_x_v2(10000000)) # 8 0038 print(find_x_v2(100000000)) # 9 0039 print(find_x_v2(1000000000)) # 10 0040 print(find_x_v2(10000000000)) # 11 0041 print(find_x_v2(100000000000)) # 12 0042 print(find_x_v2(1000000000000)) # 13 0043 print(find_x_v2(10000000000000)) # 14 0044 print(find_x_v2(100000000000000)) # 15 0045 print(find_x_v2(1000000000000000)) # 16 0046 print(find_x_v2(10000000000000000)) # 17 0047 print(find_x_v2(100000000000000000)) # 18 0048 print(find_x_v2(1000000000000000000)) # 19 0049 print(find_x_v2(10000000000000000000)) # 20 0050 print(find_x_v2(100000000000000000000)) # 21
And as a result we get:
0051 1 0052 2 0053 3 0054 4 0055 5 0056 6 0057 7 0058 8 0059 9 0060 9 0061 10 0062 11 0063 12 0064 13 0065 14 0066 15 0067 16 0068 17 0069 17 0070 Traceback (most recent call last): 0071 File "main.py", line 41, in <module> 0072 print(find_x_v2(10000000000000000000)) # 20 0073 File "main.py", line 17, in find_x_v2 0074 assert(z_x < max_z_x) 0075 AssertionError
So it appears that Python correctly crashes for suitably large integer values.
Start off with the following formula:
For the third case (skipping the second) we can write:
For the fourth case we can write:
There appears to be a pattern…
For example:
Whilst it’s annoying that we have this long term that expands, actually for the most part we can ignore it. The first term is much larger than all the summed terms down to . For the search we can therefore simplify to:
We are trying to find something around the target, , so now we search for:
This can be rewritten as:
And now we have something for approximating the location of some positive value of given some target .
I’m not going to go to the effort of programming this (because I don’t care so much), but it’s interesting to see that it’s possible to find an approximate solution very quickly, without being required to do a large loop. In theory you can now find arbitrary values by performing just a ‘few’ calculations either side of the predicted value 1.
I would need to think about exactly a search strategy.↩︎