问题:格式化浮点数而不尾随零

如何格式化浮点数,使其不包含尾随零?换句话说,我希望结果字符串尽可能短。

例如:

3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"

How can I format a float so that it doesn’t contain trailing zeros? In other words, I want the resulting string to be as short as possible.

For example:

3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"

回答 0

我,我会做的('%f' % x).rstrip('0').rstrip('.')-保证定点格式,而不是科学记数法,等等等等呀,还不如光滑和优雅的%g,但是,它的工作原理(我不知道如何强制%g从不使用科学记数法; -)。

Me, I’d do ('%f' % x).rstrip('0').rstrip('.') — guarantees fixed-point formatting rather than scientific notation, etc etc. Yeah, not as slick and elegant as %g, but, it works (and I don’t know how to force %g to never use scientific notation;-).


回答 1

您可以%g用来实现以下目的:

'%g'%(3.140)

或者,对于Python 2.6或更高版本:

'{0:g}'.format(3.140)

g原因(除其他外)

从有效数中删除不重要的尾随零,并且如果在其后没有剩余数字,则也删除小数点。

You could use %g to achieve this:

'%g'%(3.140)

or, for Python 2.6 or better:

'{0:g}'.format(3.140)

From the : g causes (among other things)

insignificant trailing zeros [to be] removed from the significand, and the decimal point is also removed if there are no remaining digits following it.


回答 2

尝试最简单且可能最有效的方法呢?方法normalize()删除所有最右边的尾随零。

from decimal import Decimal

print (Decimal('0.001000').normalize())
# Result: 0.001

适用于Python 2Python 3

– 更新 –

@ BobStein-VisiBone指出的唯一问题是,数字10、100、1000 …将以指数形式显示。可以使用以下函数轻松解决此问题:

from decimal import Decimal


def format_float(f):
    d = Decimal(str(f));
    return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()

What about trying the easiest and probably most effective approach? The method normalize() removes all the rightmost trailing zeros.

from decimal import Decimal

print (Decimal('0.001000').normalize())
# Result: 0.001

Works in Python 2 and Python 3.

— Updated —

The only problem as @BobStein-VisiBone pointed out, is that numbers like 10, 100, 1000… will be displayed in exponential representation. This can be easily fixed using the following function instead:

from decimal import Decimal


def format_float(f):
    d = Decimal(str(f));
    return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()

回答 3

在查看了几个类似问题的答案之后,这似乎是我的最佳解决方案:

def floatToString(inputValue):
    return ('%.15f' % inputValue).rstrip('0').rstrip('.')

我的推理:

%g 没有摆脱科学计数法。

>>> '%g' % 0.000035
'3.5e-05'

小数点后15位似乎可以避免发生奇怪的行为,并且可以满足我的许多要求。

>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'

我本可以使用format(inputValue, '.15f').来代替'%.15f' % inputValue,但是会慢一些(〜30%)。

我本可以使用Decimal(inputValue).normalize(),但这也有一些问题。例如,速度要慢很多(〜11x)。我还发现,尽管它具有很高的精度,但使用时仍然会遭受精度损失normalize()

>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')

最重要的是,我仍然会转换为Decimal从,float这样您最终可以得到的不是您输入的数字。我认为Decimal当算术停留在DecimalDecimal使用字符串初始化时效果最佳。

>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')

我确信Decimal.normalize()可以使用上下文设置将的精度问题调整为所需的值,但是考虑到速度已经很慢并且不需要可笑的精度,而且无论如何我仍然会从浮点数转换而失去精度,我没有认为这不值得追求。

我不担心可能的“ -0”结果,因为-0.0是有效的浮点数,并且无论如何它都可能很少出现,但是由于您确实提到要保持字符串结果尽可能短,因此总是可以以很少的额外速度成本使用额外的条件。

def floatToString(inputValue):
    result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
    return '0' if result == '-0' else result

After looking over answers to several similar questions, this seems to be the best solution for me:

def floatToString(inputValue):
    return ('%.15f' % inputValue).rstrip('0').rstrip('.')

My reasoning:

%g doesn’t get rid of scientific notation.

>>> '%g' % 0.000035
'3.5e-05'

15 decimal places seems to avoid strange behavior and has plenty of precision for my needs.

>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'

I could have used format(inputValue, '.15f'). instead of '%.15f' % inputValue, but that is a bit slower (~30%).

I could have used Decimal(inputValue).normalize(), but this has a few issues as well. For one, it is A LOT slower (~11x). I also found that although it has pretty great precision, it still suffers from precision loss when using normalize().

