रेंज () के लिए फ़्लोट्स


140

क्या range()पायथन में तैरने के लिए एक बराबर है?

>>> range(0.5,5,1.5)
[0, 1, 2, 3, 4]
>>> range(0.5,5,0.5)

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    range(0.5,5,0.5)
ValueError: range() step argument must not be zero

1
वे अंश नहीं हैं, लेकिन तैरते हैं। और फ़्लोट्स हैं ... ठीक है, आपकी अपेक्षा से अलग परिणाम देने की संभावना है।

6
एक त्वरित समाधान पूर्णांक को दशमलव के रूप में माना जाएगा, जैसे: range(5, 50, 5)और फिर हर संख्या को 10. से विभाजित करें
NullUserException

@delnan - अपडेट किया गया। मैं फ्लोट रेंज की सुविधा के लिए मिनट की अशुद्धि स्वीकार करने को तैयार हूं
जोनाथन


@NullUserException - यह सिर्फ एक उदाहरण है - असली कोड बेशक पैरामीट्रिक है :)
जोनाथन

जवाबों:


97

मैं एक अंतर्निहित कार्य नहीं जानता, लेकिन इस तरह से लिखना बहुत जटिल नहीं होना चाहिए।

def frange(x, y, jump):
  while x < y:
    yield x
    x += jump

जैसा कि टिप्पणियों का उल्लेख है, यह अप्रत्याशित परिणाम उत्पन्न कर सकता है जैसे:

>>> list(frange(0, 100, 0.1))[-1]
99.9999999999986

अपेक्षित परिणाम प्राप्त करने के लिए, आप इस प्रश्न के अन्य उत्तरों में से किसी एक का उपयोग कर सकते हैं, या जैसा कि @TADg का उल्लेख है, आप तर्क के decimal.Decimalरूप में उपयोग कर सकते हैं jump। फ्लोट के बजाय इसे स्ट्रिंग के साथ आरंभीकृत करना सुनिश्चित करें।

>>> import decimal
>>> list(frange(0, 100, decimal.Decimal('0.1')))[-1]
Decimal('99.9')

या और भी:

import decimal

def drange(x, y, jump):
  while x < y:
    yield float(x)
    x += decimal.Decimal(jump)

और तब:

>>> list(drange(0, 100, '0.1'))[-1]
99.9

34
पायथन का आदर्श वाक्य वास्तव में एक होना चाहिए - और अधिमानतः इसे करने के लिए केवल एक - स्पष्ट तरीका । लेकिन पायथन का भयानक रास्ता :)
जोनाथन

3
>>> print list(frange(0,100,0.1))[-1]==100.0होगाFalse
वोलोडिमिर कोपे

frangeअप्रत्याशित रूप से काम कर सकते हैं। अस्थायी बिंदु अंकगणित के अभिशाप के कारण , उदाहरण के लिए frange(0.0, 1.0, 0.1)11 मान प्राप्त करता है, जहां अंतिम मूल्य है 0.9999999999999999। एक व्यावहारिक सुधार होगा, while x + sys.float_info.epsilon < y:हालांकि यह भी बड़ी संख्या के साथ विफल हो सकता है
१17:

10
-1 कृपया इस कोड का उपयोग न करें , कम से कम सॉफ्टवेयर में नहीं जो कभी भी मेरे जीवन को प्रभावित कर सकता है। इसे मज़बूती से काम करने का कोई तरीका नहीं है। अक्षेली पैलेन के उत्तर का भी उपयोग न करें। Xaerxess's या wim के उत्तर का उपयोग करें (व्यवस्था के बारे में भाग को अनदेखा करने के अलावा)।
18

3
यदि आपdecimal.Decimal फ़्लोट के बजाय चरण के रूप में उपयोग करते हैं तो यह बहुत अच्छा है।
तदह मैकडॉनल्ड्स-जेनसेन

112

आप या तो उपयोग कर सकते हैं:

[x / 10.0 for x in range(5, 50, 15)]

या लैम्ब्डा / मैप का उपयोग करें:

map(lambda x: x/10.0, range(5, 50, 15))

1
और सरणी (रेंज (5,50,15)) / 10.0 के रूप में सुपीरियर सरणियों में डिवीजन, गुणन और इतने पर से निपटने के लिए ऑपरेटर हैं
edvaldig

2
@edvaldig: आप सही हैं, मुझे इस बारे में पता नहीं था ... फिर भी मुझे लगता arange(0.5, 5, 1.5)है कि IMO अधिक पठनीय है।
Xaerxess

