ভাসমানগুলির জন্য পরিসর ()


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)
কাজটি হ'ল

@ ডেলান - আপডেট হয়েছে। আমি ভাসা পরিসীমা থাকার সুবিধার্থে মিনিটের ভুলত্রুটিগুলি গ্রহণ করতে রাজি আছি
জোনাথন


@ নুল ইউজার এক্সসেপশন - এটি কেবল একটি উদাহরণ - আসল কোড অবশ্যই প্যারামিমেট্রিক :)
জোনাথন

উত্তর:


97

আমি একটি বিল্ট-ইন ফাংশন জানি না, কিন্তু মত এক লিখে এই খুব জটিল করা উচিত নয়।

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

মন্তব্যে যেমন উল্লেখ করা হয়েছে, এটি অনাকাঙ্ক্ষিত ফলাফল যেমন:

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

প্রত্যাশিত ফলাফল পেতে, আপনি এই প্রশ্নের অন্য উত্তরগুলির মধ্যে একটি ব্যবহার করতে পারেন, বা @ তাডগ উল্লেখ করেছেন, আপনি যুক্তি 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.9999999999999999while x + sys.float_info.epsilon < y:যদিও এটি সম্ভবত বিপুল সংখ্যায় ব্যর্থ হতে পারে তবে ব্যবহারিক উন্নতি হবে ।
আকসেলি পালান

10
-1 দয়া করে এই কোডটি ব্যবহার করবেন না , অন্তত এমন কোনও সফ্টওয়্যার নয় যা আমার জীবনে কখনও প্রভাব ফেলতে পারে। এটি নির্ভরযোগ্যভাবে কাজ করার কোনও উপায় নেই। আকসেলি পালনের উত্তরও ব্যবহার করবেন না। Xaerxess এর বা উইম এর উত্তর ব্যবহার করুন (অ্যারেঞ্জ সম্পর্কে অংশ উপেক্ষা ছাড়া)।
23:58

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 হিসাবে নম্পি অ্যারে বিভাগ পরিচালনা, গুণ এবং আরও পরিচালনা করার জন্য অপারেটর রয়েছে
এডভালডিগ

2
@ অ্যাডভালডিগ: আপনি ঠিক বলেছেন, আমি এ সম্পর্কে জানতাম না ... তবুও আমি মনে করি arange(0.5, 5, 1.5)আইএমও আরও পাঠযোগ্য।
Xaerxess

2
আমি এই উত্তরটি গ্রহণীকৃতটির চেয়ে বেশি পছন্দ করি, কারণ উপস্থাপিত প্রথম দুটি সমাধান পূর্ণসংখ্যার উপরে পুনরাবৃত্তি এবং পূর্ণসংখ্যার শেষ চূড়ান্ত প্রাপ্তির উপর ভিত্তি করে। এটি আরও মজবুত। যদি আপনি এটি সরাসরি ফ্লোট দিয়ে করেন তবে অভ্যন্তরীণভাবে ফ্লোটগুলি কীভাবে প্রতিনিধিত্ব করা হয় তার কারণে আপনার অদ্ভুত এক-অফ ত্রুটি হওয়ার ঝুঁকি রয়েছে। উদাহরণস্বরূপ, যদি আপনি চেষ্টা করেন তবে list(frange(0, 1, 0.5))এটি সূক্ষ্মভাবে কাজ করে এবং 1 টি বাদ দেওয়া হয়েছে, তবে আপনি যদি চেষ্টা করেন list(frange(0, 1, 0.1))তবে শেষ মূল্যটি 1.0 এর কাছাকাছি যা সম্ভবত আপনি চান না। এখানে উপস্থাপিত সমাধানগুলিতে এই সমস্যাটি নেই।
blubberdiblub

3
কখনই numpy.arange ব্যবহার করবেন না (নাম্বার ডকুমেন্টেশন নিজেই এর বিরুদ্ধে প্রস্তাব দেয়)। উইম দ্বারা প্রস্তাবিত হিসাবে 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]
টিএনটি