>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')

Most importantly, I would still be converting to Decimal from a float which can make you end up with something other than the number you put in there. I think Decimal works best when the arithmetic stays in Decimal and the Decimal is initialized with a string.

>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')

I’m sure the precision issue of Decimal.normalize() can be adjusted to what is needed using context settings, but considering the already slow speed and not needing ridiculous precision and the fact that I’d still be converting from a float and losing precision anyway, I didn’t think it was worth pursuing.

I’m not concerned with the possible “-0” result since -0.0 is a valid floating point number and it would probably be a rare occurrence anyway, but since you did mention you want to keep the string result as short as possible, you could always use an extra conditional at very little extra speed cost.

def floatToString(inputValue):
    result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
    return '0' if result == '-0' else result

回答 4

这是一个对我有用的解决方案。这是一个混合的解决方案通过多网并使用新的.format() 语法

for num in 3, 3., 3.0, 3.1, 3.14, 3.140:
    print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))

输出

3
3
3
3.1
3.14
3.14

Here’s a solution that worked for me. It’s a blend of the solution by PolyMesh and use of the new .format() syntax.

for num in 3, 3., 3.0, 3.1, 3.14, 3.140:
    print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))

Output:

3
3
3
3.1
3.14
3.14

回答 5

您可以简单地使用format()实现此目的:

format(3.140, '.10g') 其中10是您想要的精度。

You can simply use format() to achieve this:

format(3.140, '.10g') where 10 is the precision you want.


回答 6

>>> str(a if a % 1 else int(a))
>>> str(a if a % 1 else int(a))

回答 7

尽管格式化可能是大多数Python方式,但这里是使用该more_itertools.rstrip工具的替代解决方案。

import more_itertools as mit


def fmt(num, pred=None):
    iterable = str(num)
    predicate = pred if pred is not None else lambda x: x in {".", "0"}
    return "".join(mit.rstrip(iterable, predicate))

assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"

该数字将转换为字符串,该字符串将除去满足谓词的结尾字符。函数定义fmt不是必需的,但是在这里用于测试所有通过的断言。注意:它适用于字符串输入并接受可选谓词。

另请参阅有关此第三方库的详细信息more_itertools

While formatting is likely that most Pythonic way, here is an alternate solution using the more_itertools.rstrip tool.

import more_itertools as mit


def fmt(num, pred=None):
    iterable = str(num)
    predicate = pred if pred is not None else lambda x: x in {".", "0"}
    return "".join(mit.rstrip(iterable, predicate))

assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"

The number is converted to a string, which is stripped of trailing characters that satisfy a predicate. The function definition fmt is not required, but it is used here to test assertions, which all pass. Note: it works on string inputs and accepts optional predicates.

See also details on this third-party library, more_itertools.


回答 8

如果您可以将3.和3.0都显示为“ 3.0”,那么这是一种非常简单的方法,可将浮点数表示形式的零右移:

print("%s"%3.140)

(感谢@ellimilial指出exceptions)

If you can live with 3. and 3.0 appearing as “3.0”, a very simple approach that right-strips zeros from float representations:

print("%s"%3.140)

(thanks @ellimilial for pointing out the exceptions)


回答 9

您可以选择使用QuantiPhy软件包。通常,在处理带有单位和SI比例因子的数字时,会使用QuantiPhy,但它具有多种不错的数字格式设置选项。

    >>> from quantiphy import Quantity

    >>> cases = '3 3. 3.0 3.1 3.14 3.140 3.14000'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:p}')
          3 -> 3
         3. -> 3
        3.0 -> 3
        3.1 -> 3.1
       3.14 -> 3.14
      3.140 -> 3.14
    3.14000 -> 3.14

在这种情况下,它将不使用电子符号:

    >>> cases = '3.14e-9 3.14 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:,p}')
    3.14e-9 -> 0
       3.14 -> 3.14
     3.14e9 -> 3,140,000,000

您可能更喜欢的替代方法是使用SI比例因子,也许使用单位。

    >>> cases = '3e-9 3.14e-9 3 3.14 3e9 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case, 'm')
    ...    print(f'{case:>7} -> {q}')
       3e-9 -> 3 nm
    3.14e-9 -> 3.14 nm
          3 -> 3 m
       3.14 -> 3.14 m
        3e9 -> 3 Gm
     3.14e9 -> 3.14 Gm

