-1

So I'm trying to round a float to two decimal places, which works fine if there's more, but otherwise breaks.

Anyways here's what I have:

    income=input("Enter your expected annual income in USD.")
    if floatcheck(income) == True:
        Income=float(income)
        income=str(round(Income, 2))

So I'm trying to either: always have it be two decimal places (which works fine if there is more than that, but if it is a whole number it will actually add a .0 which looks weird with currency), or have whole numbers not have any decimals at all. I tried a ton of different things like making it round to 3 and hoping that would add another 0, and adding +0.00 Oh, and I already defined floatcheck above as:

def floatcheck(str):
    try:
        float(str)
        return True
    except ValueError:
        return False

Anyways I assume this is super easy to solve, but I cant seem to figure it out anywhere.

khelwood
  • 55,782
  • 14
  • 81
  • 108
Aceplante
  • 119
  • 4
  • 4
    Rounding just changes the value of a float; it has no direct effect on how many decimal places are used to display that float. You want `string formatting`, instead - `income = "%.2f" % Income` would be one way of writing this. – jasonharper Sep 10 '21 at 23:47
  • 4
    Don't use `float`s for currency, use either `int`s or `decimal`s, I suggest `decimal.Decimal`. There are serious issues with floating point arithmetic and currency (or any other fixed point number) in the [docs](https://docs.python.org/3/tutorial/floatingpoint.html#floating-point-arithmetic-issues-and-limitations). – Michael Ruth Sep 10 '21 at 23:48

3 Answers3

2

You want formatted numbers, check out this explanation of format specifiers

>>> num = 2
>>> f"{num:.2f}"
'2.00'
>>> num = 2.3455
>>> f"{num:.2f}"
'2.35'
C. Ramseyer
  • 2,322
  • 2
  • 18
  • 22
0

Try using decimal and round as shown below. I have added float to look at it for comparison with the decimal function

    from decimal import *
    n = ['20','20.25','45','35','56.43','20.25','20.00','78.906']
    for i in n:
        print(round(float(i),2),'......',round(Decimal(i),2))

Output:

20.0 ...... 20.00
20.25 ...... 20.25
45.0 ...... 45.00
35.0 ...... 35.00
56.43 ...... 56.43
20.25 ...... 20.25
20.0 ...... 20.00
78.91 ...... 78.91
Sonia Samipillai
  • 590
  • 5
  • 15
  • You shouldn't be passing `float`s to `Decimal`. You need to start with strings or ints – juanpa.arrivillaga Sep 11 '21 at 00:02
  • edited to pass it as a string to Decimal function – Sonia Samipillai Sep 11 '21 at 00:19
  • *no, not like this `Decimal(str(i))`*. The point is that the input needs to be in the form of a string. No floats. – juanpa.arrivillaga Sep 11 '21 at 00:21
  • 1
    @juanpa.arrivillaga Do you have an example where `Decimal(str(i))` goes wrong? – no comment Sep 11 '21 at 00:23
  • 1
    @juanpa.arrivillaga It [seems to do pretty well](https://tio.run/##TYxLCsMwDET3PsXsYkOgTrsphex6j2ASpxXUHxQR6Oldkw9UuzdvRvkr7xRv98ylzJwCJj9ScB9QyIkFzx2VmhODQBHs4svrq7XmoVCPcOnRWbvBROxHQX/uNJktX8kNi/CfqFTlbjNTFH10WjRYFzTt8cyU8gM). – no comment Sep 11 '21 at 00:29
  • 1
    @don'ttalkjustcode no, but it relies fundamentally on an implementation detail which is the float-to-string conversion algorithm. The algorithm is chosen to produce the *shortest representation* that would allow an accurate "round trip". Previously, it used to jsut be "round to the 17th digit", now there's a smarter algorithm (I don't recall the name). The point is, this is an implementation detail. – juanpa.arrivillaga Sep 11 '21 at 00:30
  • 1
    @juanpa.arrivillaga Hmm, ok, I thought that that "shortest representation for roundtrip" is guaranteed by the specs, but I can't find it in the docs other than [in the tutorial](https://docs.python.org/3/tutorial/floatingpoint.html), which I'm not sure counts as guarantee (don't know whether the tutorial uses "CPython implementation detail" boxes like the docs do elsewhere). – no comment Sep 11 '21 at 00:37
0

Take the following example:

print(round(2.665, 2))
print(round(2.675, 2))

Output

2.67
2.67

Note: The behavior of round() for floats can be surprising. Notice round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it's a result of the fact that most decimal fractions can't be represented exactly as a float.

When the decimal 2.675 is converted to a binary floating-point number, it's again replaced with a binary approximation, whose exact value is:

2.67499999999999982236431605997495353221893310546875

Due to this, it is rounded down to 2.67.

If you're in a situation where precision is needed, consider using the decimal module, which is designed for floating-point arithmetic:

from decimal import Decimal

# normal float
income= 2.675
print(round(income, 2))

# using decimal.Decimal (passed float as string for precision)
income= Decimal('2.675')
print(round(income, 2))


Output

2.67
2.68

Philip Mutua
  • 6,016
  • 12
  • 41
  • 84