2
मैं इस उत्तर को स्वीकार किए गए एक से अधिक पसंद करता हूं, क्योंकि प्रस्तुत पहले दो समाधान पूर्णांकों पर पुनरावृत्ति और पूर्णांक से अंतिम फ़्लोट प्राप्त करने पर आधारित हैं। यह अधिक मजबूत है। यदि आप इसे सीधे फ़्लोट्स के साथ करते हैं, तो आपको इस बात का जोखिम है कि आंतरिक रूप से फ़्लोट्स का प्रतिनिधित्व कैसे किया जाता है। उदाहरण के लिए, यदि आप कोशिश करते हैं list(frange(0, 1, 0.5)), तो यह ठीक काम करता है और 1 को बाहर रखा गया है, लेकिन यदि आप कोशिश करते हैं list(frange(0, 1, 0.1)), तो आपको प्राप्त होने वाला अंतिम मान 1.0 के करीब है, जो शायद आप नहीं चाहते हैं। यहाँ प्रस्तुत समाधान में यह समस्या नहीं है।
ब्लबरडाइब्लूब

3
कभी भी numpy.arange का उपयोग न करें (स्वयं खस्ता दस्तावेज इसके खिलाफ अनुशंसा करता है)। इस उत्तर में wim या अन्य सुझावों में से एक के रूप में numpy.linspace का उपयोग करें।
बेन्ग

79

मैंने numpy.arangeफ़्लोटिंग पॉइंट त्रुटियों के कारण उपयोग किए जाने वाले तत्वों की संख्या को नियंत्रित करने के लिए कुछ जटिलताओं का उपयोग किया था, लेकिन उनमें कुछ जटिलताएं थीं। इसलिए अब मैं उपयोग करता हूं linspace, जैसे:

>>> import numpy
>>> numpy.linspace(0, 10, num=4)
array([  0.        ,   3.33333333,   6.66666667,  10.        ])

हालांकि, अभी भी फ्लोटिंग पॉइंट एरर हैं decimal, उदाहरण के लिए , जैसे:np.linspace(-.1,10,num=5050)[0]
TNT

2
@TNT नहीं, यह कोई त्रुटि नहीं है। आप पाएंगे कि np.linspace(-.1,10,num=5050)[0] == -.1यह सच है। यह सिर्फ इतना है कि repr(np.float64('-0.1'))अधिक अंक दिखाता है।
विम

1
हालांकि उस विशेष उदाहरण में कोई अतिरिक्त गोलाई त्रुटि नहीं दिखाई देती है, लेकिन विफलता के मामले हैं। उदाहरण के लिए, print(numpy.linspace(0, 3, 148)[49])प्रिंट 0.9999999999999999जब आदर्श परिणाम होगा 1.0linspaceकी तुलना में बहुत बेहतर काम करता है arange, लेकिन यह न्यूनतम संभव गोलाई त्रुटि का उत्पादन करने की गारंटी नहीं है।
user2357112

यह सही समापन बिंदु प्रदर्शन करने की गारंटी है, और हमेशा तत्वों की अनुरोधित संख्या का सही उत्पादन करता है।
user2357112

40

पायलैब में frange(एक आवरण, वास्तव में, के लिए matplotlib.mlab.frange):

>>> import pylab as pl
>>> pl.frange(0.5,5,0.5)
array([ 0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5,  5. ])

4
Matplotlib संस्करण 2.2 के बाद से फ्रेज को हटा दिया गया है। numpy.arange का उपयोग किया जाना चाहिए।
कुजावस

13

बेसब्री से मूल्यांकन किया गया (2.x range):

[x * .5 for x in range(10)]

आलसी का मूल्यांकन (2.x xrange, 3.x range):

itertools.imap(lambda x: x * .5, xrange(10)) # or range(10) as appropriate

वैकल्पिक रूप से:

itertools.islice(itertools.imap(lambda x: x * .5, itertools.count()), 10)
# without applying the `islice`, we get an infinite stream of half-integers.

4
+1; लेकिन (x * .5 for x in range(10))आलसी मूल्यांकन के लिए एक जनरेटर अभिव्यक्ति के रूप में क्यों नहीं ?
टिम पीटरज़ेकर

2
क्योंकि यह बहुत आसान होगा, मुझे लगता है? :)
कार्ल केनचेल

11

का उपयोग कर itertools: lazily मूल्यांकन अस्थायी बिंदु सीमा:

>>> from itertools import count, takewhile
>>> def frange(start, stop, step):
        return takewhile(lambda x: x< stop, count(start, step))

>>> list(frange(0.5, 5, 1.5))
# [0.5, 2.0, 3.5]

3
उपयोग करने के लिए +1 itertools.takewhile। हालाँकि, itertools.count(start, step)संचित फ़्लोटिंग-पॉइंट त्रुटियों से ग्रस्त है। ( takewhile(lambda x: x < 100, count(0, 0.1))उदाहरण के लिए मूल्यांकन करें ।) मैं takewhile(lambda x: x < stop, (start + i * step for i in count()))इसके बजाय लिखूंगा ।
मुस्तफिल

6

मैं समारोह जोड़ने में मदद की numeric_range पैकेज के लिए अधिक-itertools

more_itertools.numeric_range(start, stop, step) बिल्ट इन फंक्शन रेंज की तरह काम करता है, लेकिन फ़्लोट्स, डेसीमल और फ़्रेक्शन प्रकारों को संभाल सकता है।

>>> from more_itertools import numeric_range
>>> tuple(numeric_range(.1, 5, 1))
(0.1, 1.1, 2.1, 3.1, 4.1)

