반 플로트 숫자를 적절하게 반올림하는 방법은 무엇입니까?
나는 이상한 행동에 직면해 있습니다.round()
함수:
for i in range(1, 15, 2):
n = i / 2
print(n, "=>", round(n))
이 코드는 다음을 인쇄합니다.
0.5 => 0
1.5 => 2
2.5 => 2
3.5 => 4
4.5 => 4
5.5 => 6
6.5 => 6
부동 값은 항상 반올림될 것으로 예상했지만, 대신 가장 가까운 짝수로 반올림됩니다.
왜 그런 행동을 하는지, 그리고 올바른 결과를 얻기 위한 가장 좋은 방법은 무엇입니까?
저는 그것을 사용하려고 했지만 결과는 동일합니다.
숫자 유형 섹션에서는 이 동작을 명시적으로 설명합니다.
round(x[, n])
x 반올림하여 n자리로 반올림하고 반올림하여 짝수로 만듭니다.n을 생략하면 기본값은 0입니다.
반올림하여 짝수로 표시합니다.이를 은행원 반올림이라고도 합니다. 항상 반올림하거나 반올림(반올림 오차를 합함)하는 대신 가장 가까운 짝수로 반올림하여 반올림 오차를 평균화합니다.
반올림 동작을 더 잘 제어해야 하는 경우 모듈을 사용하면 사용할 반올림 전략을 정확하게 지정할 수 있습니다.
예를 들어, 절반에서 반올림하는 방법:
>>> from decimal import localcontext, Decimal, ROUND_HALF_UP
>>> with localcontext() as ctx:
... ctx.rounding = ROUND_HALF_UP
... for i in range(1, 15, 2):
... n = Decimal(i) / 2
... print(n, '=>', n.to_integral_value())
...
0.5 => 1
1.5 => 2
2.5 => 3
3.5 => 4
4.5 => 5
5.5 => 6
6.5 => 7
예:
from decimal import Decimal, ROUND_HALF_UP
Decimal(1.5).quantize(0, ROUND_HALF_UP)
# This also works for rounding to the integer part:
Decimal(1.5).to_integral_value(rounding=ROUND_HALF_UP)
다음을 사용할 수 있습니다.
import math
def normal_round(n):
if n - math.floor(n) < 0.5:
return math.floor(n)
return math.ceil(n)
숫자를 위 또는 아래로 올바르게 반올림합니다.
round()
숫자가 짝수인지 홀수인지에 따라 위 또는 아래로 반올림됩니다.간단한 반올림 방법은 다음과 같습니다.
int(num + 0.5)
음수에 대해 올바르게 작동하려면 다음을 사용합니다.
((num > 0) - (num < 0)) * int(abs(num) + 0.5)
은 참로고, 이은큰숫매나우정숫확대자한과 같은 큰 숫자나 정말 을 엉망으로 수 .5000000000000001.0
그리고.0.49999999999999994
.
Fedor 2612 답변을 사랑합니다.나는 이 함수를 사용하여 소수점 이하의 수를 반올림하려는 사람들을 위해 선택적인 "소수점" 인수로 확장했습니다(예를 들어, 통화를 26.455달러에서 26.46달러로 반올림하고 싶은 경우).
import math
def normal_round(n, decimals=0):
expoN = n * 10 ** decimals
if abs(expoN) - abs(math.floor(expoN)) < 0.5:
return math.floor(expoN) / 10 ** decimals
return math.ceil(expoN) / 10 ** decimals
oldRounding = round(26.455,2)
newRounding = normal_round(26.455,2)
print(oldRounding)
print(newRounding)
출력:
26.45
26.46
표시되는 동작은 일반적인 IEEE 754 반올림 동작입니다.입력과 동일하게 다른 두 숫자 중에서 선택해야 하는 경우 항상 짝수를 선택합니다.이 동작의 장점은 평균 반올림 효과가 0이라는 것입니다. 마찬가지로 많은 숫자가 위아래로 반올림됩니다.중간 숫자를 일정한 방향으로 반올림하면 반올림이 기대 값에 영향을 줍니다.
목표가 공정한 반올림이라면 여러분이 보고 있는 행동은 옳지만, 그것이 항상 필요한 것은 아닙니다.
원하는 반올림 유형을 얻는 한 가지 방법은 0.5를 추가한 다음 바닥을 차지하는 것입니다.예를 들어, 0.5에서 2.5를 더하면 바닥이 3이고 바닥이 3입니다.
왜 그렇게 복잡하게 만드나요? (양수에만 해당)
def HalfRoundUp(value):
return int(value + 0.5)
물론 다음과 같은 람다로 만들 수 있습니다.
HalfRoundUp = lambda value: int(value + 0.5)
불행하게도, 이 간단한 답은 음수에서는 작동하지 않지만, 수학의 바닥 함수에서는 고정될 수 있습니다. (양수와 음수 모두에 대해서도 작동합니다.)
from math import floor
def HalfRoundUp(value):
floor(value + 0.5)
짧은 버전: 십진수 모듈을 사용합니다.2.675가 실제로 2.674999999999982236416599749535322189331056875(정확히)인 파이썬 플로트와는 달리 2.675와 같은 숫자를 정확하게 나타낼 수 있습니다.그리고 원하는 반올림을 지정할 수 있습니다. ROUUND_CEILING, ROUUND_DOWN, ROUUND_HALF_DOWN, ROUUND_HALF_EVEN, ROUUND_HALF_UP, ROUUND_05UP가 모두 옵션입니다.
질문에서 이것은 기본적으로 양의 정수를 2로 나눌 때 문제가 됩니다.은 가장쉬방은법입니다.int(n + 0.5)
개개의 번호로
그러나 우리는 이것을 시리즈에 적용할 수 없기 때문에, 예를 들어 판다 데이터 프레임에 대해 루프에 들어가지 않고 다음과 같이 할 수 있는 것은 다음과 같습니다.
import numpy as np
df['rounded_division'] = np.where(df['some_integer'] % 2 == 0, round(df['some_integer']/2,0), round((df['some_integer']+1)/2,0))
일부 솔루션을 반올림하여 작은 값을 추가하는 것은 경우에 따라 예상대로 작동하지 않을 수 있습니다.
예를 들어 위의 기능을 사용하면 다음과 같습니다.
from decimal import Decimal, ROUND_HALF_UP
def round_half_up(x: float, num_decimals: int) -> float:
if num_decimals < 0:
raise ValueError("Num decimals needs to be at least 0.")
target_precision = "1." + "0" * num_decimals
rounded_x = float(Decimal(x).quantize(Decimal(target_precision), ROUND_HALF_UP))
return rounded_x
round_half_up(1.35, 1)
1.4
round_half_up(4.35, 1)
4.3
내가 기대했던 곳은4.4
ㅠㅠㅠㅠㅠㅠㅠㅠㅠx
먼저 줄로
from decimal import Decimal, ROUND_HALF_UP
def round_half_up(x: float, num_decimals: int) -> float:
if num_decimals < 0:
raise ValueError("Num decimals needs to be at least 0.")
target_precision = "1." + "0" * num_decimals
rounded_x = float(Decimal(str(x)).quantize(Decimal(target_precision), ROUND_HALF_UP))
return rounded_x
round_half_up(4.35, 1)
4.4
가장 가까운 짝수로 반올림하는 것은 수치 분야에서 일반적인 관행이 되었습니다."반올림"은 더 큰 결과에 대한 약간의 편향을 생성합니다.
에서는 그서래관, 계의서보면점에과학,보▁so면ific과서에관,▁establish▁the,학계ment점.round
올바른 동작을 합니다.
여기 또 다른 해결책이 있습니다.엑셀에서 정상적인 라운딩으로 작동할 것입니다.
from decimal import Decimal, getcontext, ROUND_HALF_UP
round_context = getcontext()
round_context.rounding = ROUND_HALF_UP
def c_round(x, digits, precision=5):
tmp = round(Decimal(x), precision)
return float(tmp.__round__(digits))
c_round(0.15, 1) -> 0.2, c_round(0.5, 0) -> 1
은 "학교 라운딩"을 " 패션 라운딩"을달성했습니다.decimal
모듈(느린 것으로 판명됨).
def school_round(a_in,n_in):
''' python uses "banking round; while this round 0.05 up" '''
if (a_in * 10 ** (n_in + 1)) % 10 == 5:
return round(a_in + 1 / 10 ** (n_in + 1), n_in)
else:
return round(a_in, n_in)
예.
print(round(0.005,2)) # 0
print(school_round(0.005,2)) #0.01
그래서 여기에 명확한 작업 사례가 있는지 확인하기 위해 작은 편의 기능을 작성했습니다.
def round_half_up(x: float, num_decimals: int) -> float:
"""Use explicit ROUND HALF UP. See references, for an explanation.
This is the proper way to round, as taught in school.
Args:
x:
num_decimals:
Returns:
https://stackoverflow.com/questions/33019698/how-to-properly-round-up-half-float-numbers-in-python
"""
if num_decimals < 0:
raise ValueError("Num decimals needs to be at least 0.")
target_precision = "1." + "0" * num_decimals
rounded_x = float(Decimal(x).quantize(Decimal(target_precision), ROUND_HALF_UP))
return rounded_x
그리고 적절한 테스트 사례 세트가
def test_round_half_up():
x = 1.5
y = round_half_up(x, 0)
assert y == 2.0
y = round_half_up(x, 1)
assert y == 1.5
x = 1.25
y = round_half_up(x, 1)
assert y == 1.3
y = round_half_up(x, 2)
assert y == 1.25
소수 자릿수를 인수로 사용하는 함수입니다.소수점 이하 반올림하기도 합니다.
import math
def normal_round(n, decimal_places):
if int((str(n)[-1])) < 5:
return round(n, decimal_places)
return round(n + 10**(-1 * (decimal_places+1)), decimal_places)
테스트 사례:
>>> normal_round(5.12465, 4)
5.1247
>>> normal_round(5.12464, 4)
5.1246
>>> normal_round(5.12467, 4)
5.1247
>>> normal_round(5.12463, 4)
5.1246
>>> normal_round(5.1241, 4)
5.1241
>>> normal_round(5.1248, 4)
5.1248
>>> normal_round(5.1248, 3)
5.125
>>> normal_round(5.1242, 3)
5.124
사용할 수 있는 항목:
from decimal import Decimal, ROUND_HALF_UP
for i in range(1, 15, 2):
n = i / 2
print(n, "=>", Decimal(str(n)).quantize(Decimal("1"), rounding=ROUND_HALF_UP))
라이브러리가 없는 고전적인 수학적 반올림
def rd(x,y=0):
''' A classical mathematical rounding by Voznica '''
m = int('1'+'0'*y) # multiplier - how many positions to the right
q = x*m # shift to the right by multiplier
c = int(q) # new number
i = int( (q-c)*10 ) # indicator number on the right
if i >= 5:
c += 1
return c/m
Compare:
print( round(0.49), round(0.51), round(0.5), round(1.5), round(2.5), round(0.15,1)) # 0 1 0 2 2 0.1
print( rd(0.49), rd(0.51), rd(0.5), rd(1.5), rd(2.5), rd(0.15,1)) # 0 1 1 2 3 0.2
은는은▁that것▁knowing.round(9.99,0)
로의 라운드.int=10
그리고.int(9.99)
로의 라운드.int=9
성공을 가져옵니다.
목에 더 와 더 합니다.value
def get_half_round_numers(self, value):
"""
Returns dict with upper_half_rn and lower_half_rn
:param value:
:return:
"""
hrns = {}
if not isinstance(value, float):
print("Error>Input is not a float. None return.")
return None
value = round(value,2)
whole = int(value) # Rounds 9.99 to 9
remainder = (value - whole) * 100
if remainder >= 51:
hrns['upper_half_rn'] = round(round(value,0),2) # Rounds 9.99 to 10
hrns['lower_half_rn'] = round(round(value,0) - 0.5,2)
else:
hrns['lower_half_rn'] = round(int(value),2)
hrns['upper_half_rn'] = round(int(value) + 0.5,2)
return hrns
일부 테스트:
야!
import math
# round tossing n digits from the end
def my_round(n, toss=1):
def normal_round(n):
if isinstance(n, int):
return n
intn, dec = str(n).split(".")
if int(dec[-1]) >= 5:
if len(dec) == 1:
return math.ceil(n)
else:
return float(intn + "." + str(int(dec[:-1]) + 1))
else:
return float(intn + "." + dec[:-1])
while toss >= 1:
n = normal_round(n)
toss -= 1
return n
for n in [1.25, 7.3576, 30.56]:
print(my_round(n, 2))
1.0
7.36
31
import math
def round_half_up(x: float) -> int:
if x < 0:
return math.trunc(x) if -x % 1 < 0.5 else math.floor(x)
else:
return math.trunc(x) if x % 1 < 0.5 else math.ceil(x)
이것은 심지어 다음과 같은 코너 케이스에도 효과가 있습니다.0.49999999999999994
그리고.5000000000000001.0
.
해보세요.
def round(num):
return round(num + 10**(-9))
이후로 작동할 것입니다.num = x.5
항상 그럴 것입니다.x.5 + 0.00...01
보다 가까운 과정에서x+1
따라서 라운드 함수는 제대로 작동하고 라운드할 것입니다.x.5
로.x+1
언급URL : https://stackoverflow.com/questions/33019698/how-to-properly-round-up-half-float-numbers
'source' 카테고리의 다른 글
항목을 수평으로 배치하는 WPF ListBox (0) | 2023.05.26 |
---|---|
한 배열에 다른 배열의 모든 요소가 포함되어 있는지 확인하는 방법 (0) | 2023.05.26 |
div에서 텍스트를 수직으로 정렬하려면 어떻게 해야 합니까? (0) | 2023.05.26 |
각도 2를 사용한 HTML5 이벤트 처리(포커스 및 포커스 아웃) (0) | 2023.05.26 |
업데이트 패키지.json 버전 자동으로 (0) | 2023.05.21 |