2
@ টিএনটি না, এটি কোনও ত্রুটি নয়। আপনি np.linspace(-.1,10,num=5050)[0] == -.1সত্য খুঁজে পাবেন । এটি কেবলমাত্র repr(np.float64('-0.1'))আরও অংক দেখায়।
wim

1
যদিও সেই বিশেষ উদাহরণটি কোনও অতিরিক্ত গোলাকৃতি ত্রুটি দেখায় না, ব্যর্থতার কেস রয়েছে। উদাহরণস্বরূপ, print(numpy.linspace(0, 3, 148)[49])মুদ্রণগুলি 0.9999999999999999যখন আদর্শ ফলাফল হবে 1.0linspaceএর চেয়ে অনেক বেশি ভাল কাজ করে arangeতবে এটি ন্যূনতম সম্ভাব্য রাউন্ডিং ত্রুটি তৈরির নিশ্চয়তা দেয় না।
ব্যবহারকারী 2357112 মনিকা

এটা তোলে হয় সঠিক শেষবিন্দু হ্যান্ডলিং সঞ্চালন নিশ্চিত, এবং সবসময় উপাদানের ঠিক অনুরোধ সংখ্যা উত্পাদন।
ব্যবহারকারী 2357112 মনিকা 10

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
ম্যাজপ্লটলিব সংস্করণ ২.২ থেকে অদ্ভুতভাবে হ্রাস করা হয়েছে। 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
কারণ এটি খুব সহজ হবে, আমার ধারণা? :)
কার্ল নচেটেল 1'11

11

ব্যবহার itertools: আলস্যভাবে মূল্যায়ন ভাসমান পয়েন্ট পরিসীমা:

>>> 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 ফাংশন যুক্ত করতে সহায়তা করেছি

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

গিটহাবে পাওয়া কোড available


4

স্ট্যান্ডার্ড লাইব্রেরিতে কেন কোনও ফ্লোটিং পয়েন্ট রেঞ্জ বাস্তবায়ন নেই?

যেমনটি এখানে সমস্ত পোস্ট দ্বারা পরিষ্কার করা হয়েছে, এর কোনও ভাসমান পয়েন্ট সংস্করণ নেই range()। তাই বলা হয়, ভ্রান্তি যদি আমরা বিবেচনা যে অর্থে তোলে range()ফাংশন প্রায়ই (এবং অবশ্যই, তার মানে একটি একটি সূচক হিসেবে ব্যবহার করা হয় অ্যাকসেসর ) জেনারেটর। সুতরাং, আমরা যখন কল করি তখন আমরা range(0,40)কার্যকরভাবে বলব যে আমরা 40 টির মান 0 থেকে শুরু করে 40 পর্যন্ত, তবে 40 এর মধ্যে অন্তর্ভুক্ত নয়।

যখন আমরা বিবেচনা করি যে সূচক প্রজন্ম সূচকের সংখ্যাটি যতটা তার মান হিসাবে তত পরিমাণে range()হয় তবে স্ট্যান্ডার্ড লাইব্রেরিতে ভাসমান প্রয়োগের ব্যবহারটি কম বোঝায়। উদাহরণস্বরূপ, আমরা যদি ফাংশনটি কল frange(0, 10, 0.25)করি তবে আমরা 0 এবং 10 উভয়ই অন্তর্ভুক্ত করার প্রত্যাশা করব, তবে এটি 41 মান সহ একটি ভেক্টর অর্জন করবে।

সুতরাং, কোনও frange()ফাংশন তার ব্যবহারের উপর নির্ভর করে সর্বদা স্বাক্ষরিত আচরণের পাল্টা প্রদর্শন করবে; সূচকের দৃষ্টিকোণ থেকে এটির অনেকগুলি মান রয়েছে যা গণিতের দৃষ্টিকোণ থেকে যুক্তিসঙ্গতভাবে ফিরে আসা উচিত a

গাণিতিক ব্যবহারের কেস

যা বলা হয়েছে, আলোচিত হিসাবে, 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