4

ऐसा कोई अंतर्निहित कार्य नहीं है, लेकिन आप कार्य को करने के लिए निम्नलिखित (पायथन 3 कोड) का उपयोग कर सकते हैं क्योंकि पायथन आपको अनुमति देता है।

from fractions import Fraction

def frange(start, stop, jump, end=False, via_str=False):
    """
    Equivalent of Python 3 range for decimal numbers.

    Notice that, because of arithmetic errors, it is safest to
    pass the arguments as strings, so they can be interpreted to exact fractions.

    >>> assert Fraction('1.1') - Fraction(11, 10) == 0.0
    >>> assert Fraction( 0.1 ) - Fraction(1, 10) == Fraction(1, 180143985094819840)

    Parameter `via_str` can be set to True to transform inputs in strings and then to fractions.
    When inputs are all non-periodic (in base 10), even if decimal, this method is safe as long
    as approximation happens beyond the decimal digits that Python uses for printing.


    For example, in the case of 0.1, this is the case:

    >>> assert str(0.1) == '0.1'
    >>> assert '%.50f' % 0.1 == '0.10000000000000000555111512312578270211815834045410'


    If you are not sure whether your decimal inputs all have this property, you are better off
    passing them as strings. String representations can be in integer, decimal, exponential or
    even fraction notation.

    >>> assert list(frange(1, 100.0, '0.1', end=True))[-1] == 100.0
    >>> assert list(frange(1.0, '100', '1/10', end=True))[-1] == 100.0
    >>> assert list(frange('1', '100.0', '.1', end=True))[-1] == 100.0
    >>> assert list(frange('1.0', 100, '1e-1', end=True))[-1] == 100.0
    >>> assert list(frange(1, 100.0, 0.1, end=True))[-1] != 100.0
    >>> assert list(frange(1, 100.0, 0.1, end=True, via_str=True))[-1] == 100.0

    """
    if via_str:
        start = str(start)
        stop = str(stop)
        jump = str(jump)
    start = Fraction(start)
    stop = Fraction(stop)
    jump = Fraction(jump)
    while start < stop:
        yield float(start)
        start += jump
    if end and start == stop:
        yield(float(start))

आप कुछ दावे करके सभी को सत्यापित कर सकते हैं:

assert Fraction('1.1') - Fraction(11, 10) == 0.0
assert Fraction( 0.1 ) - Fraction(1, 10) == Fraction(1, 180143985094819840)

assert str(0.1) == '0.1'
assert '%.50f' % 0.1 == '0.10000000000000000555111512312578270211815834045410'

assert list(frange(1, 100.0, '0.1', end=True))[-1] == 100.0
assert list(frange(1.0, '100', '1/10', end=True))[-1] == 100.0
assert list(frange('1', '100.0', '.1', end=True))[-1] == 100.0
assert list(frange('1.0', 100, '1e-1', end=True))[-1] == 100.0
assert list(frange(1, 100.0, 0.1, end=True))[-1] != 100.0
assert list(frange(1, 100.0, 0.1, end=True, via_str=True))[-1] == 100.0

assert list(frange(2, 3, '1/6', end=True))[-1] == 3.0
assert list(frange(0, 100, '1/3', end=True))[-1] == 100.0

GitHub पर उपलब्ध कोड


4

मानक पुस्तकालय में कोई फ्लोटिंग प्वाइंट रेंज कार्यान्वयन क्यों नहीं है?

जैसा कि यहां के सभी पदों से स्पष्ट है, इसका कोई फ्लोटिंग पॉइंट संस्करण नहीं है range()। उस ने कहा, चूक से समझ में आता है अगर हम मानते हैं कि range()फ़ंक्शन को अक्सर एक इंडेक्स के रूप में उपयोग किया जाता है (और निश्चित रूप से, इसका मतलब एक एक्सेसर ) जनरेटर है। इसलिए, जब हम फोन करते हैं, तो हम कहते range(0,40)हैं कि हम 40 मान 0 पर शुरू करना चाहते हैं, 40 तक, लेकिन गैर-समावेशी 40 ही।

जब हम मानते हैं कि सूचकांक पीढ़ी सूचकांकों की संख्या के बारे में उतना ही है जितना कि यह उनके मूल्य हैं, range()मानक पुस्तकालय में फ्लोट कार्यान्वयन का उपयोग कम समझ में आता है। उदाहरण के लिए, यदि हम फ़ंक्शन को कहते हैंfrange(0, 10, 0.25) उम्मीद करेंगे कि 0 और 10 दोनों शामिल होंगे, लेकिन यह 41 मानों के साथ एक वेक्टर प्राप्त करेगा।

इस प्रकार, frange()इसके उपयोग के आधार पर एक फ़ंक्शन हमेशा काउंटर सहज व्यवहार प्रदर्शित करेगा; यह या तो बहुत सारे मूल्यों के रूप में अनुक्रमण परिप्रेक्ष्य से माना जाता है या एक संख्या के समावेशी नहीं है जो गणितीय दृष्टिकोण से उचित रूप से वापस आ जाना चाहिए।

