简体   繁体   中英

floating point formatting in python 3

I have been researching a bit but i could not find a easy solution to do the following behavior. I want to round a float to a specific place and get the result as a string (raw string preferably). Specificly the digit I want to be rounded might be left from the decimal point and I would like the result to not include the decimalpoint in that case.

Example

to_string_(x: float, prec: int): ...
# Results should look like:
>>> to_string_(1.2345e2, 3)
123.450
>>> to_string_(1.2345e2, 2)
123.45
>>> to_string_(1.2345e2, 1)
123.5
>>> to_string_(1.2345e2, 0)
123
>>> to_string_(1.2345e2, -1)
120
>>> to_string_(1.2345e2, -2)
100
>>> to_string_(1.2345e2, -3)
0
>>> to_string_(1.2345e-1, 0)
0
>>> to_string_(1.2345e-1, 1)
0.1
>>> to_string_(1.2345e-1, 6)
0.123450

I'm aware the

def to_string(x: float, prec: int):
    return ((f"%.{prec}f") % x)

would work in some of the examples, but not with negative prec. Thank you in advance.

Once the values are negative, it might be easier to convert your value to an integer and then truncate it to the appropriate precision. You can get the resolution of the number by taking 10 ** (-prec) when prec<=0 Example:

def to_string(x: float, prec: int):
    if prec > 0:
        return f"{x:.{prec}f}"
    else:
        res = 10 ** (-prec)
        return str(int(x / res) * res)


for i in range(-3, 4)[::-1]:
    print(i, ":", to_string(1.2345e2, i))
3 : 123.450
2 : 123.45
1 : 123.5
0 : 123
-1 : 120
-2 : 100
-3 : 0

Your own solution works fine if you do the rounding differently for a negative value.

def to_string(x: float, prec: int):
    if prec < 0:
        x = round(x, prec)
        prec = 0
    return ((f"%.{prec}f") % x)

Note that both the round function and f-strings may round differently than you expect. They use a mode called half to even (also known as Banker's rounding) which affects how numbers ending in 5 will round. For example both f'{1.5:.0f}' and f'{2.5:.0f}' will produce '2' because 2 is even and 3 is not.

Here is a solution using the decimal module. Note, if you can help it, you may want to use decimal.Decimal objects to begin with instead of float (passing either a string or a tuple but not a float to the constructor) for the most typical expected behavior. You can specify the rounding type you want as well (look at the decimal docs for how to do this):

>>> from decimal import Decimal as _Decimal
>>> def to_string_(x: float, prec: int) -> str:
...     d = _Decimal(x).quantize(_Decimal((0, (1,), -prec)))
...     return f"{d:f}"
...
>>> to_string_(1.2345e2, 3)
'123.450'
>>> to_string_(1.2345e2, 2)
'123.45'
>>> to_string_(1.2345e2, 1)
'123.5'
>>> to_string_(1.2345e2, 0)
'123'
>>> to_string_(1.2345e2, -1)
'120'
>>> to_string_(1.2345e2, -2)
'100'
>>> to_string_(1.2345e2, -3)
'0'
>>> to_string_(1.2345e-1, 0)
'0'
>>> to_string_(1.2345e-1, 1)
'0.1'
>>> to_string_(1.2345e-1, 6)
'0.123450'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM