3

I have the radius of a circle and the equation y = int(math.sqrt(pow(radius, 2)-pow(i,2))) (Pythagoras). I want to iterate over a specific range with a custom step size, which is a multiple of 16. Here's an example to illustrate my desired output:

radius = 4
# Desired output: -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4
# Actually output: -4, -3, -2, 1, 1, 2, 3, 4

I found a workaround using list comprehensions. By dividing the values by 2, I was able to achieve the desired step size. Here's the code that works for radius = 4:

from itertools import chain

radius = 4
result = [x/2 for x in chain(range(-2*radius, 0), range(1, 2*radius+1))]
print("Length: ", len(result))
print("Values: ", result)

The output is as expected with a length of 16. However, this approach is not generalizable, and it fails for other values of radius, such as radius = 5. I'm looking for a solution allowing me to loop through a range in a specific number of steps. How can I achieve this?

Gykonik
  • 638
  • 1
  • 7
  • 24
  • Possible duplicate of [Python decimal range() step value](http://stackoverflow.com/questions/477486/python-decimal-range-step-value) – Prune Feb 08 '17 at 22:35
  • You can use Numpy, and there is a function that creates lists like what you're trying to do. `numpy.linspace(-radius, radius, radius * radius)` – kbunarjo Feb 08 '17 at 22:35
  • The equation of a circle should be `sqrt(radius * radius - x * x)` (square-root instead of `int`), assuming iteration variable is `x`. This will give the upper part of the circle. – Sci Prog Feb 08 '17 at 22:40
  • ... the numpy solution is included in the duplicate question. – Prune Feb 08 '17 at 22:40
  • @SciProg yeah, thanks – Gykonik Feb 08 '17 at 22:48

4 Answers4

2

Solution 1.1:

You can use the linspace-function and then pick those values which are not 0. This is done by the my_range-function in the following code:

import numpy as np

def my_range(radius, steps):
    ran = np.linspace(-radius, radius, steps+1)
    return ran[np.nonzero(ran)]

Now,

[i for i in my_range(4, 16)]

produces

[-4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]

Solution 1.2:

Alternatively,

list(my_range(4, 16))

produces the same list.


Solution 2:

If you don't want to define a function, here is a concise way to achieve the same thing:

[i for i in np.linspace(-4, 4, 16+1) if i != 0]
yogabonito
  • 657
  • 5
  • 14
  • Thanks! This one worked but please note, that the solution from another use (sadly he deleted his post again...) is a bit faster: `range_steps = (num * 2) / float(steps) #calculate the increment value to get you your step count (LINEBREAK) return list(np.arange(num * -1, num , range_steps))` – Gykonik Feb 08 '17 at 23:12
  • @Niklas the code in your comment produces a list which contains the 0 in the middle of it. And it does not include the last value of the list in my example. So the code in your comment produces something different than what you defined as the desired result. – yogabonito Feb 08 '17 at 23:22
  • yeah, I saw that in the same moment... I mean the problem with the 0 is easy to fix, because you can delete it afterwards and the algorithm would still be faster, but the problem with the last value isn't that easy to fix I think – Gykonik Feb 08 '17 at 23:29
  • You are right about the 0. But I really recommend to use `linspace` instead of `arange` when dealing with steps of type float. Try out `np.arange(0, 1.1, 0.1)` and `np.arange(0.5, 1.1, 0.1)`, compare their last values and ... surprise! They are different! (This example is adapted from [this page](http://quantumwise.com/forum/index.php?topic=110.0).) – yogabonito Feb 08 '17 at 23:57
  • Yeah, you're right! But take a look at @f5r5e5d's solution! This one needs nothing and works the same I think, doesn't it? (if you round the result its nearly the same) – Gykonik Feb 09 '17 at 00:02
  • Well, both contain 0. In his first solution you have to consider to use `n=17` instead of `n=16`. And his second solution didn't produce the last value in the list when I tried it out. So with a little tweaking you could also use @f5r5e5d's version. I would choose the one I find more readable :) – yogabonito Feb 09 '17 at 00:14
  • for me @f5r5e5d's solution produces the last value and don't contain 0 but I think, that I choose ur solution! :D – Gykonik Feb 09 '17 at 12:18
0

Hope you like this solution, __future__ import is for python 2.x:

from __future__ import division
r = 4
result = [-a/2 for a in xrange(1, r*2+1)][::-1] + [a/2 for a in xrange(1, r*2+1)]
print result
zipa
  • 27,316
  • 6
  • 40
  • 58
  • Thanks! This solution works, but please keep in mind, that this is really slow in comparision to @yogabonito's method! :) – Gykonik Feb 08 '17 at 23:08
  • 2
    By really slow I mean: For 9999 calculations yours need 17 secs and yogabonito's need 0,05 :D – Gykonik Feb 08 '17 at 23:09
0

it looks like you want +/- limits equal magnitude

you then have the choice of include the endpoint in the range, and if that then makes you want to get n + 1 points

pure python, no imports:

lim, n = 3, 10

[-lim + i * 2 * lim / (n - 1) for i in range(n)]
Out[27]: 
[-3.0,
 -2.3333333333333335,
 -1.6666666666666667,
 -1.0,
 -0.3333333333333335,
 0.3333333333333335,
 1.0,
 1.666666666666667,
 2.333333333333333,
 3.0]

or

[-lim + i * 2 * lim / n for i in range( n + 1)]
Out[28]: 
[-3.0,
 -2.4,
 -1.8,
 -1.2,
 -0.6000000000000001,
 0.0,
 0.6000000000000001,
 1.2000000000000002,
 1.7999999999999998,
 2.4000000000000004,
 3.0]

changing the list comprehension sq brackets to round makes a generator that could be used in place of range()

f5r5e5d
  • 3,656
  • 3
  • 14
  • 18
-1

range function takes three parameters start , stop and step (third argument is optional) . range(-4,4,0.5) will solve your problem. so let's assume -x is start and x is stop.

step =  int(x/16);
range(-x, x, step);
Nirmal Dey
  • 191
  • 5