गणितीय उपयोग मामला

उस के साथ, जैसा कि चर्चा की गई है, numpy.linspace()पीढ़ी को गणितीय दृष्टिकोण के साथ अच्छी तरह से करता है:

numpy.linspace(0, 10, 41)
array([  0.  ,   0.25,   0.5 ,   0.75,   1.  ,   1.25,   1.5 ,   1.75,
         2.  ,   2.25,   2.5 ,   2.75,   3.  ,   3.25,   3.5 ,   3.75,
         4.  ,   4.25,   4.5 ,   4.75,   5.  ,   5.25,   5.5 ,   5.75,
         6.  ,   6.25,   6.5 ,   6.75,   7.  ,   7.25,   7.5 ,   7.75,
         8.  ,   8.25,   8.5 ,   8.75,   9.  ,   9.25,   9.5 ,   9.75,  10.
])

अनुक्रमण उपयोग प्रकरण

और अनुक्रमण परिप्रेक्ष्य के लिए, मैंने कुछ मुश्किल स्ट्रिंग जादू के साथ थोड़ा अलग दृष्टिकोण लिखा है जो हमें दशमलव स्थानों की संख्या निर्दिष्ट करने की अनुमति देता है।

# Float range function - string formatting method
def frange_S (start, stop, skip = 1.0, decimals = 2):
    for i in range(int(start / skip), int(stop / skip)):
        yield float(("%0." + str(decimals) + "f") % (i * skip))

इसी तरह, हम बिल्ट-इन roundफ़ंक्शन का भी उपयोग कर सकते हैं और दशमलव की संख्या निर्दिष्ट कर सकते हैं :

# Float range function - rounding method
def frange_R (start, stop, skip = 1.0, decimals = 2):
    for i in range(int(start / skip), int(stop / skip)):
        yield round(i * skip, ndigits = decimals)

एक त्वरित तुलना और प्रदर्शन

बेशक, उपरोक्त चर्चा को देखते हुए, इन कार्यों में काफी सीमित उपयोग का मामला है। बहरहाल, यहाँ एक त्वरित तुलना है:

def compare_methods (start, stop, skip):

    string_test  = frange_S(start, stop, skip)
    round_test   = frange_R(start, stop, skip)

    for s, r in zip(string_test, round_test):
        print(s, r)

compare_methods(-2, 10, 1/3)

परिणाम प्रत्येक के लिए समान हैं:

-2.0 -2.0
-1.67 -1.67
-1.33 -1.33
-1.0 -1.0
-0.67 -0.67
-0.33 -0.33
0.0 0.0
...
8.0 8.0
8.33 8.33
8.67 8.67
9.0 9.0
9.33 9.33
9.67 9.67

और कुछ समय:

>>> import timeit

>>> setup = """
... def frange_s (start, stop, skip = 1.0, decimals = 2):
...     for i in range(int(start / skip), int(stop / skip)):
...         yield float(("%0." + str(decimals) + "f") % (i * skip))
... def frange_r (start, stop, skip = 1.0, decimals = 2):
...     for i in range(int(start / skip), int(stop / skip)):
...         yield round(i * skip, ndigits = decimals)
... start, stop, skip = -1, 8, 1/3
... """

>>> min(timeit.Timer('string_test = frange_s(start, stop, skip); [x for x in string_test]', setup=setup).repeat(30, 1000))
0.024284090992296115

>>> min(timeit.Timer('round_test = frange_r(start, stop, skip); [x for x in round_test]', setup=setup).repeat(30, 1000))
0.025324633985292166

ऐसा लगता है जैसे मेरे सिस्टम पर बालों द्वारा स्ट्रिंग प्रारूपण विधि जीत जाती है।

सीमाएँ

और अंत में, ऊपर चर्चा से बिंदु का एक प्रदर्शन और एक आखिरी सीमा:

# "Missing" the last value (10.0)
for x in frange_R(0, 10, 0.25):
    print(x)

0.25
0.5
0.75
1.0
...
9.0
9.25
9.5
9.75

इसके अलावा, जब skipपैरामीटर stopमान से विभाज्य नहीं होता है , तो बाद के मुद्दे को देखते हुए एक जम्हाई गैप हो सकता है:

# Clearly we know that 10 - 9.43 is equal to 0.57
for x in frange_R(0, 10, 3/7):
    print(x)

0.0
0.43
0.86
1.29
...
8.14
8.57
9.0
9.43

इस मुद्दे को संबोधित करने के तरीके हैं, लेकिन दिन के अंत में, सबसे अच्छा तरीका शायद Numpy का उपयोग करना होगा।


