在Python中截断浮动

问题:在Python中截断浮动

我想从浮点数中删除数字,以使小数点后的位数固定不变,例如:

1.923328437452 -> 1.923

我需要作为字符串输出到另一个函数,而不是打印。

我也想忽略丢失的数字,而不是四舍五入。

I want to remove digits from a float to have a fixed number of digits after the dot, like:

1.923328437452 → 1.923

I need to output as a string to another function, not print.

Also I want to ignore the lost digits, not round them.


回答 0

首先,该功能针对那些只需要复制和粘贴代码的人:

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使用Python程序编写,则编译器将使用IEEE浮点格式将其编码为位序列(假定为64位浮点数)

0011111111010011001100110011001100110011001100110011001100110011

这是最接近0.3的值,可以准确地表示为IEEE浮点数。但是,如果您0.29999999999999998使用Python程序编写代码,则编译器会将其转换为完全相同的value。在一种情况下,您希望将其截断为(一位)0.3,而在另一种情况下,您希望将其截断为0.2,但是Python只能给出一个答案。这是Python的根本限制,或者实际上是任何没有延迟评估的编程语言。截断功能只能访问存储在计算机内存中的二进制值,而不能访问您实际在源代码中键入的字符串。1个

如果再次使用IEEE 64位浮点格式将位序列解码回十进制数,则会得到

0.2999999999999999888977697537484345957637...

因此0.2即使您可能并不想这样做,也会提出一个幼稚的实现。有关浮点表示错误的更多信息,请参见Python教程

使用非常接近整数但又有意不等于该整数的浮点值是非常罕见的。因此,在截断时,从所有可能对应于内存值的“十进制”十进制表示中选择是最有意义的。Python 2.7及更高版本(但不是3.0)提供了一种完善的算法来执行此操作,我们可以通过默认的字符串格式设置操作来访问该算法

'{}'.format(f)

唯一需要注意的是,如果数字足够大或足够小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)

此处使用的精度位数并不重要,它只需要足够大即可确保在字符串转换中执行的任何舍入操作都不会将值“累加”到其漂亮的十进制表示形式。我认为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

将其通用化以处理您传入变量的情况似乎是一个失败的原因,因为您必须在程序的执行过程中向后追溯,直到找到为变量赋值的浮点文字。如果有一个。大多数变量将从用户输入或数学表达式初始化,在这种情况下,二进制表示就全部存在。

First, the function, for those who just want some copy-and-paste code:

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

This is valid in Python 2.7 and 3.1+. For older versions, it’s not possible to get the same “intelligent rounding” effect (at least, not without a lot of complicated code), but rounding to 12 decimal places before truncation will work much of the time:

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

Explanation

The core of the underlying method is to convert the value to a string at full precision and then just chop off everything beyond the desired number of characters. The latter step is easy; it can be done either with string manipulation

i, p, d = s.partition('.')
'.'.join([i, (d+'0'*n)[:n]])

or the decimal module

str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN))

The first step, converting to a string, is quite difficult because there are some pairs of floating point literals (i.e. what you write in the source code) which both produce the same binary representation and yet should be truncated differently. For example, consider 0.3 and 0.29999999999999998. If you write 0.3 in a Python program, the compiler encodes it using the IEEE floating-point format into the sequence of bits (assuming a 64-bit float)

0011111111010011001100110011001100110011001100110011001100110011

This is the closest value to 0.3 that can accurately be represented as an IEEE float. But if you write 0.29999999999999998 in a Python program, the compiler translates it into exactly the same value. In one case, you meant it to be truncated (to one digit) as 0.3, whereas in the other case you meant it to be truncated as 0.2, but Python can only give one answer. This is a fundamental limitation of Python, or indeed any programming language without lazy evaluation. The truncation function only has access to the binary value stored in the computer’s memory, not the string you actually typed into the source code.1

If you decode the sequence of bits back into a decimal number, again using the IEEE 64-bit floating-point format, you get

0.2999999999999999888977697537484345957637...

so a naive implementation would come up with 0.2 even though that’s probably not what you want. For more on floating-point representation error, see the Python tutorial.

It’s very rare to be working with a floating-point value that is so close to a round number and yet is intentionally not equal to that round number. So when truncating, it probably makes sense to choose the “nicest” decimal representation out of all that could correspond to the value in memory. Python 2.7 and up (but not 3.0) includes a sophisticated algorithm to do just that, which we can access through the default string formatting operation.

'{}'.format(f)

The only caveat is that this acts like a g format specification, in the sense that it uses exponential notation (1.23e+4) if the number is large or small enough. So the method has to catch this case and handle it differently. There are a few cases where using an f format specification instead causes a problem, such as trying to truncate 3e-10 to 28 digits of precision (it produces 0.0000000002999999999999999980), and I’m not yet sure how best to handle those.