Using the QuantiPhy package is an option. Normally QuantiPhy is used when working with numbers with units and SI scale factors, but it has a variety of nice number formatting options.

    >>> from quantiphy import Quantity

    >>> cases = '3 3. 3.0 3.1 3.14 3.140 3.14000'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:p}')
          3 -> 3
         3. -> 3
        3.0 -> 3
        3.1 -> 3.1
       3.14 -> 3.14
      3.140 -> 3.14
    3.14000 -> 3.14

And it will not use e-notation in this situation:

    >>> cases = '3.14e-9 3.14 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:,p}')
    3.14e-9 -> 0
       3.14 -> 3.14
     3.14e9 -> 3,140,000,000

An alternative you might prefer is to use SI scale factors, perhaps with units.

    >>> cases = '3e-9 3.14e-9 3 3.14 3e9 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case, 'm')
    ...    print(f'{case:>7} -> {q}')
       3e-9 -> 3 nm
    3.14e-9 -> 3.14 nm
          3 -> 3 m
       3.14 -> 3.14 m
        3e9 -> 3 Gm
     3.14e9 -> 3.14 Gm

回答 10

OP希望删除多余的零,并使生成的字符串尽可能短。

我发现%g指数格式会缩短结果字符串的大小和数值。对于不需要指数表示法的值(例如128.0)来说,问题来了,它既不是很大也不是很小。

这是将数字格式化为短字符串的一种方法,仅当Decimal.normalize创建的字符串过长时才使用%g指数表示法。这可能不是最快的解决方案(因为它确实使用Decimal.normalize)

def floatToString (inputValue, precision = 3):
    rc = str(Decimal(inputValue).normalize())
    if 'E' in rc or len(rc) > 5:
        rc = '{0:.{1}g}'.format(inputValue, precision)        
    return rc

inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0]

outputs = [floatToString(i) for i in inputs]

print(outputs)

# ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10']

OP would like to remove superflouous zeros and make the resulting string as short as possible.

I find the %g exponential formatting shortens the resulting string for very large and very small values. The problem comes for values that don’t need exponential notation, like 128.0, which is neither very large or very small.

Here is one way to format numbers as short strings that uses %g exponential notation only when Decimal.normalize creates strings that are too long. This might not be the fastest solution (since it does use Decimal.normalize)

def floatToString (inputValue, precision = 3):
    rc = str(Decimal(inputValue).normalize())
    if 'E' in rc or len(rc) > 5:
        rc = '{0:.{1}g}'.format(inputValue, precision)        
    return rc

inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0]

outputs = [floatToString(i) for i in inputs]

print(outputs)

# ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10']

回答 11

对于float,您可以使用以下代码:

def format_float(num):
    return ('%i' if num == int(num) else '%s') % num

测试一下:

>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'

对于十进制,请在此处查看解决方案:https : //stackoverflow.com/a/42668598/5917543

For float you could use this:

def format_float(num):
    return ('%i' if num == int(num) else '%s') % num

Test it:

>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'

For Decimal see solution here: https://stackoverflow.com/a/42668598/5917543


回答 12

"{:.5g}".format(x)

我用它来格式化浮点数以尾随零。

"{:.5g}".format(x)

I use this to format floats to trail zeros.


回答 13

答案是:

import numpy

num1 = 3.1400
num2 = 3.000
numpy.format_float_positional(num1, 3, trim='-')
numpy.format_float_positional(num2, 3, trim='-')

输出“ 3.14”和“ 3”

trim='-' 删除尾随零和小数。

Here’s the answer:

import numpy

num1 = 3.1400
num2 = 3.000
numpy.format_float_positional(num1, 3, trim='-')
numpy.format_float_positional(num2, 3, trim='-')

output “3.14” and “3”

trim='-' removes both the trailing zero’s, and the decimal.


回答 14

使用宽度足够大的%g,例如’%.99g’。对于任何较大的数字,它将以定点表示法打印。

编辑:这不起作用

>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'

Use %g with big enough width, for example ‘%.99g’. It will print in fixed-point notation for any reasonably big number.

EDIT: it doesn’t work

>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'

回答 15

您可以这样使用max()

print(max(int(x), x))

You can use max() like this:

print(max(int(x), x))


回答 16

您可以通过以下大多数pythonic方式实现该目标:

python3:

"{:0.0f}".format(num)

You can achieve that in most pythonic way like that:

python3:

"{:0.0f}".format(num)

回答 17

处理%f,您应该放

%.2f

,其中:.2f == .00浮动。

例:

打印“价格:%.2f”%价格[产品]

输出:

价格:1.50

Handling %f and you should put

%.2f

, where: .2f == .00 floats.

Example:

print “Price: %.2f” % prices[product]

output:

Price: 1.50


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。