यह काफी घुमा-फिराकर तर्क है। रेंज () को बस इट्रैशन जनरेटर पर देखा जाना चाहिए और क्या इसका उपयोग लूप के लिए किया जाता है या किसी चीज़ को इंडेक्स करने के लिए कॉलर्स पर छोड़ दिया जाना चाहिए। सहस्राब्दियों से लोग पाश के लिए झांकियों का उपयोग करते रहे हैं और औचित्य निरर्थक हैं। पायथन समितियों में लोगों ने यहां बड़ा समय खराब कर दिया और अच्छा तर्क शायद ऊपर जैसे कुछ औचित्य से डूब गया। यह इतना सादा और सरल है। अब पायथन भाषा में उपर्युक्त जैसे कई निर्णय हैं।
शीतल शाह

3

किपिक आदि पर निर्भरता के बिना एक समाधान किलिक द्वारा प्रदान किया गया था, लेकिन अस्थायी बिंदु अंकगणित के कारण , यह अक्सर अप्रत्याशित रूप से व्यवहार करता है। जैसा कि मेरे द्वारा और ब्लबरडाइब्लूब द्वारा उल्लेख किया गया है , अतिरिक्त तत्व आसानी से परिणाम में घुस जाते हैं। उदाहरण के लिए, इसके अंतिम मूल्य के रूप में naive_frange(0.0, 1.0, 0.1)उपज होगी 0.999...और इस प्रकार कुल 11 मान प्राप्त होंगे।

एक मजबूत संस्करण यहां दिया गया है:

def frange(x, y, jump=1.0):
    '''Range for floats.'''
    i = 0.0
    x = float(x)  # Prevent yielding integers.
    x0 = x
    epsilon = jump / 2.0
    yield x  # yield always first value
    while x + epsilon < y:
        i += 1.0
        x = x0 + i * jump
        yield x

क्योंकि गुणन, गोलाई की त्रुटियाँ जमा नहीं होती हैं। epsilonगुणन की संभावित गोल त्रुटि का ख्याल रखने का उपयोग , भले ही पाठ्यक्रम के मुद्दे बहुत छोटे और बहुत बड़े छोरों में बढ़ सकते हैं। अब, जैसा कि अपेक्षित था:

> a = list(frange(0.0, 1.0, 0.1))
> a[-1]
0.9
> len(a)
10

और कुछ बड़ी संख्याओं के साथ:

> b = list(frange(0.0, 1000000.0, 0.1))
> b[-1]
999999.9
> len(b)
10000000

कोड भी GitHub Gist के रूप में उपलब्ध है ।


यह frange (2.0, 17.0 / 6.0, 1.0 / 6.0) के साथ विफल हो जाता है। ऐसा कोई तरीका नहीं है जिससे इसे कभी भी मजबूत बनाया जा सके।
18

@benrg इसे इंगित करने के लिए धन्यवाद! इससे मुझे एहसास हुआ कि एप्सिलॉन को कूद पर निर्भर होना चाहिए, इसलिए मैंने एल्गोरिथ्म की समीक्षा की और मुद्दे की मरम्मत की। यह नया संस्करण अधिक मजबूत है, है ना?
अक्सेली पैलेन

2

एक सरल पुस्तकालय-कम संस्करण

ओह, हेक - मैं एक साधारण पुस्तकालय-कम संस्करण में टॉस करूँगा। इस पर सुधार करने के लिए स्वतंत्र महसूस करें [*]:

def frange(start=0, stop=1, jump=0.1):
    nsteps = int((stop-start)/jump)
    dy = stop-start
    # f(i) goes from start to stop as i goes from 0 to nsteps
    return [start + float(i)*dy/nsteps for i in range(nsteps)]

मुख्य विचार यह है कि nstepsआपको शुरू से रोकने के लिए चरणों की संख्या है और range(nsteps)हमेशा पूर्णांक का उत्सर्जन करता है ताकि सटीकता की हानि न हो। अंतिम चरण [0..nsteps] को रेखीय रूप से [start..stop] पर मैप करना है।

संपादित करें

यदि, अलंकाल्वीति की तरह आप सटीक तर्कसंगत प्रतिनिधित्व के लिए श्रृंखला चाहते हैं, तो आप हमेशा भिन्न का उपयोग कर सकते हैं :

from fractions import Fraction

def rrange(start=0, stop=1, jump=0.1):
    nsteps = int((stop-start)/jump)
    return [Fraction(i, nsteps) for i in range(nsteps)]

[*] विशेष रूप से, frange()एक सूची देता है, एक जनरेटर नहीं। लेकिन यह मेरी जरूरतों के लिए पर्याप्त है।


यदि आप स्टॉप + जंप को जोड़कर आउटपुट में स्टॉप वैल्यू को शामिल करना चाहते हैं, तो यह तरीका फिर से बीच में खराब फ्लोटिंग पॉइंट्स के साथ भोले परिणाम को frange(0,1.1,0.1)frange(0,1.05,0.1)
दर्शाता है

@alancalvitti: "ख़राब" फ्लोटिंग पॉइंट की आपकी परिभाषा क्या है? हां, परिणाम अच्छी तरह से प्रिंट नहीं हो सकते हैं, लेकिन फ्लेंज प्वाइंट प्रतिनिधित्व की सीमा के भीतर frange () समान रूप से दूरी के मूल्यों का निकटतम सेट प्रदान करता है। आप इसे कैसे सुधारेंगे?
fearless_fool

