답변:
첫째, 복사하여 붙여 넣기 코드를 원하는 사람들을위한 함수 :
def truncate(f, n):
'''Truncates/pads a float f to n decimal places without rounding'''
s = '{}'.format(f)
if 'e' in s or 'E' in s:
return '{0:.{1}f}'.format(f, n)
i, p, d = s.partition('.')
return '.'.join([i, (d+'0'*n)[:n]])
이것은 Python 2.7 및 3.1+에서 유효합니다. 이전 버전의 경우 동일한 "지능형 반올림"효과를 얻을 수 없습니다 (적어도 복잡한 코드가 많지 않음). 그러나 자르기 전에 소수점 이하 12 자리로 반올림하면 대부분의 경우 작동합니다.
def truncate(f, n):
'''Truncates/pads a float f to n decimal places without rounding'''
s = '%.12f' % f
i, p, d = s.partition('.')
return '.'.join([i, (d+'0'*n)[:n]])
기본 방법의 핵심은 값을 완전한 정밀도로 문자열로 변환 한 다음 원하는 문자 수를 초과하는 모든 것을 잘라내는 것입니다. 후자의 단계는 쉽습니다. 문자열 조작으로 수행 할 수 있습니다.
i, p, d = s.partition('.')
'.'.join([i, (d+'0'*n)[:n]])
또는 decimal모듈
str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN))
문자열로 변환하는 첫 번째 단계는 동일한 이진 표현을 생성하지만 다르게 잘 려야하는 부동 소수점 리터럴 (즉, 소스 코드에 작성한 내용) 쌍이 있기 때문에 매우 어렵습니다. 예를 들어 0.3 및 0.29999999999999998을 고려하십시오. 사용자가 작성하면 0.3파이썬 프로그램 컴파일러는 비트의 시퀀스 (64- 비트 부동 가정)에 IEEE 부동 소수점 포맷을 사용하여 인코딩
0011111111010011001100110011001100110011001100110011001100110011
이것은 IEEE 부동 소수점으로 정확하게 표현할 수있는 0.3에 가장 가까운 값입니다. 그러나 0.29999999999999998Python 프로그램으로 작성하면 컴파일러는 정확히 동일한 값 으로 변환합니다 . 한 경우에는으로 잘 리도록 (한 자리로) 0.3의미했지만 다른 경우에는으로 잘리는 것을 의미 0.2했지만 Python은 하나의 답변 만 제공 할 수 있습니다. 이것은 Python 또는 실제로 지연 평가가없는 모든 프로그래밍 언어의 근본적인 제한입니다. 자르기 함수는 소스 코드에 실제로 입력 한 문자열이 아니라 컴퓨터 메모리에 저장된 이진 값에만 액세스 할 수 있습니다. 1
IEEE 64 비트 부동 소수점 형식을 사용하여 비트 시퀀스를 10 진수로 다시 디코딩하면
0.2999999999999999888977697537484345957637...
그래서 0.2당신이 원하는 것이 아닐지라도 순진한 구현이 나올 것입니다 . 부동 소수점 표현 오류에 대한 자세한 내용은 Python 가이드를 참조하세요 .
라운드 수에 너무 가깝지만 의도적 으로 해당 라운드 수와 같지 않은 부동 소수점 값으로 작업하는 것은 매우 드뭅니다 . 따라서자를 때 메모리의 값에 해당 할 수있는 모든 것 중에서 "가장 가까운"십진수 표현을 선택하는 것이 좋습니다. Python 2.7 이상 (3.0은 아님)에는이 를 수행 하는 정교한 알고리즘이 포함되어 있으며 기본 문자열 형식화 작업을 통해 액세스 할 수 있습니다.
'{}'.format(f)
유일한주의 사항은 숫자가 충분히 크거나 작은 경우 g지수 표기법 ( 1.23e+4)을 사용한다는 점에서 형식 사양 처럼 작동 한다는 것 입니다. 따라서 메서드는이 경우를 포착하고 다르게 처리해야합니다. f대신 형식 사양을 사용 3e-10하여 28 자리의 정밀도 로 자르는 것과 같이 문제가 발생 하는 몇 가지 경우가 있습니다 (생성됨 0.0000000002999999999999999980).
실제로 반올림 숫자에 매우 가깝지만 의도적으로 같지 않은 s 로 작업하는 경우 float(예 : 0.29999999999999998 또는 99.959999999999994) 이는 일부 거짓 양성을 생성합니다. 즉, 반올림하지 않으려는 숫자를 반올림합니다. 이 경우 해결책은 고정 정밀도를 지정하는 것입니다.
'{0:.{1}f}'.format(f, sys.float_info.dig + n + 2)
여기서 사용할 정밀도의 자릿수는 실제로 중요하지 않습니다. 문자열 변환에서 수행 된 반올림이 값을 멋진 십진수 표현으로 "올라가는"일이 없도록 충분히 커야합니다. 나는 sys.float_info.dig + n + 2모든 경우에 충분 하다고 생각 하지만 그렇지 않다면 2증가해야 할 수도 있고 그렇게해도 아프지 않습니다.
이전 버전의 Python (최대 2.6 또는 3.0)에서는 부동 소수점 숫자 형식이 훨씬 더 조잡했으며 다음과 같은 것을 정기적으로 생성했습니다.
>>> 1.1
1.1000000000000001
이 경우이 상황 인 경우 않는 절단은 "좋은"진수 표현을 사용하려는 모든 당신이 (내가 아는 한) 할 수있는 것은으로 전체 정밀 표현할 수보다 적은 숫자의 몇 가지 숫자를 선택이며 float, 둥근 자르기 전에 그 수만큼의 숫자로. 일반적인 선택은 12입니다.
'%.12f' % f
하지만 사용중인 숫자에 맞게 조정할 수 있습니다.
1 음 ... 거짓말을 했어. 기술적으로 Python에 자체 소스 코드를 다시 구문 분석하고 자르기 함수에 전달하는 첫 번째 인수에 해당하는 부분을 추출하도록 지시 할 수 있습니다 . 해당 인수가 부동 소수점 리터럴이면 소수점 뒤의 특정 자릿수를 잘라 내고 반환 할 수 있습니다. 그러나이 전략은 인수가 변수 인 경우 작동하지 않으므로 상당히 쓸모가 없습니다. 다음은 엔터테인먼트 가치로만 제공됩니다.
def trunc_introspect(f, n):
'''Truncates/pads the float f to n decimal places by looking at the caller's source code'''
current_frame = None
caller_frame = None
s = inspect.stack()
try:
current_frame = s[0]
caller_frame = s[1]
gen = tokenize.tokenize(io.BytesIO(caller_frame[4][caller_frame[5]].encode('utf-8')).readline)
for token_type, token_string, _, _, _ in gen:
if token_type == tokenize.NAME and token_string == current_frame[3]:
next(gen) # left parenthesis
token_type, token_string, _, _, _ = next(gen) # float literal
if token_type == tokenize.NUMBER:
try:
cut_point = token_string.index('.') + n + 1
except ValueError: # no decimal in string
return token_string + '.' + '0' * n
else:
if len(token_string) < cut_point:
token_string += '0' * (cut_point - len(token_string))
return token_string[:cut_point]
else:
raise ValueError('Unable to find floating-point literal (this probably means you called {} with a variable)'.format(current_frame[3]))
break
finally:
del s, current_frame, caller_frame
변수를 전달하는 경우를 처리하기 위해 이것을 일반화하면 변수에 값을 부여한 부동 소수점 리터럴을 찾을 때까지 프로그램 실행을 거꾸로 추적해야하기 때문에 손실 된 원인처럼 보입니다. 하나라도 있다면. 대부분의 변수는 사용자 입력 또는 수학 식에서 초기화되며,이 경우 이진 표현이 전부입니다.
applymap(). 전체 작업을보다 효율적으로 만드는 방법이있을 수 있지만 별도의 질문이 필요합니다.
round(1.923328437452, 3)
표준 유형에 대한 Python의 문서를 참조하십시오 . round 함수를 사용하려면 약간 아래로 스크롤해야합니다. 기본적으로 두 번째 숫자는 반올림 할 소수 자릿수를 나타냅니다.
의 결과 round는 부동 소수점이므로주의하십시오 (예 : Python 2.6).
>>> round(1.923328437452, 3)
1.923
>>> round(1.23456, 3)
1.2350000000000001
형식이 지정된 문자열을 사용할 때 더 좋습니다.
>>> "%.3f" % 1.923328437452
'1.923'
>>> "%.3f" % 1.23456
'1.235'
round(1.23456, 3)입니다 1.235하지1.2350000000000001
n = 1.923328437452
str(n)[:4]
2소수점이있을 .것입니다. 제 생각에는 좋은 해결책이 아닙니다.
간단한 파이썬 스크립트-
n = 1.923328437452
n = float(int(n * 1000))
n /=1000
정말 비단뱀적인 방법은
from decimal import *
with localcontext() as ctx:
ctx.rounding = ROUND_DOWN
print Decimal('1.923328437452').quantize(Decimal('0.001'))
이하 :
from decimal import Decimal as D, ROUND_DOWN
D('1.923328437452').quantize(D('0.001'), rounding=ROUND_DOWN)
최신 정보
일반적으로 문제는 float 자체를 자르는 것이 아니라 반올림 하기 전에 float 숫자 를 부적절하게 사용하는 것입니다 .
예 : int(0.7*3*100)/100 == 2.09.
실수 를 사용 하도록 강요받는 경우 (예 :를 사용하여 코드를 가속화 numba하는 경우) 센트를 가격의 "내부 표현"으로 사용 70*3 == 210하고 입력 / 출력을 곱하거나 나누는 것이 좋습니다.
int(0.7*3*100)/100 == 2.09. 내 1 센트는 어디로 갔습니까?
ImportError: cannot import name 'D', 난 당신이 명명 된 수입 없음을 확인하고 싶었 생각?
이 질문에 대한 많은 답변이 완전히 잘못되었습니다. 그들은 (자르기보다는) 수레를 반올림하거나 모든 경우에 작동하지 않습니다.
'Python truncate float'를 검색했을 때 가장 많이 검색된 Google 검색 결과입니다.이 개념은 정말 간단하고 더 나은 답변을받을 가치가 있습니다. 나는 decimal모듈 을 사용하는 것이 비단뱀적인 방법이라는 Hatchkins에 동의한다 . 그래서 나는 여기서 질문에 올바르게 답하고 모든 경우에 예상대로 작동하는 함수를 제공한다.
참고로, 분수 값은 일반적으로 이진 부동 소수점 변수로 정확하게 표현할 수 없습니다 (이에 대한 설명 은 여기 참조 ). 이것이 내 함수가 문자열을 반환하는 이유입니다.
from decimal import Decimal, localcontext, ROUND_DOWN
def truncate(number, places):
if not isinstance(places, int):
raise ValueError("Decimal places must be an integer.")
if places < 1:
raise ValueError("Decimal places must be at least 1.")
# If you want to truncate to 0 decimal places, just do int(number).
with localcontext() as context:
context.rounding = ROUND_DOWN
exponent = Decimal(str(10 ** - places))
return Decimal(str(number)).quantize(exponent).to_eng_string()
넌 할 수있어:
def truncate(f, n):
return math.floor(f * 10 ** n) / 10 ** n
테스트 :
>>> f=1.923328437452
>>> [truncate(f, n) for n in range(5)]
[1.0, 1.9, 1.92, 1.923, 1.9233]
그냥 "make round () with floor ()"트릭을 언급하고 싶었습니다.
round(f) = floor(f+0.5)
round ()에서 floor ()를 만들 수 있습니다.
floor(f) = round(f-0.5)
이 두 규칙은 모두 음수로 구분되지만 사용하는 것은 이상적이지 않습니다.
def trunc(f, n):
if f > 0:
return "%.*f" % (n, (f - 0.5*10**-n))
elif f == 0:
return "%.*f" % (n, f)
elif f < 0:
return "%.*f" % (n, (f + 0.5*10**-n))
사용하기위한 일반적이고 간단한 기능 :
def truncate_float(number, length):
"""Truncate float numbers, up to the number specified
in length that must be an integer"""
number = number * pow(10, length)
number = int(number)
number = float(number)
number /= pow(10, length)
return number
제 생각에는 대부분의 답변이 너무 복잡합니다. 이건 어떨까요?
digits = 2 # Specify how many digits you want
fnum = '122.485221'
truncated_float = float(fnum[:fnum.find('.') + digits + 1])
>>> 122.48
'.'의 색인을 스캔하기 만하면됩니다. 원하는대로 자릅니다 (반올림 없음). 마지막 단계로 문자열을 부동 소수점으로 변환합니다.
또는 귀하의 경우에는 float를 입력으로 얻고 문자열을 출력으로 원할 경우 :
fnum = str(122.485221) # convert float to string first
truncated_float = fnum[:fnum.find('.') + digits + 1] # string output
라이브러리 나 다른 외부 종속성없이 목록 이해에 적합 할만큼 간단한 것. Python> = 3.6의 경우 f- 문자열로 작성하는 것은 매우 간단합니다.
아이디어는 문자열 변환이 필요한 것보다 한 자리 더 반올림 한 다음 마지막 숫자를 잘라내는 것입니다.
>>> nout = 3 # desired number of digits in output
>>> [f'{x:.{nout+1}f}'[:-1] for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]]
['0.666', '0.800', '0.888', '1.125', '1.250', '1.500']
물론,이 된다 (즉, 네 번째 자리를 위해) 여기에서 일어나고 반올림하지만, 반올림 어떤 점에서 것은 unvoidable입니다. 잘림과 반올림 사이의 전환이 관련된 경우 다음은 약간 더 나은 예입니다.
>>> nacc = 6 # desired accuracy (maximum 15!)
>>> nout = 3 # desired number of digits in output
>>> [f'{x:.{nacc}f}'[:-(nacc-nout)] for x in [2.9999, 2.99999, 2.999999, 2.9999999]]
>>> ['2.999', '2.999', '2.999', '3.000']
보너스 : 오른쪽에서 0 제거
>>> nout = 3 # desired number of digits in output
>>> [f'{x:.{nout+1}f}'[:-1].rstrip('0') for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]]
['0.666', '0.8', '0.888', '1.125', '1.25', '1.5']
파이썬 초보자이기도합니다. 여기에서 약간의 조각을 활용 한 후 2 센트를 제공합니다.
print str(int(time.time()))+str(datetime.now().microsecond)[:3]
str (int (time.time ()))은 시간 epoch를 int로 취하여 문자열로 변환하고 다음과 결합합니다 ... str (datetime.now (). microsecond) [: 3] 이는 마이크로 초 만 반환합니다. 문자열을 만들고 처음 3 자까지 자릅니다.
# value value to be truncated
# n number of values after decimal
value = 0.999782
n = 3
float(int(value*1en))*1e-n