এই সমস্যাটি সমাধান করার জন্য কয়েকটি উপায় রয়েছে তবে দিনের শেষে, সেরা নমুনাটি সম্ভবত নম্পিকে ব্যবহার করা হবে।


এটি বেশ বাঁকানো যুক্তি। পরিসীমা () কেবল পুনরাবৃত্তি জেনারেটরের দিকে লক্ষ্য করা উচিত এবং এটি লুপের জন্য ব্যবহৃত হয় বা কিছু সূচকে কল করার জন্য রেখে দেওয়া উচিত। মানুষ সহস্রাব্দের জন্য লুপ ফর লুপ ব্যবহার করে আসছেন এবং উপরোক্ত ন্যায়সঙ্গততা বোকামিযুক্ত। পাইথন কমিটির লোকেরা এখানে বিরাট সময় নিয়েছিল এবং ভাল যুক্তি সম্ভবত উপরের মতো কিছু বাঁকানো ন্যায়সঙ্গত দ্বারা ডুবে গেছে। এটি যে সরল এবং সহজ। পাইথন ভাষায় উপরোক্ত যেমন অনেকগুলি সিদ্ধান্ত রয়েছে।
শীতল শাহ

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

কোডটি গিটহাব গিস্ট হিসাবেও উপলব্ধ ।


এটি ফ্রেঞ্জ (2.0, 17.0 / 6.0, 1.0 / 6.0) এর সাথে ব্যর্থ। এটিকে কখনই শক্তিশালী করা যায় না এমন কোনও উপায় নেই।
23:58

@ বেনারগ এটি নির্দেশ করার জন্য ধন্যবাদ! এটি আমাকে উপলব্ধি করতে পরিচালিত করেছিল যে অ্যাপসিলনটি লাফের উপর নির্ভর করবে, তাই আমি অ্যালগরিদম পর্যালোচনা করে সমস্যাটি মেরামত করেছি। এই নতুন সংস্করণটি আরও শক্তিশালী, তাই না?
আকসেলি পালান

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] রৈখিকভাবে [শুরুর দিকে..স্টপ] map

সম্পাদন করা

যদি, অ্যালাঙ্কালভিটির মতো আপনিও সিরিজের সঠিক যুক্তিযুক্ত উপস্থাপনা করতে চান, আপনি সর্বদা ভগ্নাংশ ব্যবহার করতে পারেন :

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)
নিষ্পাপ

@ অ্যালাঙ্কালভিটি: আপনার "খারাপ" ভাসমান পয়েন্টের সংজ্ঞা কী? হ্যাঁ, ফলাফলগুলি দুর্দান্তভাবে মুদ্রণ করতে পারে না, তবে অদ্ভুত () ভাসমান পয়েন্ট উপস্থাপনার সীমাতে সমানভাবে ব্যবধানযুক্ত মানের সবচেয়ে নিকটতম সেট সরবরাহ করে। আপনি কিভাবে এটি উন্নতি করবেন?
নির্ভীক_ফুল

ভাল কথা, আমি এমন উচ্চ স্তরের ভাষাতে অভ্যস্ত হয়েছি যেখানে আপনি এই জাতীয় কোনও কাজের জন্য যুক্তিযুক্ত সংখ্যার উপর বিস্তৃত হবেন, যে পাইটিকে সমাবেশের মতো মনে হয়।
অ্যালানচলভিট্টি

পরিষদের? Hrrumph! ;) অবশ্যই পাইথন ভগ্নাংশ সঙ্গে সঠিক উপস্থাপনা প্রদান করতে পারেন: docs.python.org/3/library/fractions.html
fearless_fool

ঠিক আছে, ধন্যবাদ, তবে উদাহরণস্বরূপ, আমি যে ভাষাটি পছন্দ করি সেগুলি স্বয়ংক্রিয়ভাবে এই ধরণের রূপান্তরিত করে, সুতরাং ১/২ একটি যুক্তিযুক্ত, যখন ১ / ২.০ ভাসমান রয়েছে, তাদের যেমন ঘোষণার দরকার নেই - জাভাতে ঘোষণা ছেড়ে দিন, যা আরও বেশি পাই এর চেয়ে কম / সমাবেশ।
অ্যালানচলভিট্টি 22'19

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()(নিম্পী ডকুমেন্টেশন নিজেই এর বিরুদ্ধে প্রস্তাব দেয়) w