अच्छी बात है, मैं उच्च स्तर की भाषा के लिए उपयोग किया जाता हूं, जहां आप इस तरह के कार्य के लिए तर्कसंगत संख्या से अधिक होंगे, जो कि पेइ को विधानसभा जैसा लगता है।
अलंकालविटि

सभा? Hrrumph! ;) बेशक अजगर भिन्न के साथ सटीक प्रतिनिधित्व प्रदान कर सकते हैं: docs.python.org/3/library/fractions.html
fearless_fool

सही, धन्यवाद, लेकिन उदाहरण के लिए, मुझे जो भाषा पसंद है, वह स्वचालित रूप से इन प्रकारों को परिवर्तित करता है, इसलिए 1/2 एक तर्कसंगत है, जबकि 1 / 2.0 फ्लोट है, उन्हें इस तरह घोषित करने की कोई आवश्यकता नहीं है - जावा को घोषणाएं छोड़ें, जो और भी अधिक है Py से कम / असेंबली।
अलंकालविटि

2

यह numpy.arange के साथ किया जा सकता है (प्रारंभ, रोक, क़दम)

import numpy as np

np.arange(0.5,5,1.5)
>> [0.5, 2.0, 3.5, 5.0]

# OBS you will sometimes see stuff like this happening, 
# so you need to decide whether that's not an issue for you, or how you are going to catch it.
>> [0.50000001, 2.0, 3.5, 5.0]

नोट 1: यहां टिप्पणी अनुभाग में चर्चा से, "कभी भी उपयोग न करें numpy.arange()(स्वयं खतना दस्तावेज इसके खिलाफ अनुशंसा करता है)। wim द्वारा अनुशंसित के रूप में numpy.linspace का उपयोग करें, या इस उत्तर में अन्य सुझावों में से एक"

नोट 2: मैंने कुछ टिप्पणियों में चर्चा यहाँ पढ़ी है, लेकिन अब तीसरी बार इस सवाल पर वापस आने के बाद, मुझे लगता है कि इस जानकारी को अधिक पठनीय स्थिति में रखा जाना चाहिए।


2

जैसा कि किचिक ने लिखा है, यह बहुत जटिल नहीं होना चाहिए। हालाँकि यह कोड:

def frange(x, y, jump):
  while x < y:
    yield x
    x += jump

फ़्लोट्स के साथ काम करते समय त्रुटियों के संचयी प्रभाव के कारण अनुचित है। यही कारण है कि आप कुछ इस तरह प्राप्त करते हैं:

>>>list(frange(0, 100, 0.1))[-1]
99.9999999999986

जबकि अपेक्षित व्यवहार होगा:

>>>list(frange(0, 100, 0.1))[-1]
99.9

समाधान 1

अनुक्रमणिका चर का उपयोग करके संचयी त्रुटि को कम किया जा सकता है। यहाँ उदाहरण है:

from math import ceil

    def frange2(start, stop, step):
        n_items = int(ceil((stop - start) / step))
        return (start + i*step for i in range(n_items))

यह उदाहरण उम्मीद के मुताबिक काम करता है।

समाधान २

कोई नेस्टेड कार्य नहीं। केवल थोड़ी देर और एक काउंटर चर:

def frange3(start, stop, step):
    res, n = start, 1

    while res < stop:
        yield res
        res = start + n * step
        n += 1

जब आप उलटी सीमा चाहते हैं, तो उन मामलों को छोड़कर, यह फ़ंक्शन भी अच्छी तरह से काम करेगा। उदाहरण के लिए:

>>>list(frange3(1, 0, -.1))
[]

इस मामले में समाधान 1 उम्मीद के मुताबिक काम करेगा। ऐसी स्थितियों में इस कार्य को करने के लिए, आपको निम्नलिखित के समान एक हैक लागू करना होगा:

from operator import gt, lt

def frange3(start, stop, step):
    res, n = start, 0.
    predicate = lt if start < stop else gt
    while predicate(res, stop):
        yield res
        res = start + n * step
        n += 1

इस हैक के साथ आप नकारात्मक चरणों के साथ इन कार्यों का उपयोग कर सकते हैं:

>>>list(frange3(1, 0, -.1))
[1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.3999999999999999, 0.29999999999999993, 0.19999999999999996, 0.09999999999999998]

समाधान 3

आप सादे मानक पुस्तकालय के साथ और भी आगे जा सकते हैं और अधिकांश संख्यात्मक प्रकारों के लिए रेंज फ़ंक्शन की रचना कर सकते हैं:

from itertools import count
from itertools import takewhile

def any_range(start, stop, step):
    start = type(start + step)(start)
    return takewhile(lambda n: n < stop, count(start, step))

यह जनरेटर फ्लुएंट पायथन पुस्तक (अध्याय 14. Iterables, Iterators और जनरेटर) से अनुकूलित है। यह घटती श्रेणियों के साथ काम नहीं करेगा। आपको पिछले समाधान की तरह, एक हैक लागू करना होगा।

