Joa*_*nge 100 python floating-point
我想从浮点数中删除数字,使点后面有一个固定的位数,如:
1.923328437452 -> 1.923
Run Code Online (Sandbox Code Playgroud)
我需要将字符串输出到另一个函数,而不是打印.
此外,我想忽略丢失的数字,而不是围绕它们.
Tei*_*ion 143
round(1.923328437452, 3)
Run Code Online (Sandbox Code Playgroud)
请参阅Python有关标准类型的文档.你需要向下滚动一下才能进入圆形函数.基本上第二个数字表示将它四舍五入到的小数位数.
Dav*_*d Z 106
首先,该功能适用于那些只想要一些复制粘贴代码的人:
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]])
Run Code Online (Sandbox Code Playgroud)
这在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]])
Run Code Online (Sandbox Code Playgroud)
底层方法的核心是以完全精度将值转换为字符串,然后只删除超出所需字符数的所有内容.后一步很容易; 它可以通过字符串操作来完成
i, p, d = s.partition('.')
'.'.join([i, (d+'0'*n)[:n]])
Run Code Online (Sandbox Code Playgroud)
或decimal模块
str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN))
Run Code Online (Sandbox Code Playgroud)
第一步,转换为字符串,是非常困难的,因为有一些浮点文字(即你在源代码中编写的内容),它们都产生相同的二进制表示,但应该被截断不同.例如,考虑0.3和0.29999999999999998.如果您0.3在Python程序中编写,则编译器使用IEEE浮点格式将其编码为位序列(假设为64位浮点数)
0011111111010011001100110011001100110011001100110011001100110011
Run Code Online (Sandbox Code Playgroud)
这是0.3的最接近的值,可以准确地表示为IEEE浮点数.但是如果你0.29999999999999998在Python程序中编写,编译器会将其转换为完全相同的值.在一种情况下,你的意思是它被截断(到一位数)0.3,而在另一种情况下你的意思是它被截断为0.2,但Python只能给出一个答案.这是Python的基本限制,或者实际上没有懒惰评估的任何编程语言.截断功能只能访问存储在计算机内存中的二进制值,而不能访问实际输入源代码的字符串.1
如果您将位序列解码为十进制数,再次使用IEEE 64位浮点格式,则可以得到
0.2999999999999999888977697537484345957637...
Run Code Online (Sandbox Code Playgroud)
所以0.2即使这可能不是你想要的,也会提出一个天真的实现.有关浮点表示错误的更多信息,请参阅Python教程.
使用浮点值非常罕见,浮点值非常接近圆数但有意不等于该数.因此,当截断时,从可能对应于内存中的值的所有选择中"最好的"十进制表示可能是有意义的.Python 2.7及更高版本(但不是3.0)包含一个复杂的算法,我们可以通过默认的字符串格式化操作来访问它.
'{}'.format(f)
Run Code Online (Sandbox Code Playgroud)
唯一需要注意的是,这就像g格式规范一样,它使用指数表示法(1.23e+4),如果数字足够大或足够小.因此,该方法必须捕获此情况并以不同方式处理它.在某些情况下,使用f格式规范会导致问题,例如尝试截断3e-10到28位精度(它会产生0.0000000002999999999999999980),而我还不确定如何最好地处理这些问题.
如果你确实正在与工作floats表示非常接近圆形数字,但故意不等于他们(像0.29999999999999998或99.959999999999994),这会产生一些假阳性,即它会圆你不想四舍五入数值.在这种情况下,解决方案是指定固定的精度.
'{0:.{1}f}'.format(f, sys.float_info.dig + n + 2)
Run Code Online (Sandbox Code Playgroud)
这里使用的精度位数并不重要,它只需要足够大,以确保在字符串转换中执行的任何舍入不会将值"提升"到其漂亮的十进制表示.我认为sys.float_info.dig + n + 2在所有情况下都可能足够,但如果不是这样2可能必须增加,并且这样做也没有坏处.
在Python的早期版本(高达2.6或3.0)中,浮点数格式化更粗糙,并且会定期生成像
>>> 1.1
1.1000000000000001
Run Code Online (Sandbox Code Playgroud)
如果这是你的情况,如果你不希望使用"好"十进制表示为截断,所有你能做的(据我所知)是挑选一些号码的数字,小于由全精度表示的float,与轮在截断之前编号为那么多位数.典型的选择是12,
'%.12f' % f
Run Code Online (Sandbox Code Playgroud)
但你可以调整它以适应你正在使用的数字.
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
Run Code Online (Sandbox Code Playgroud)
推广这个以处理传入变量的情况似乎是一个失败的原因,因为你必须追溯程序的执行,直到找到给变量赋值的浮点文字.如果有的话.大多数变量将从用户输入或数学表达式初始化,在这种情况下,二进制表示就是全部.
Fer*_*yer 31
结果round是一个浮点数,所以要注意(例如来自Python 2.6):
>>> round(1.923328437452, 3)
1.923
>>> round(1.23456, 3)
1.2350000000000001
Run Code Online (Sandbox Code Playgroud)
使用格式化字符串时,您会更好:
>>> "%.3f" % 1.923328437452
'1.923'
>>> "%.3f" % 1.23456
'1.235'
Run Code Online (Sandbox Code Playgroud)
小智 19
n = 1.923328437452
str(n)[:4]
Run Code Online (Sandbox Code Playgroud)
mar*_*xor 10
简单的python脚本 -
n = 1.923328437452
n = float(int(n * 1000))
n /=1000
Run Code Online (Sandbox Code Playgroud)
def trunc(num, digits):
sp = str(num).split('.')
return '.'.join([sp[0], sp[1][:digits]])
Run Code Online (Sandbox Code Playgroud)
这应该工作.它应该给你你正在寻找的截断.
真正的pythonic方式是
from decimal import *
with localcontext() as ctx:
ctx.rounding = ROUND_DOWN
print Decimal('1.923328437452').quantize(Decimal('0.001'))
Run Code Online (Sandbox Code Playgroud)
为这个问题提出的许多答案都是完全错误的.它们要么将浮动(而不是截断)弄圆,要么不适用于所有情况.
当我搜索"Python truncate float"时,这是谷歌的最高结果,这个概念非常简单,值得更好的答案.我同意Hatchkins的说法,使用该decimal模块是这样做的pythonic 方式,所以我在这里给出一个函数,我认为这个函数正确地回答了问题,并且在所有情况下都能正常工作.
作为旁注,通常,小数值不能用二进制浮点变量精确表示(参见此处讨论),这就是我的函数返回一个字符串的原因.
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()
Run Code Online (Sandbox Code Playgroud)
小智 6
>>> from math import floor
>>> floor((1.23658945) * 10**4) / 10**4
1.2365
Run Code Online (Sandbox Code Playgroud)
#除以 10**所需位数
如果你喜欢一些数学魔法,这适用于 +ve 数字:
>>> v = 1.923328437452
>>> v - v % 1e-3
1.923
Run Code Online (Sandbox Code Playgroud)