If you actually are working with floats that are very close to round numbers but intentionally not equal to them (like 0.29999999999999998 or 99.959999999999994), this will produce some false positives, i.e. it’ll round numbers that you didn’t want rounded. In that case the solution is to specify a fixed precision.

'{0:.{1}f}'.format(f, sys.float_info.dig + n + 2)

The number of digits of precision to use here doesn’t really matter, it only needs to be large enough to ensure that any rounding performed in the string conversion doesn’t “bump up” the value to its nice decimal representation. I think sys.float_info.dig + n + 2 may be enough in all cases, but if not that 2 might have to be increased, and it doesn’t hurt to do so.

In earlier versions of Python (up to 2.6, or 3.0), the floating point number formatting was a lot more crude, and would regularly produce things like

>>> 1.1
1.1000000000000001

If this is your situation, if you do want to use “nice” decimal representations for truncation, all you can do (as far as I know) is pick some number of digits, less than the full precision representable by a float, and round the number to that many digits before truncating it. A typical choice is 12,

'%.12f' % f

but you can adjust this to suit the numbers you’re using.


1Well… I lied. Technically, you can instruct Python to re-parse its own source code and extract the part corresponding to the first argument you pass to the truncation function. If that argument is a floating-point literal, you can just cut it off a certain number of places after the decimal point and return that. However this strategy doesn’t work if the argument is a variable, which makes it fairly useless. The following is presented for entertainment value only:

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

Generalizing this to handle the case where you pass in a variable seems like a lost cause, since you’d have to trace backwards through the program’s execution until you find the floating-point literal which gave the variable its value. If there even is one. Most variables will be initialized from user input or mathematical expressions, in which case the binary representation is all there is.


回答 1

round(1.923328437452, 3)

请参阅有关标准类型的Python文档。您需要向下滚动才能进入取整功能。本质上,第二个数字表示要舍入到小数点后位数。

round(1.923328437452, 3)

See Python’s documentation on the standard types. You’ll need to scroll down a bit to get to the round function. Essentially the second number says how many decimal places to round it to.


回答 2

的结果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'

The result of round is a float, so watch out (example is from Python 2.6):

>>> round(1.923328437452, 3)
1.923
>>> round(1.23456, 3)
1.2350000000000001

You will be better off when using a formatted string:

>>> "%.3f" % 1.923328437452
'1.923'
>>> "%.3f" % 1.23456
'1.235'

回答 3

n = 1.923328437452
str(n)[:4]
n = 1.923328437452
str(n)[:4]

回答 4

在我的Python 2.7提示符下:

>>> int(1.923328437452 * 1000)/1000.0 1.923

At my Python 2.7 prompt:

>>> int(1.923328437452 * 1000)/1000.0 1.923


回答 5

简单的python脚本-

n = 1.923328437452
n = float(int(n * 1000))
n /=1000

Simple python script –

n = 1.923328437452
n = float(int(n * 1000))
n /=1000

回答 6

def trunc(num, digits):
   sp = str(num).split('.')
   return '.'.join([sp[0], sp[1][:digits]])

这应该工作。它应该为您提供所需的截断。

def trunc(num, digits):
   sp = str(num).split('.')
   return '.'.join([sp[0], sp[1][:digits]])

This should work. It should give you the truncation you are looking for.


回答 7

真正的pythonic方式是

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)

更新资料

通常问题不在于截断浮点数本身,而在于舍入不正确使用浮点数。

例如:int(0.7*3*100)/100 == 2.09

如果您被迫使用浮点数(例如,使用来加速代码numba),则最好使用美分作为价格的“内部表示”:(70*3 == 210)并乘/除输入/输出。

The truely pythonic way of doing it is

from decimal import *

with localcontext() as ctx:
    ctx.rounding = ROUND_DOWN
    print Decimal('1.923328437452').quantize(Decimal('0.001'))

or shorter:

from decimal import Decimal as D, ROUND_DOWN

D('1.923328437452').quantize(D('0.001'), rounding=ROUND_DOWN)

Update

Usually the problem is not in truncating floats itself, but in the improper usage of float numbers before rounding.

For example: int(0.7*3*100)/100 == 2.09.

If you are forced to use floats (say, you’re accelerating your code with numba), it’s better to use cents as “internal representation” of prices: (70*3 == 210) and multiply/divide the inputs/outputs.


回答 8

因此,针对这个问题给出的许多答案完全是错误的。它们要么将浮点取整(而不是截断),要么不能在所有情况下都起作用。

当我搜索“ Python truncate float”时,这是Google的最高结果,这个概念非常简单,应该得到更好的答案。我同意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()