आप इस जनरेटर का उपयोग इस प्रकार कर सकते हैं, उदाहरण के लिए:

>>>list(any_range(Fraction(2, 1), Fraction(100, 1), Fraction(1, 3)))[-1]
299/3
>>>list(any_range(Decimal('2.'), Decimal('4.'), Decimal('.3')))
[Decimal('2'), Decimal('2.3'), Decimal('2.6'), Decimal('2.9'), Decimal('3.2'), Decimal('3.5'), Decimal('3.8')]

और निश्चित रूप से आप इसे फ्लोट और इंट के साथ भी उपयोग कर सकते हैं ।

सावधान रहे

यदि आप नकारात्मक चरणों के साथ इन कार्यों का उपयोग करना चाहते हैं, तो आपको चरण चिह्न के लिए एक चेक जोड़ना चाहिए, जैसे:

no_proceed = (start < stop and step < 0) or (start > stop and step > 0)
if no_proceed: raise StopIteration

यहां सबसे अच्छा विकल्प उठाना है StopIteration, अगर आप rangeफ़ंक्शन की नकल करना चाहते हैं ।

मिमिक रेंज

यदि आप rangeफ़ंक्शन इंटरफ़ेस की नकल करना चाहते हैं , तो आप कुछ तर्क जांच प्रदान कर सकते हैं:

def any_range2(*args):
    if len(args) == 1:
        start, stop, step = 0, args[0], 1.
    elif len(args) == 2:
        start, stop, step = args[0], args[1], 1.
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise TypeError('any_range2() requires 1-3 numeric arguments')

    # here you can check for isinstance numbers.Real or use more specific ABC or whatever ...

    start = type(start + step)(start)
    return takewhile(lambda n: n < stop, count(start, step))

मुझे लगता है, आपको वह बात मिल गई है। आप इन कार्यों (बहुत पहले एक को छोड़कर) से किसी के साथ जा सकते हैं और सब आप उनके लिए जरूरत अजगर मानक पुस्तकालय है।


1

मैंने एक फ़ंक्शन लिखा है जो सौवें से परे किसी भी दशमलव स्थानों के बिना डबल परिशुद्धता फ़्लोटिंग पॉइंट संख्याओं की एक सीमा को देता है। यह केवल स्ट्रिंग्स जैसे अतिरिक्त मूल्यों को पार्स करने और अतिरिक्त से अलग होने का मामला था। मैं UI के भीतर से चयन करने के लिए पर्वतमाला प्रदर्शित करने के लिए इसका उपयोग करता हूं। मुझे आशा है कि किसी और को यह उपयोगी लगता है।

def drange(start,stop,step):
    double_value_range = []
    while start<stop:
        a = str(start)
        a.split('.')[1].split('0')[0]
        start = float(str(a))
        double_value_range.append(start)
        start = start+step
    double_value_range_tuple = tuple(double_value_range)
   #print double_value_range_tuple
    return double_value_range_tuple

1

प्रयोग

# Counting up
drange(0, 0.4, 0.1)
[0, 0.1, 0.2, 0.30000000000000004, 0.4]

# Counting down
drange(0, -0.4, -0.1)
[0, -0.1, -0.2, -0.30000000000000004, -0.4]

एन दशमलव स्थानों के लिए प्रत्येक चरण को गोल करने के लिए

drange(0, 0.4, 0.1, round_decimal_places=4)
[0, 0.1, 0.2, 0.3, 0.4]

drange(0, -0.4, -0.1, round_decimal_places=4)
[0, -0.1, -0.2, -0.3, -0.4]

कोड

def drange(start, end, increment, round_decimal_places=None):
    result = []
    if start < end:
        # Counting up, e.g. 0 to 0.4 in 0.1 increments.
        if increment < 0:
            raise Exception("Error: When counting up, increment must be positive.")
        while start <= end:
            result.append(start)
            start += increment
            if round_decimal_places is not None:
                start = round(start, round_decimal_places)
    else:
        # Counting down, e.g. 0 to -0.4 in -0.1 increments.
        if increment > 0:
            raise Exception("Error: When counting down, increment must be negative.")
        while start >= end:
            result.append(start)
            start += increment
            if round_decimal_places is not None:
                start = round(start, round_decimal_places)
    return result

यह उत्तर क्यों चुनें?

  • गिनती करने के लिए कहने पर कई अन्य जवाब लटक जाएंगे।
  • कई अन्य उत्तर गलत तरीके से गोल परिणाम देंगे।
  • np.linspaceहिट-एंड-मिस पर आधारित अन्य उत्तर , विभाजन की सही संख्या चुनने में कठिनाई के कारण काम कर सकते हैं या नहीं भी।np.linspaceवास्तव में 0.1 की दशमलव वृद्धि के साथ संघर्ष करता है, और सूत्र में विभाजन को कई विभाजन में बदलने का क्रम सही या टूटा हुआ कोड हो सकता है।
  • के आधार पर अन्य उत्तर np.arangeहटाए गए हैं।