দ্রষ্টব্য 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

সমাধান ঘ

ইনডেক্স ভেরিয়েবল ব্যবহার করে ক্রমগত ত্রুটি হ্রাস করা যায়। উদাহরণটি এখানে:

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))

এই উদাহরণটি প্রত্যাশার মতো কাজ করে।

সমাধান 2

নেস্টেড ফাংশন নেই। শুধুমাত্র একটি সময় এবং একটি পাল্টা পরিবর্তনশীল:

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. Iteabless, 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

আমি একটি ফাংশন লিখেছি যা শততম দশকে ছাড়িয়ে কোনও দশমিক স্থান ছাড়াই ডাবল নির্ভুলতা ভাসমান পয়েন্ট সংখ্যার একটি পরিসীমা ফেরত দেয়। এটি কেবল স্ট্রিংয়ের মতো পরিসরের মানকে ভাগ করে নেওয়া এবং অতিরিক্তকে বিভক্ত করার বিষয়টি ছিল। আমি এটি কোনও ইউআইয়ের মধ্যে থেকে নির্বাচন করতে ব্যাপ্তি প্রদর্শন করতে ব্যবহার করি। আমি আশা করি অন্য কারও এটি দরকারী মনে হয়।

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]

প্রতিটি দশকে N দশমিক স্থানে গোল করতে

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দশমিক দশমিক ইনক্রিমেন্টের সাথে সত্যই সংগ্রাম করে, এবং সূত্রের বিভাগগুলির ক্রম বৃদ্ধিকে বিভিন্ন বিভাজনে রূপান্তর করার জন্য সঠিক বা ভাঙা কোডের ফলস্বরূপ হতে পারে।
  • ভিত্তিক অন্যান্য উত্তরগুলি 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)

দয়া করে নোট করুন রেঞ্জের প্রথম অক্ষরটি মূলধন is পাইথনের ফাংশনগুলির জন্য এই নামকরণ পদ্ধতিটি উত্সাহিত হয় না। আপনি চাইলে রেঞ্জকে ড্রেঞ্জ বা ফ্রেঞ্জের মতো কিছুতে পরিবর্তন করতে পারেন। "রেঞ্জ" ফাংশনটি আপনি যেমন চান তেমন আচরণ করে। আপনি এখানে এটির ম্যানুয়াল পরীক্ষা করতে পারেন [ http://references.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)... বেশিরভাগ ব্যবহারিক উদ্দেশ্যে, arangeনিম্পি থেকে একটি সহজ, নিরাপদ এবং দ্রুত সমাধান।
বার্ট

তুমি ঠিক. নম্পির সাথে আমার কোডের চেয়ে 1.8 দ্রুত।
গ্রিগর কোলেভ

তুমি ঠিক. নম্পির সাথে আমার কোডের চেয়ে 1.8 দ্রুত। তবে আমি যে সিস্টেমটিতে কাজ করি তা সম্পূর্ণ বন্ধ closed কেবল পাইথন এবং পাইসারিয়াল আর নেই।
গ্রিগর কোলেভ

-2

এখানে বেশ কয়েকটি উত্তর রয়েছে যা নেতিবাচক পদক্ষেপ, ভুল সূচনা, থামানো ইত্যাদির মতো সহজ প্রান্তের কেসগুলি পরিচালনা করে না Here এখানে এমন সংস্করণ যা এই ক্ষেত্রে অনেকগুলি হ্যান্ডেল করে যা সঠিকভাবে দেশীয় হিসাবে একই আচরণ দেয় 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। একটি পার্থক্য হ'ল নেটিজ রেঞ্জ রিটার্ন করা অবজেক্ট যা ইনডেক্সযোগ্য এবং বিপরীত হয় যখন উপরে থাকে না।

আপনি এই কোডটি এবং টেস্টের কেসগুলি এখানে খেলতে পারেন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.