So many of the answers given for this question are just completely wrong. They either round up floats (rather than truncate) or do not work for all cases.

This is the top Google result when I search for ‘Python truncate float’, a concept which is really straightforward, and which deserves better answers. I agree with Hatchkins that using the decimal module is the pythonic way of doing this, so I give here a function which I think answers the question correctly, and which works as expected for all cases.

As a side-note, fractional values, in general, cannot be represented exactly by binary floating point variables (see here for a discussion of this), which is why my function returns a string.

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

回答 9

我做了这样的事情:

from math import trunc


def truncate(number, decimals=0):
    if decimals < 0:
        raise ValueError('truncate received an invalid value of decimals ({})'.format(decimals))
    elif decimals == 0:
        return trunc(number)
    else:
        factor = float(10**decimals)
        return trunc(number*factor)/factor

I did something like this:

from math import trunc


def truncate(number, decimals=0):
    if decimals < 0:
        raise ValueError('truncate received an invalid value of decimals ({})'.format(decimals))
    elif decimals == 0:
        return trunc(number)
    else:
        factor = float(10**decimals)
        return trunc(number*factor)/factor

回答 10

你可以做:

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]

You can do:

def truncate(f, n):
    return math.floor(f * 10 ** n) / 10 ** n

testing:

>>> f=1.923328437452
>>> [truncate(f, n) for n in range(5)]
[1.0, 1.9, 1.92, 1.923, 1.9233]

回答 11

如果您喜欢一些数学运算,则适用于+ ve数:

>>> v = 1.923328437452
>>> v - v % 1e-3
1.923

If you fancy some mathemagic, this works for +ve numbers:

>>> v = 1.923328437452
>>> v - v % 1e-3
1.923

回答 12

使用pandas df时,这对我有用

import math
def truncate(number, digits) -> float:
    stepper = 10.0 ** digits
    return math.trunc(stepper * number) / stepper

df['trunc'] = df['float_val'].apply(lambda x: truncate(x,1))
df['trunc']=df['trunc'].map('{:.1f}'.format)

When using a pandas df this worked for me

import math
def truncate(number, digits) -> float:
    stepper = 10.0 ** digits
    return math.trunc(stepper * number) / stepper

df['trunc'] = df['float_val'].apply(lambda x: truncate(x,1))
df['trunc']=df['trunc'].map('{:.1f}'.format)

回答 13

只是想提一下旧的“用floor()制作round()”技巧

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

Just wanted to mention that the old “make round() with floor()” trick of

round(f) = floor(f+0.5)

can be turned around to make floor() from round()

floor(f) = round(f-0.5)

Although both these rules break around negative numbers, so using it is less than ideal:

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

回答 14

int(16.5); 这将给出16的整数值,即trunc,将无法指定小数,但是您可以通过以下方式做到这一点

import math;

def trunc(invalue, digits):
    return int(invalue*math.pow(10,digits))/math.pow(10,digits);

int(16.5); this will give an integer value of 16, i.e. trunc, won’t be able to specify decimals, but guess you can do that by

import math;

def trunc(invalue, digits):
    return int(invalue*math.pow(10,digits))/math.pow(10,digits);

回答 15

这是一个简单的方法:

def truncate(num, res=3):
    return (floor(num*pow(10, res)+0.5))/pow(10, res)

对于num = 1.923328437452,则输出1.923

Here is an easy way:

def truncate(num, res=3):
    return (floor(num*pow(10, res)+0.5))/pow(10, res)

for num = 1.923328437452, this outputs 1.923


回答 16

def trunc(f,n):
  return ('%.16f' % f)[:(n-16)]
def trunc(f,n):
  return ('%.16f' % f)[:(n-16)]

回答 17

通用简单的功能:

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

A general and simple function to use:

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

回答 18

在python 3中有一个简单的解决方法。在哪里剪切我定义了一个帮助变量decPlace以使其易于适应。

f = 1.12345
decPlace= 4
f_cut = int(f * 10**decPlace) /10**decPlace

输出:

f = 1.1234

希望能帮助到你。

There is an easy workaround in python 3. Where to cut I defined with an help variable decPlace to make it easy to adapt.

f = 1.12345
decPlace= 4
f_cut = int(f * 10**decPlace) /10**decPlace

Output:

f = 1.1234

Hope it helps.


回答 19

def precision(value, precision):
    """
    param: value: takes a float
    param: precision: int, number of decimal places
    returns a float
    """
    x = 10.0**precision
    num = int(value * x)/ x
    return num
precision(1.923328437452, 3)

1.923

def precision(value, precision):
    """
    param: value: takes a float
    param: precision: int, number of decimal places
    returns a float
    """
    x = 10.0**precision
    num = int(value * x)/ x
    return num