यदि संदेह है, तो ऊपर दिए गए चार परीक्षण मामलों का प्रयास करें।


0
def Range(*argSequence):
    if len(argSequence) == 3:
        imin = argSequence[0]; imax = argSequence[1]; di = argSequence[2]
        i = imin; iList = []
        while i <= imax:
            iList.append(i)
            i += di
        return iList
    if len(argSequence) == 2:
        return Range(argSequence[0], argSequence[1], 1)
    if len(argSequence) == 1:
        return Range(1, argSequence[0], 1)

कृपया ध्यान दें कि रेंज का पहला अक्षर कैपिटल है। पायथन में कार्यों के लिए इस नामकरण पद्धति को प्रोत्साहित नहीं किया गया है। यदि आप चाहें तो आप रेंज को किसी अजीब या अजीब तरह से बदल सकते हैं। "रेंज" फ़ंक्शन ठीक उसी तरह व्यवहार करता है जैसे आप इसे चाहते हैं। आप इसे यहाँ मैनुअल देख सकते हैं [ http://reference.wolfram.com/language/ref/Range.html ]।


0

मुझे लगता है कि एक बहुत ही सरल उत्तर है जो वास्तव में रेंज की सभी विशेषताओं का अनुकरण करता है लेकिन फ्लोट और पूर्णांक दोनों के लिए। इस समाधान में, आपको लगता है कि आपका सन्निकटन डिफ़ॉल्ट रूप से 1e-7 (या आप जिसे चुनते हैं) है और जब आप फ़ंक्शन को कॉल करते हैं तो आप इसे बदल सकते हैं।

def drange(start,stop=None,jump=1,approx=7): # Approx to 1e-7 by default
  '''
  This function is equivalent to range but for both float and integer
  '''
  if not stop: # If there is no y value: range(x)
      stop= start
      start= 0
  valor= round(start,approx)
  while valor < stop:
      if valor==int(valor):
          yield int(round(valor,approx))
      else:
          yield float(round(valor,approx))
      valor += jump
  for i in drange(12):
      print(i)

0

निश्चित रूप से कुछ राउंडिंग त्रुटियां होंगी, इसलिए यह सही नहीं है, लेकिन यह वही है जो मैं आमतौर पर अनुप्रयोगों के लिए उपयोग करता हूं, जिन्हें उच्च परिशुद्धता की आवश्यकता नहीं होती है। यदि आप इसे अधिक सटीक बनाना चाहते हैं, तो आप यह निर्दिष्ट करने के लिए एक अतिरिक्त तर्क जोड़ सकते हैं कि गोलाई की त्रुटियों को कैसे प्रबंधित किया जाए। शायद एक राउंडिंग फ़ंक्शन पास करने से यह एक्स्टेंसिबल हो सकता है और प्रोग्रामर को यह निर्दिष्ट करने की अनुमति दे सकता है कि राउंडिंग त्रुटियों को कैसे संभालना है।

arange = lambda start, stop, step: [i + step * i for i in range(int((stop - start) / step))]

अगर मैं लिखूं:

arange(0, 1, 0.1)

यह उत्पादन होगा:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

-1

क्या पायथन में तैरने के लिए एक सीमा () बराबर है? इसका उपयोग न करें:

def f_range(start, end, step):
    a = range(int(start/0.01), int(end/0.01), int(step/0.01))
    var = []
    for item in a:
        var.append(item*0.01)
    return var

3
बहुत बुरा समाधान, प्रयास करें f_range(0.01,0.02,0.001)... अधिकांश व्यावहारिक उद्देश्यों के लिए, arangeNumpy एक सरल, सुरक्षित और तेज़ समाधान है।
बार्ट

तुम सही हो। सुन्न के साथ मेरे कोड की तुलना में 1.8 तेज है।
ग्रिगोर कोलेव

तुम सही हो। सुन्न के साथ मेरे कोड की तुलना में 1.8 तेज है। लेकिन जिस सिस्टम में मैं काम करता हूं वह पूरी तरह से बंद है। केवल पायथन और pyserial और नहीं।
ग्रिगोर कोलेव

-2

यहाँ कई उत्तर हैं जो सरल किनारे के मामलों जैसे कि नकारात्मक कदम, गलत शुरुआत, रोक आदि को नहीं संभालते हैं। यहाँ वह संस्करण है जो इनमें से कई मामलों को सही ढंग से संभालता है जो मूल रूप से समान व्यवहार देते हैं range():

def frange(start, stop=None, step=1):
  if stop is None:
    start, stop = 0, start
  steps = int((stop-start)/step)
  for i in range(steps):
    yield start
    start += step  

ध्यान दें कि यह मूल के समान ही चरण = 0 में त्रुटि करेगा range। एक अंतर यह है कि देशी रेंज रिटर्न ऑब्जेक्ट है जो इंडेक्सेबल और रिवर्सिबल है जबकि ऊपर नहीं है।

आप इस कोड के साथ खेल सकते हैं और यहां मामलों का परीक्षण कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.