소수점 범위 () 단계 값을 사용하는 방법은 무엇입니까?
0.1 씩 0과 1 사이를 이동하는 방법이 있습니까?
나는 다음과 같이 할 수 있다고 생각했지만 실패했습니다.
for i in range(0, 1, 0.1):
print i
대신 단계 인수가 0이 될 수 없다고 말하며 예상하지 못했습니다.
소수점 단계를 직접 사용하는 것보다 원하는 포인트 수로 표현하는 것이 훨씬 안전합니다. 그렇지 않으면 부동 소수점 반올림 오류가 잘못된 결과를 제공 할 수 있습니다.
NumPy 라이브러리 의 linspace
함수를 사용할 수 있습니다 (표준 라이브러리의 일부는 아니지만 비교적 쉽게 얻을 수 있음). 반환 할 여러 포인트를 취하고 올바른 끝점을 포함할지 여부를 지정할 수도 있습니다.linspace
>>> np.linspace(0,1,11)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
>>> np.linspace(0,1,10,endpoint=False)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
부동 소수점 단계 값을 실제로 사용하려면 numpy.arange
.
>>> import numpy as np
>>> np.arange(0.0, 1.0, 0.1)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
그러나 부동 소수점 반올림 오류 로 인해 문제 가 발생합니다. 다음은 반올림 오류로 인해 arange
3 개의 숫자 만 생성되어야하는 길이 4 배열을 생성 하는 간단한 경우 입니다.
>>> numpy.arange(1, 1.3, 0.1)
array([1. , 1.1, 1.2, 1.3])
파이썬의 range ()는 부동 소수점이 아닌 정수만 할 수 있습니다. 특정 경우에는 대신 목록 이해를 사용할 수 있습니다.
[x * 0.1 for x in range(0, 10)]
(범위 호출을 해당 식으로 바꿉니다.)
보다 일반적인 경우에는 사용자 지정 함수 또는 생성기를 작성할 수 있습니다.
'xrange ([start], stop [, step])' 에서 빌드 하면 선택한 모든 유형을 수락하고 생성하는 생성기를 정의 할 수 있습니다 ( +
및 지원하는 유형에 고착 <
).
>>> def drange(start, stop, step):
... r = start
... while r < stop:
... yield r
... r += step
...
>>> i0=drange(0.0, 1.0, 0.1)
>>> ["%g" % x for x in i0]
['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']
>>>
i
for 루프 의 크기를 늘린 다음 필요할 때 줄이십시오.
for i * 100 in range(0, 100, 10):
print i / 100.0
편집 : 나는 그것이 구문 론적으로 작동한다고 생각한 이유를 솔직히 기억할 수 없습니다.
for i in range(0, 11, 1):
print i / 10.0
원하는 출력이 있어야합니다.
scipy
플로트 처리 요구 사항을 충족시키기 위해 arange
Python의 range()
생성자를 일반화 하는 내장 함수 가 있습니다.
from scipy import arange
NumPy는 약간 과잉이라고 생각합니다.
[p/10 for p in range(0, 10)]
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
일반적으로 스텝 부산물 할 말하기 1/x
까지를 y
당신이 할 것
x=100
y=2
[p/x for p in range(0, int(x*y))]
[0.0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99]
( 1/x
테스트했을 때 반올림 노이즈가 적습니다).
R의 seq
함수 와 유사하게 ,이 함수는 올바른 단계 값이 주어지면 순서에 관계없이 시퀀스를 반환합니다. 마지막 값은 중지 값과 같습니다.
def seq(start, stop, step=1):
n = int(round((stop - start)/float(step)))
if n > 1:
return([start + step*i for i in range(n+1)])
elif n == 1:
return([start])
else:
return([])
결과
seq(1, 5, 0.5)
[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
seq(10, 0, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
seq(10, 0, -2)
[10, 8, 6, 4, 2, 0]
seq(1, 1)
[ 1 ]
range () 내장 함수는 정수 값의 시퀀스를 반환합니다. 두렵기 때문에 십진수 단계를 수행하는 데 사용할 수 없습니다.
while 루프를 사용한다고 말하고 싶습니다.
i = 0.0
while i <= 1.0:
print i
i += 0.1
궁금하다면 Python이 0.1을 0으로 변환하고 있기 때문에 인수가 0이 될 수 없다고 말하는 것입니다.
itertools를 사용하는 솔루션은 다음과 같습니다 .
import itertools
def seq(start, end, step):
if step == 0:
raise ValueError("step must not be 0")
sample_count = int(abs(end - start) / step)
return itertools.islice(itertools.count(start, step), sample_count)
사용 예 :
for i in seq(0, 1, 0.1):
print(i)
[x * 0.1 for x in range(0, 10)]
Python 2.7x에서 결과는 다음과 같습니다.
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]
그러나 다음을 사용하는 경우 :
[ round(x * 0.1, 1) for x in range(0, 10)]
원하는 것을 제공합니다.
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
import numpy as np
for i in np.arange(0, 1, 0.1):
print i
이 작업을 자주 수행하면 생성 된 목록을 저장하는 것이 좋습니다. r
r=map(lambda x: x/10.0,range(0,10))
for i in r:
print i
내 버전은 원래 범위 함수를 사용하여 이동에 대한 곱셈 인덱스를 만듭니다. 이것은 원래 범위 함수에 동일한 구문을 허용합니다. 어떤 경우에는 부동 소수점 산술로 인한 반올림 드리프트를 피하고 싶었 기 때문에 두 가지 버전을 만들었습니다. 하나는 float를 사용하고 다른 하나는 Decimal을 사용했기 때문입니다.
범위 / xrange에서와 같이 빈 집합 결과와 일치합니다.
하나의 숫자 값만 두 함수에 전달하면 표준 범위 출력이 입력 매개 변수의 정수 상한 값으로 반환됩니다 (따라서 5.5를 지정하면 range (6)를 반환합니다).
편집 : 아래 코드는 이제 pypi에서 패키지로 사용할 수 있습니다 : Franges
## frange.py
from math import ceil
# find best range function available to version (2.7.x / 3.x.x)
try:
_xrange = xrange
except NameError:
_xrange = range
def frange(start, stop = None, step = 1):
"""frange generates a set of floating point values over the
range [start, stop) with step size step
frange([start,] stop [, step ])"""
if stop is None:
for x in _xrange(int(ceil(start))):
yield x
else:
# create a generator expression for the index values
indices = (i for i in _xrange(0, int((stop-start)/step)))
# yield results
for i in indices:
yield start + step*i
## drange.py
import decimal
from math import ceil
# find best range function available to version (2.7.x / 3.x.x)
try:
_xrange = xrange
except NameError:
_xrange = range
def drange(start, stop = None, step = 1, precision = None):
"""drange generates a set of Decimal values over the
range [start, stop) with step size step
drange([start,] stop, [step [,precision]])"""
if stop is None:
for x in _xrange(int(ceil(start))):
yield x
else:
# find precision
if precision is not None:
decimal.getcontext().prec = precision
# convert values to decimals
start = decimal.Decimal(start)
stop = decimal.Decimal(stop)
step = decimal.Decimal(step)
# create a generator expression for the index values
indices = (
i for i in _xrange(
0,
((stop-start)/step).to_integral_value()
)
)
# yield results
for i in indices:
yield float(start + step*i)
## testranges.py
import frange
import drange
list(frange.frange(0, 2, 0.5)) # [0.0, 0.5, 1.0, 1.5]
list(drange.drange(0, 2, 0.5, precision = 6)) # [0.0, 0.5, 1.0, 1.5]
list(frange.frange(3)) # [0, 1, 2]
list(frange.frange(3.5)) # [0, 1, 2, 3]
list(frange.frange(0,10, -1)) # []
이것은 부동 단계로 범위를 얻는 내 솔루션입니다.
이 함수를 사용하면 numpy를 가져 오거나 설치할 필요가 없습니다.
나는 그것이 개선되고 최적화 될 수 있다고 확신합니다. 자유롭게하고 여기에 게시하세요.
from __future__ import division
from math import log
def xfrange(start, stop, step):
old_start = start #backup this value
digits = int(round(log(10000, 10)))+1 #get number of digits
magnitude = 10**digits
stop = int(magnitude * stop) #convert from
step = int(magnitude * step) #0.1 to 10 (e.g.)
if start == 0:
start = 10**(digits-1)
else:
start = 10**(digits)*start
data = [] #create array
#calc number of iterations
end_loop = int((stop-start)//step)
if old_start == 0:
end_loop += 1
acc = start
for i in xrange(0, end_loop):
data.append(acc/magnitude)
acc += step
return data
print xfrange(1, 2.1, 0.1)
print xfrange(0, 1.1, 0.1)
print xfrange(-1, 0.1, 0.1)
출력은 다음과 같습니다.
[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1]
[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0]
more_itertools
numeric_range
도구 를 구현하는 타사 라이브러리입니다 .
import more_itertools as mit
for x in mit.numeric_range(0, 1, 0.1):
print("{:.1f}".format(x))
산출
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
이 도구는 Decimal
및 에서도 작동합니다 Fraction
.
이 기능을 사용할 수 있습니다.
def frange(start,end,step):
return map(lambda x: x*step, range(int(start*1./step),int(end*1./step)))
트릭 피해야 할 반올림 문제 의 범위를 이동하기 위해 별도의 번호를 사용하는 것입니다 시작하고 반 단계 의 앞서 시작 .
# floating point range
def frange(a, b, stp=1.0):
i = a+stp/2.0
while i<b:
yield a
a += stp
i += stp
또는 numpy.arange
사용할 수 있습니다.
부티크의 완성도를위한 기능적 솔루션 :
def frange(a,b,s):
return [] if s > 0 and a > b or s < 0 and a < b or s==0 else [a]+frange(a+s,b,s)
Numpy 라이브러리를 사용하여 수행 할 수 있습니다. arange () 함수는 부동 단계를 허용합니다. 그러나 편의를 위해 tolist ()를 사용하여 목록으로 변환 할 수있는 numpy 배열을 반환합니다.
for i in np.arange(0, 1, 0.1).tolist():
print i
내 대답은 NumPy가 필요하지 않고 람다를 사용하지 않고 map ()을 사용하는 다른 사람들과 비슷합니다 (할 수는 있지만). dt 단위로 0.0에서 t_max까지의 float 값 목록을 얻으려면 :
def xdt(n):
return dt*float(n)
tlist = map(xdt, range(int(t_max/dt)+1))
잘못된 로그인 단계의 가능성에 대한 자동 수정을 추가합니다.
def frange(start,step,stop):
step *= 2*((stop>start)^(step<0))-1
return [start+i*step for i in range(int((stop-start)/step))]
내 솔루션 :
def seq(start, stop, step=1, digit=0):
x = float(start)
v = []
while x <= stop:
v.append(round(x,digit))
x += step
return v
최상의 솔루션 : 반올림 오류 없음
_________________________________________________________________________________
>>> step = .1
>>> N = 10 # number of data points
>>> [ x / pow(step, -1) for x in range(0, N + 1) ]
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
_________________________________________________________________________________
또는 설정된 데이터 포인트 (예 : 연속 기능) 대신 설정된 범위의 경우 다음을 사용합니다.
>>> step = .1
>>> rnge = 1 # NOTE range = 1, i.e. span of data points
>>> N = int(rnge / step
>>> [ x / pow(step,-1) for x in range(0, N + 1) ]
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
기능을 구현하려면 : 교체 x / pow(step, -1)
로 f( x / pow(step, -1) )
, 그리고 정의 f
.
예를 들면 :
>>> import math
>>> def f(x):
return math.sin(x)
>>> step = .1
>>> rnge = 1 # NOTE range = 1, i.e. span of data points
>>> N = int(rnge / step)
>>> [ f( x / pow(step,-1) ) for x in range(0, N + 1) ]
[0.0, 0.09983341664682815, 0.19866933079506122, 0.29552020666133955, 0.3894183423086505,
0.479425538604203, 0.5646424733950354, 0.644217687237691, 0.7173560908995228,
0.7833269096274834, 0.8414709848078965]
시작 및 중지는 둘 중 하나가 아닌 포함 (일반적으로 중지는 제외됨)이며 가져 오기없이 생성기를 사용합니다.
def rangef(start, stop, step, fround=5):
"""
Yields sequence of numbers from start (inclusive) to stop (inclusive)
by step (increment) with rounding set to n digits.
:param start: start of sequence
:param stop: end of sequence
:param step: int or float increment (e.g. 1 or 0.001)
:param fround: float rounding, n decimal places
:return:
"""
try:
i = 0
while stop >= start and step > 0:
if i==0:
yield start
elif start >= stop:
yield stop
elif start < stop:
if start == 0:
yield 0
if start != 0:
yield start
i += 1
start += step
start = round(start, fround)
else:
pass
except TypeError as e:
yield "type-error({})".format(e)
else:
pass
# passing
print(list(rangef(-100.0,10.0,1)))
print(list(rangef(-100,0,0.5)))
print(list(rangef(-1,1,0.2)))
print(list(rangef(-1,1,0.1)))
print(list(rangef(-1,1,0.05)))
print(list(rangef(-1,1,0.02)))
print(list(rangef(-1,1,0.01)))
print(list(rangef(-1,1,0.005)))
# failing: type-error:
print(list(rangef("1","10","1")))
print(list(rangef(1,10,"1")))
Python 3.6.2 (v3.6.2 : 5fd33b5, 2017 년 7 월 8 일, 04:57:36) [MSC v.1900 64 비트 (AMD64)]
아무도 아직 Python 3 문서에서 권장 솔루션 을 언급하지 않았습니다 .
또한보십시오:
- linspace 요리법 포인트 애플리케이션 부동이 적절한 범위의 게으른 버전을 구현하는 방법을 보여줍니다.
일단 정의되면 레시피는 사용하기 쉽고 numpy
다른 외부 라이브러리가 필요하지 않지만 numpy.linspace()
. step
인수 가 아닌 세 번째 num
인수는 원하는 값의 수를 지정합니다. 예를 들면 다음과 같습니다.
print(linspace(0, 10, 5))
# linspace(0, 10, 5)
print(list(linspace(0, 10, 5)))
# [0.0, 2.5, 5.0, 7.5, 10]
아래 Andrew Barnert의 전체 Python 3 레시피 수정 버전을 인용합니다.
import collections.abc
import numbers
class linspace(collections.abc.Sequence):
"""linspace(start, stop, num) -> linspace object
Return a virtual sequence of num numbers from start to stop (inclusive).
If you need a half-open range, use linspace(start, stop, num+1)[:-1].
"""
def __init__(self, start, stop, num):
if not isinstance(num, numbers.Integral) or num <= 1:
raise ValueError('num must be an integer > 1')
self.start, self.stop, self.num = start, stop, num
self.step = (stop-start)/(num-1)
def __len__(self):
return self.num
def __getitem__(self, i):
if isinstance(i, slice):
return [self[x] for x in range(*i.indices(len(self)))]
if i < 0:
i = self.num + i
if i >= self.num:
raise IndexError('linspace object index out of range')
if i == self.num-1:
return self.stop
return self.start + i*self.step
def __repr__(self):
return '{}({}, {}, {})'.format(type(self).__name__,
self.start, self.stop, self.num)
def __eq__(self, other):
if not isinstance(other, linspace):
return False
return ((self.start, self.stop, self.num) ==
(other.start, other.stop, other.num))
def __ne__(self, other):
return not self==other
def __hash__(self):
return hash((type(self), self.start, self.stop, self.num))
float 정밀도 문제를 해결하기 위해 Decimal
module을 사용할 수 있습니다 .
이것은로 변환의 추가적인 노력이 요구 Decimal
에서 int
또는 float
코드를 작성하면서,하지만 당신은 대신 전달할 수있는 str
편리의 종류는 참으로 필요한 경우 기능을 수정합니다.
from decimal import Decimal
from decimal import Decimal as D
def decimal_range(*args):
zero, one = Decimal('0'), Decimal('1')
if len(args) == 1:
start, stop, step = zero, args[0], one
elif len(args) == 2:
start, stop, step = args + (one,)
elif len(args) == 3:
start, stop, step = args
else:
raise ValueError('Expected 1 or 2 arguments, got %s' % len(args))
if not all([type(arg) == Decimal for arg in (start, stop, step)]):
raise ValueError('Arguments must be passed as <type: Decimal>')
# neglect bad cases
if (start == stop) or (start > stop and step >= zero) or \
(start < stop and step <= zero):
return []
current = start
while abs(current) < abs(stop):
yield current
current += step
샘플 출력-
list(decimal_range(D('2')))
# [Decimal('0'), Decimal('1')]
list(decimal_range(D('2'), D('4.5')))
# [Decimal('2'), Decimal('3'), Decimal('4')]
list(decimal_range(D('2'), D('4.5'), D('0.5')))
# [Decimal('2'), Decimal('2.5'), Decimal('3.0'), Decimal('3.5'), Decimal('4.0')]
list(decimal_range(D('2'), D('4.5'), D('-0.5')))
# []
list(decimal_range(D('2'), D('-4.5'), D('-0.5')))
# [Decimal('2'),
# Decimal('1.5'),
# Decimal('1.0'),
# Decimal('0.5'),
# Decimal('0.0'),
# Decimal('-0.5'),
# Decimal('-1.0'),
# Decimal('-1.5'),
# Decimal('-2.0'),
# Decimal('-2.5'),
# Decimal('-3.0'),
# Decimal('-3.5'),
# Decimal('-4.0')]
다음은 float_range (-1, 0, 0.01)에서 잘 작동하고 부동 소수점 표현 오류없이 작동하는 솔루션입니다. 매우 빠르지는 않지만 잘 작동합니다.
from decimal import Decimal
def get_multiplier(_from, _to, step):
digits = []
for number in [_from, _to, step]:
pre = Decimal(str(number)) % 1
digit = len(str(pre)) - 2
digits.append(digit)
max_digits = max(digits)
return float(10 ** (max_digits))
def float_range(_from, _to, step, include=False):
"""Generates a range list of floating point values over the Range [start, stop]
with step size step
include=True - allows to include right value to if possible
!! Works fine with floating point representation !!
"""
mult = get_multiplier(_from, _to, step)
# print mult
int_from = int(round(_from * mult))
int_to = int(round(_to * mult))
int_step = int(round(step * mult))
# print int_from,int_to,int_step
if include:
result = range(int_from, int_to + int_step, int_step)
result = [r for r in result if r <= int_to]
else:
result = range(int_from, int_to, int_step)
# print result
float_result = [r / mult for r in result]
return float_result
print float_range(-1, 0, 0.01,include=False)
assert float_range(1.01, 2.06, 5.05 % 1, True) ==\
[1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01, 2.06]
assert float_range(1.01, 2.06, 5.05 % 1, False)==\
[1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01]
나는 초보자에 불과하지만 일부 계산을 시뮬레이션 할 때 동일한 문제가 발생했습니다. 여기에 내가 이것을 해결하려고 시도한 방법이 있습니다.
나는 또한 꽤 게으 르기 때문에 내 자신의 범위 함수를 작성하기가 어려웠습니다.
기본적으로 내가 한 일은 내 변경 xrange(0.0, 1.0, 0.01)
에 xrange(0, 100, 1)
의해 사용 된 부문 100.0
루프 내부. 반올림 실수가 있는지도 걱정했습니다. 그래서 나는 어떤 것이 있는지 테스트하기로 결정했습니다. 예를 들어 0.01
계산 결과가 정확히 일치하지 않으면 0.01
False를 반환해야한다고 들었습니다 (내가 틀렸다면 알려주세요).
그래서 짧은 테스트를 실행하여 내 솔루션이 내 범위에서 작동하는지 테스트하기로 결정했습니다.
for d100 in xrange(0, 100, 1):
d = d100 / 100.0
fl = float("0.00"[:4 - len(str(d100))] + str(d100))
print d, "=", fl , d == fl
그리고 그것은 각각에 대해 True를 인쇄했습니다.
자, 내가 완전히 틀렸다면 알려주세요.
이 하나의 라이너는 코드를 복잡하게 만들지 않습니다. 단계 매개 변수 의 부호 가 중요합니다.
def frange(start, stop, step):
return [x*step+start for x in range(0,round(abs((stop-start)/step)+0.5001),
int((stop-start)/step<0)*-2+1)]
frange (시작, 중지, 정밀도)
def frange(a,b,i):
p = 10**i
sr = a*p
er = (b*p) + 1
p = float(p)
return map(lambda x: x/p, xrange(sr,er))
In >frange(-1,1,1)
Out>[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
참고 URL : https://stackoverflow.com/questions/477486/how-to-use-a-decimal-range-step-value
'Development Tip' 카테고리의 다른 글
Maven의 dependencyManagement와 종속성의 차이점 (0) | 2020.09.30 |
---|---|
파이썬`x가 None이 아니면`아니면`x가 None`이 아니면? (0) | 2020.09.30 |
git에서 두 커밋 사이에 변경된 줄 수를 어떻게 계산할 수 있습니까? (0) | 2020.09.30 |
다른 git 저장소에서 커밋을 체리로 선택할 수 있습니까? (0) | 2020.09.30 |
Android getResources (). getDrawable () 지원 중단 API 22 (0) | 2020.09.30 |