precision(1.923328437452, 3)

1.923


回答 20

简短易用的变体

def truncate_float(value, digits_after_point=2):
    pow_10 = 10 ** digits_after_point
    return (float(int(value * pow_10))) / pow_10

>>> truncate_float(1.14333, 2)
>>> 1.14

>>> truncate_float(1.14777, 2)
>>> 1.14


>>> truncate_float(1.14777, 4)
>>> 1.1477

Short and easy variant

def truncate_float(value, digits_after_point=2):
    pow_10 = 10 ** digits_after_point
    return (float(int(value * pow_10))) / pow_10

>>> truncate_float(1.14333, 2)
>>> 1.14

>>> truncate_float(1.14777, 2)
>>> 1.14


>>> truncate_float(1.14777, 4)
>>> 1.1477

回答 21

我认为大多数答案都太复杂了,这又如何呢?

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

Most answers are way too complicated in my opinion, how about this?

digits = 2  # Specify how many digits you want

fnum = '122.485221'
truncated_float = float(fnum[:fnum.find('.') + digits + 1])

>>> 122.48

Simply scanning for the index of ‘.’ and truncate as desired (no rounding). Convert string to float as final step.

Or in your case if you get a float as input and want a string as output:

fnum = str(122.485221)  # convert float to string first
truncated_float = fnum[:fnum.find('.') + digits + 1]  # string output

回答 22

>>> floor((1.23658945) * 10**4) / 10**4
1.2365

除以10 **所需位数

>>> floor((1.23658945) * 10**4) / 10**4
1.2365

# divide and multiply by 10**number of desired digits


回答 23

使用numpy.round

import numpy as np
precision = 3
floats = [1.123123123, 2.321321321321]
new_float = np.round(floats, precision)

use numpy.round

import numpy as np
precision = 3
floats = [1.123123123, 2.321321321321]
new_float = np.round(floats, precision)

回答 24

足够简单以适合列表理解的东西,没有库或其他外部依赖项。对于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']

当然,这里会进行四舍五入(即四位数),但是在某些时候四舍五入是不可避免的。如果截断和舍入之间的过渡是相关的,那么下面是一个更好的示例:

>>> 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']

奖励:删除右边的零

>>> 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']

Something simple enough to fit in a list-comprehension, with no libraries or other external dependencies. For Python >=3.6, it’s very simple to write with f-strings.

The idea is to let the string-conversion do the rounding to one more place than you need and then chop off the last digit.

>>> 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']

Of course, there is rounding happening here (namely for the fourth digit), but rounding at some point is unvoidable. In case the transition between truncation and rounding is relevant, here’s a slightly better example:

>>> 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']

Bonus: removing zeros on the right

>>> 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']

回答 25

我看来,此处给出的核心思想是解决此问题的最佳方法。不幸的是,它获得的票数较少,而后来获得更多票数的答案尚未完成(如评论中所观察)。希望以下实现为截断提供了一个简短完整的解决方案。

def trunc(num, digits):
    l = str(float(num)).split('.')
    digits = min(len(l[1]), digits)
    return (l[0]+'.'+l[1][:digits])

应该处理在这里这里找到的所有极端情况。

The core idea given here seems to me to be the best approach for this problem. Unfortunately, it has received less votes while the later answer that has more votes is not complete (as observed in the comments). Hopefully, the implementation below provides a short and complete solution for truncation.

def trunc(num, digits):
    l = str(float(num)).split('.')
    digits = min(len(l[1]), digits)
    return (l[0]+'.'+l[1][:digits])

which should take care of all corner cases found here and here.


回答 26

我也是python新手,在使用了一些零碎的内容后,我提供了2美分

print str(int(time.time()))+str(datetime.now().microsecond)[:3]

str(int(time.time()))将时间段作为整数,并将其转换为字符串,并与… str(datetime.now()。microsecond)[:3]结合使用,它仅返回微秒,转换字符串并截断为前3个字符

Am also a python newbie and after making use of some bits and pieces here, I offer my two cents

print str(int(time.time()))+str(datetime.now().microsecond)[:3]

str(int(time.time())) will take the time epoch as int and convert it to string and join with… str(datetime.now().microsecond)[:3] which returns the microseconds only, convert to string and truncate to first 3 chars


回答 27

# value  value to be truncated
# n  number of values after decimal

value = 0.999782
n = 3
float(int(value*1en))*1e-n
# value  value to be truncated
# n  number of values after decimal

value = 0.999782
n = 3
float(int(value*1en))*1e-n

回答 28

如果您是说打印时,那么以下方法应该起作用:

print '%.3f' % number

If you mean when printing, then the following should work:

print '%.3f' % number