Find range of arguments that return the same result for a linear function
<p>Consider the <code>y = round(300000/x**2)</code>. I would like to find the ranges of <code>x</code> that return the same <code>y</code> for <code>100 &lt; x &lt; 40000</code>.</p>

<p>How would I do that with python/numpy?</p>

<p>First of all: the credit of this solution should go to <a href="http://stackoverflow.com/a/39948612/1029516">@CoryKramer</a>, even after the fix in the question.</p>

<pre><code>from itertools import groupby
groups = groupby(range(100, 40000), key=lambda x: round(300000/x**2))
</code></pre>

<p>Anyway there is something you should be aware, due to the division operator you are using: currently you used <em>integer division</em>, but using the <em>true division</em> operator can lead to slightly different grouping due to rounding (<code>300000/x**2</code> vs <code>300000.0/x**2</code>).</p>

<pre><code>from itertools import groupby
groups_int = groupby(range(100, 40000), key=lambda x: round(300000/x**2))
groups_true = groupby(range(100, 40000), key=lambda x: round(300000.0/x**2))


res_int  = [(g[0], [n for n in g[1]]) for g in groups_int]
res_true = [(g[0], [n for n in g[1]]) for g in groups_true]

for v_int, v_true in zip(res_int, res_true):
    # show the min and the max for each grouping 
    print v_int[0], min(v_int[1]), 'to', max(v_int[1]), '---', min(v_true[1]), 'to', max(v_true[1])

30.0 100 to 100 --- 100 to 100
29.0 101 to 101 --- 101 to 102
28.0 102 to 103 --- 103 to 104
27.0 104 to 105 --- 105 to 106
26.0 106 to 107 --- 107 to 108
25.0 108 to 109 --- 109 to 110
24.0 110 to 111 --- 111 to 112
23.0 112 to 114 --- 113 to 115
22.0 115 to 116 --- 116 to 118
21.0 117 to 119 --- 119 to 120
20.0 120 to 122 --- 121 to 124
19.0 123 to 125 --- 125 to 127
18.0 126 to 129 --- 128 to 130
17.0 130 to 132 --- 131 to 134
16.0 133 to 136 --- 135 to 139
15.0 137 to 141 --- 140 to 143
14.0 142 to 146 --- 144 to 149
13.0 147 to 151 --- 150 to 154
12.0 152 to 158 --- 155 to 161
11.0 159 to 165 --- 162 to 169
10.0 166 to 173 --- 170 to 177
9.0 174 to 182 --- 178 to 187
8.0 183 to 193 --- 188 to 200
7.0 194 to 207 --- 201 to 214
6.0 208 to 223 --- 215 to 233
5.0 224 to 244 --- 234 to 258
4.0 245 to 273 --- 259 to 292
3.0 274 to 316 --- 293 to 346
2.0 317 to 387 --- 347 to 447
1.0 388 to 547 --- 448 to 774
0.0 548 to 39999 --- 775 to 39999
</code></pre>

<hr>

<h2>Alternative solution</h2>

<p>Here I propose another solution reversing the problem: the turning point of the rounding is when a value reaches <code>xxx.5</code>, so we can try to reverse the equation and solve</p>

<p><img src="http://latex.codecogs.com/gif.latex?x%20%3D%20%5Csqrt%7B%5Cfrac%7B300000%7D%7By%20&plus;%200.5%7D%7D" alt="formula"></p>

<p>computing <code>x</code> for each <code>y</code> integer between 0 and 30 (we know it doing a bit of domain analysis or simply peeking from the previous solution :P).</p>

<pre><code>points = [(y, (300000.0/(y + 0.5))**.5) for y in range(30,0,-1)]
# [(30, 99.17694073609294), (29, 100.84389681792216), (28, 102.59783520851542), (27, 104.44659357341871), (26, 106.3990353197863), (25, 108.46522890932809), (24, 110.65666703449763), (23, 112.98653657320641), (22, 115.47005383792515), (21, 118.12488464372366), (20, 120.97167578182678), (19, 124.03473458920845), (18, 127.34290799340266), (17, 130.93073414159542), (16, 134.8399724926484), (15, 139.12166872805048), (14, 143.83899044561525), (13, 149.07119849998597), (12, 154.91933384829667), (11, 161.51457061744966), (10, 169.03085094570332), (9, 177.7046633277277), (8, 187.86728732554485), (7, 200.0), (6, 214.83446221182987), (5, 233.5496832484569), (4, 258.19888974716116), (3, 292.7700218845599), (2, 346.41016151377545), (1, 447.21359549995793)]
</code></pre>

<p>Then for each point we can compute your result grouping all the integers between the points we just calculated:</p>

<pre><code>from math import ceil, floor
res = [(low[0], range(int(ceil(low[1])), int(floor(up[1]))+1)) for low, up in zip(points[:-1], points[1:])]
</code></pre>

python numpy