Generalized range

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • tkpmep@hotmail.com

    #1

    Generalized range

    I need to create ranges that can start and end with real numbers.
    Searching this newsgroup brought me to a function that I then modified
    as follows:

    def myRange(iMin, iMax=None, iStep=1):
    """Extends range to real numbers. Wherever possible, use Python's
    range .
    In other cases, make the behavior follow the spirit of Python's
    range """
    epsilon = 1.e-8

    if iMax == None and iStep == 1:
    return range(int(iMin) )

    elif type(iMin).__na me__.lower() in ('int', 'long') and \
    type(iMax).__na me__.lower() in ('int', 'long') and \
    type(iStep).__n ame__.lower() in ('int', 'long') and iStep !=
    0:
    return range( iMin, iMax, iStep)

    elif iMin <= iMax and iStep 0:
    return [ iMin+i*iStep for i in range( int(math.ceil(( iMax -
    iMin - epsilon)/iStep)) )]

    elif iMin >= iMax and iStep < 0:
    return [ iMin+i*iStep for i in range(-int(math.ceil(( iMin -
    iMax + epsilon)/iStep)) )]

    else:
    raise ValueError, 'Cannot construct a range with steps of size
    ' + str(iStep) + ' between ' + str(iMin) + ' and ' + str(iMax)


    The one part of my implementation that has me a bit queasy (i.e.
    works in my current application, but I can see it misbehaving
    elsewhere) is the addition/subtraction of a fixed epsilon to ensure
    that my rounding goes the right way. A clean implementation would
    modify epsilon based on the achievable level of precision given the
    particular values of iMax, iMin and iStep. I suspect this requires a
    detailed understanding of the implementation of floating point
    arithmetic, and would appreciate hearing any thoughts you might have
    on gilding this lily.

    Sincerely

    Thomas Philips

  • Stargaming

    #2
    Re: Generalized range

    tkpmep@hotmail. com schrieb:
    I need to create ranges that can start and end with real numbers.
    Searching this newsgroup brought me to a function that I then modified
    as follows:
    >
    def myRange(iMin, iMax=None, iStep=1):
    Just as a sidenote: it is not common to prefix your names with its type.
    It could change at any time and min, max, step would be clear, too. IMO.
    """Extends range to real numbers. Wherever possible, use Python's
    range .
    In other cases, make the behavior follow the spirit of Python's
    range """
    If you want to stick to the "normal" range-implementation, myRange
    should consider an one-argument-call as transmission of iMax.
    epsilon = 1.e-8
    I can't really say if your attempt using an epsilon-environment is good.
    I think just increasing a "counter" from iMin to iMax should be fine,
    achieving more precision by making computations fuzzy -- i don't know,
    perhaps it's very good. I wouldn't do it.
    If you like to care about precision, you should have a look at the
    `decimal module <http://docs.python.org/lib/module-decimal.html>`_ .
    >
    if iMax == None and iStep == 1:
    return range(int(iMin) )
    >
    elif type(iMin).__na me__.lower() in ('int', 'long') and \
    type(iMax).__na me__.lower() in ('int', 'long') and \
    type(iStep).__n ame__.lower() in ('int', 'long') and iStep !=
    0:
    return range( iMin, iMax, iStep)
    Ouchie! *That* is a bad one. Checking for a name of an object is neither
    safe nor good nor common. A better way would be directly comparing
    type(yourobject ) with int/long/float/anytype. See
    http://docs.python.org/lib/comparisons.html for details on comparisons.
    Another way of type-checking in python is doing something like ``if
    isinstance(iMin , (int, long))``. Would work for subclasses, too.
    >
    elif iMin <= iMax and iStep 0:
    return [ iMin+i*iStep for i in range( int(math.ceil(( iMax -
    iMin - epsilon)/iStep)) )]
    >
    elif iMin >= iMax and iStep < 0:
    return [ iMin+i*iStep for i in range(-int(math.ceil(( iMin -
    iMax + epsilon)/iStep)) )]
    >
    Will eat your memory. See below.
    else:
    raise ValueError, 'Cannot construct a range with steps of size
    ' + str(iStep) + ' between ' + str(iMin) + ' and ' + str(iMax)
    In Python, it is common to use string interpolation instead. Like::
    print 'Hello from %d to %d' % (iMin, iMax)
    Read `String Formatting Operations
    <http://docs.python.org/lib/typesseq-strings.html>`_ in the manual for
    details.
    >
    >
    The one part of my implementation that has me a bit queasy (i.e.
    works in my current application, but I can see it misbehaving
    elsewhere) is the addition/subtraction of a fixed epsilon to ensure
    that my rounding goes the right way. A clean implementation would
    modify epsilon based on the achievable level of precision given the
    particular values of iMax, iMin and iStep. I suspect this requires a
    detailed understanding of the implementation of floating point
    arithmetic,
    I think so, too. That's why it is a bad idea, IMO.
    and would appreciate hearing any thoughts you might have
    on gilding this lily.
    >
    Sincerely
    >
    Thomas Philips
    >
    I'd recommend you to have a look into `generators
    <http://docs.python.org/ref/yield.html>`_, it is what `xrange
    <http://docs.python.org/lib/built-in-funcs.html#l2h-80>`_ uses. You
    don't put all numbers into your memory ("precompute them") but behave a
    little bit lazy and compute them whenever the user needs the next one. I
    expect Google to have lots of example implementations of range as a
    generator in python for you. :-)

    HTH,
    Stargaming

    Comment

    • Michael Hoffman

      #3
      Re: Generalized range

      tkpmep@hotmail. com wrote:
      I need to create ranges that can start and end with real numbers.
      Searching this newsgroup brought me to a function that I then modified
      as follows:
      >
      def myRange(iMin, iMax=None, iStep=1):
      """Extends range to real numbers. Wherever possible, use Python's
      range .
      In other cases, make the behavior follow the spirit of Python's
      range """
      epsilon = 1.e-8
      >
      if iMax == None and iStep == 1:
      return range(int(iMin) )
      >
      elif type(iMin).__na me__.lower() in ('int', 'long') and \
      type(iMax).__na me__.lower() in ('int', 'long') and \
      type(iStep).__n ame__.lower() in ('int', 'long') and iStep !=
      0:
      return range( iMin, iMax, iStep)
      >
      elif iMin <= iMax and iStep 0:
      return [ iMin+i*iStep for i in range( int(math.ceil(( iMax -
      iMin - epsilon)/iStep)) )]
      >
      elif iMin >= iMax and iStep < 0:
      return [ iMin+i*iStep for i in range(-int(math.ceil(( iMin -
      iMax + epsilon)/iStep)) )]
      >
      else:
      raise ValueError, 'Cannot construct a range with steps of size
      ' + str(iStep) + ' between ' + str(iMin) + ' and ' + str(iMax)
      >
      >
      The one part of my implementation that has me a bit queasy (i.e.
      works in my current application, but I can see it misbehaving
      elsewhere) is the addition/subtraction of a fixed epsilon to ensure
      that my rounding goes the right way. A clean implementation would
      modify epsilon based on the achievable level of precision given the
      particular values of iMax, iMin and iStep. I suspect this requires a
      detailed understanding of the implementation of floating point
      arithmetic, and would appreciate hearing any thoughts you might have
      on gilding this lily.
      In addition to the comments of Stargaming, most of which I agree with, I
      think you would be far better dropping the epsilon business and doing
      something like:

      # requires that minimum <= maximum; swap values if necessary
      res = minimum
      while res < maximum:
      yield res
      res += step
      --
      Michael Hoffman

      Comment

      • tkpmep@hotmail.com

        #4
        Re: Generalized range

        Thanks - you have covered a fair bit of gorund here - I will modify
        myRange taking your suggestions into account. The one suggestion that
        I'm going to have to think through is repeatedly incrementing res.

        I deliberately did not use this as repeated addition can cause
        rounding errors to accumulate, making the loop run a little longer or
        shorter than necessary. I thought I would be far less likely to run
        into rounding issues with a multiplicative construct - hence my use of
        epsilon, and my question about an appropriate value for it

        Comment

        • Michael Hoffman

          #5
          Re: Generalized range

          tkpmep@hotmail. com wrote:
          Thanks - you have covered a fair bit of gorund here - I will modify
          myRange taking your suggestions into account. The one suggestion that
          I'm going to have to think through is repeatedly incrementing res.
          >
          I deliberately did not use this as repeated addition can cause
          rounding errors to accumulate, making the loop run a little longer or
          shorter than necessary. I thought I would be far less likely to run
          into rounding issues with a multiplicative construct - hence my use of
          epsilon, and my question about an appropriate value for it
          You are right about rounding issues--with a sufficiently small step, the
          way I have done it, it could become an infinite loop. But you can still
          do it with multiplication, without using an epsilon constant. How about
          something like this:

          index = 0
          while res < maximum:
          yield minimum + (step * index)
          index += 1
          --
          Michael Hoffman

          Comment

          • Michael Hoffman

            #6
            Re: Generalized range

            Michael Hoffman wrote:
            How about something like this:
            >
            index = 0
            while res < maximum:
            yield minimum + (step * index)
            index += 1
            Well it really would have to be something LIKE that since I never
            defined res. Let's try that again:

            index = 0
            res = minimum
            while res < maximum:
            yield res
            res = minimum + (step * index)
            index += 1
            --
            Michael Hoffman

            Comment

            • Alex Martelli

              #7
              Re: Generalized range

              Michael Hoffman <cam.ac.uk@mh39 1.invalidwrote:
              tkpmep@hotmail. com wrote:
              Thanks - you have covered a fair bit of gorund here - I will modify
              myRange taking your suggestions into account. The one suggestion that
              I'm going to have to think through is repeatedly incrementing res.

              I deliberately did not use this as repeated addition can cause
              rounding errors to accumulate, making the loop run a little longer or
              shorter than necessary. I thought I would be far less likely to run
              into rounding issues with a multiplicative construct - hence my use of
              epsilon, and my question about an appropriate value for it
              >
              You are right about rounding issues--with a sufficiently small step, the
              way I have done it, it could become an infinite loop. But you can still
              do it with multiplication, without using an epsilon constant. How about
              something like this:
              >
              index = 0
              while res < maximum:
              yield minimum + (step * index)
              index += 1
              Absolutely (with your later correction of actually assigning res), MUCH
              better than the misguided attempts based on repeatedly adding 'step'.

              I've taught "numerical computing" in university, and I would have had to
              fail anybody who'd misunderstood floating-point computations badly
              enough to try that "+=step" idea (including, sigh, the coders of several
              Fortran compilers who were popular at that time).

              These days, I _heartily_ recommend "Real Computing Made Real" by Foreman
              Acton -- the best programming book without one line of code in any
              language (it's all formulas and graphs). Anybody who has trouble
              following it must understand they should NOT use floating point numbers
              until they've gotten the prereqs (which aren't all that deep:
              engineering-undergrad-level algebra and calculus, plus
              <http://docs.sun.com/source/806-3568/ncg_goldberg.ht mland a couple
              weeks' worth of refresher courses on fundamental algorithms such as
              Newton's root-finding approach and the like -- I shudder to think how
              many people with CS bachelor degrees and even post-grad degrees are just
              never taught these fundamentals, yet end up having to program _some_
              floating point computations, mistakenly thinking they can...).


              Alex

              Comment

              • Beliavsky

                #8
                Re: Generalized range

                On Apr 27, 1:32 am, a...@mac.com (Alex Martelli) wrote:
                Michael Hoffman <cam.ac...@mh39 1.invalidwrote:
                tkp...@hotmail. com wrote:
                Thanks - you have covered a fair bit of gorund here - I will modify
                myRange taking your suggestions into account. The one suggestion that
                I'm going to have to think through is repeatedly incrementing res.
                >
                I deliberately did not use this as repeated addition can cause
                rounding errors to accumulate, making the loop run a little longer or
                shorter than necessary. I thought I would be far less likely to run
                into rounding issues with a multiplicative construct - hence my use of
                epsilon, and my question about an appropriate value for it
                >
                You are right about rounding issues--with a sufficiently small step, the
                way I have done it, it could become an infinite loop. But you can still
                do it with multiplication, without using an epsilon constant. How about
                something like this:
                >
                index = 0
                while res < maximum:
                yield minimum + (step * index)
                index += 1
                >
                Absolutely (with your later correction of actually assigning res), MUCH
                better than the misguided attempts based on repeatedly adding 'step'.
                >
                I've taught "numerical computing" in university, and I would have had to
                fail anybody who'd misunderstood floating-point computations badly
                enough to try that "+=step" idea (including, sigh, the coders of several Fortran compilers who were popular at that time).
                You may be referring to the Fortran DO loop with a REAL loop variable,
                for example

                do x=1.5,3.5,0.5
                print*,x
                end do

                This was part of standard Fortran 77, so one should blame the
                standards committee, not the compiler writers. Very few features of
                F77 were deleted in Fortran 95, but this was one of them. In practice,
                nothing gets deleted from commercial Fortran compilers.

                At the SciPy site http://www.scipy.org/Cookbook/OptimizationAndFitDemo1
                there is some code

                1 from enthought.chaco .wx import plt
                2 from scipy import arange, optimize, special
                3
                4 plt.figure()
                5 plt.hold()
                6 w = []
                7 z = []
                8 x = arange(0,10,.01 )
                9
                10 for k in arange(1,5,.5):
                11 y = special.jv(k,x)
                12 plt.plot(x,y)
                13 f = lambda x: -special.jv(k,x)
                14 x_max = optimize.fminbo und(f,0,6)
                15 w.append(x_max)
                16 z.append(specia l.jv(k,x_max))
                17
                18 plt.plot(w,z, 'ro')
                19 from scipy import interpolate
                20 t = interpolate.spl rep(w, z, k=3)
                21 s_fit3 = interpolate.spl ev(x,t)
                22 plt.plot(x,s_fi t3, 'g-')
                23 t5 = interpolate.spl rep(w, z, k=5)
                24 s_fit5 = interpolate.spl ev(x,t5)
                25 plt.plot(x,s_fi t5, 'y-')

                I think the use of arange with a non-integer increment is poor style,
                for reasons discussed in this thread.

                Comment

                • Alex Martelli

                  #9
                  Re: Generalized range

                  Beliavsky <beliavsky@aol. comwrote:
                  ...
                  I've taught "numerical computing" in university, and I would have had to
                  fail anybody who'd misunderstood floating-point computations badly
                  enough to try that "+=step" idea (including, sigh, the coders of several
                  Fortran compilers who were popular at that time).
                  >
                  You may be referring to the Fortran DO loop with a REAL loop variable,
                  for example
                  >
                  do x=1.5,3.5,0.5
                  print*,x
                  end do
                  >
                  This was part of standard Fortran 77, so one should blame the
                  standards committee, not the compiler writers. Very few features of
                  I was thinking of "Fortran IV" aka Fortran '66, where as I recall per
                  the standard you were _supposed_ to only use integers in a DO, but
                  several compilers supplied real loop variables as an extension, and got
                  its implementation wrong.


                  Alex

                  Comment

                  Working...