views:

783

answers:

3

I need it to show:

49 as 49.00

and:

54.9 as 54.90

I need it to have no limitations on length (ie, a trillion dollars), but still always have just 2 decimal places so that it is formatted like money (without the dollar sign):

eg, 4898489.00

Is this efficient, BTW?

+4  A: 

The String Formatting section of the Python documentation contains the answer you're looking for. In short:

"%0.2f" % (num,)

Some examples:

>>> "%0.2f" % 10
'10.00'
>>> "%0.2f" % 1000
'1000.00'
>>> "%0.2f" % 10.1
'10.10'
>>> "%0.2f" % 10.120
'10.12'
>>> "%0.2f" % 10.126
'10.13'
Travis Bradshaw
There's no need for the `0` after the `%`, and no need to wrap `num` in a `tuple`.
Actually, wrapping num in a tuple is a coding convention to prevent a duck typing error on arguments during string formatting. It doesn't have any effect in this case with a float conversion, but it prevents an unexpected type error when converting to strings. Consider `r = 1; "%s" % r; r = (1, 2); "%s" % r` versus `r = 1; "%s" % (r,); r = (1,2 ); "%s" % (r,)`. As such, most sophisticated coding styles in python use the unconditional tuple now (and Python 3 deprecated the entire method of string formatting as error prone).
Travis Bradshaw
Also, as a guy with a math background, "naked" decimal notation is ugly. The leading 0 doesn't hurt anything and looks better. :)
Travis Bradshaw
But it's not a number, it's a format string
Ben James
Aesthetically no different. Most importantly, the 0 is the default value, anyway. There's absolutely no harm in providing the default if it makes for aesthetically pleasing code. It's interesting how many developers choose not to (can't?) differentiate between correctness and style. :/
Travis Bradshaw
+4  A: 

You can use the string formatting operator as so:

f = 49
x = "%.2f" % f  # x is now the string "49.00"

I'm not sure what you mean by "efficient" -- this is almost certainly not the bottleneck of your application. If your program is running slowly, profile it first to find the hot spots, and then optimize those.

Adam Rosenfield
+3  A: 

I suppose you're probably using the Decimal objects from the decimal module? (If you need exactly two digits of precision beyond the decimal point with arbitrarily large numbers, you definitely should be, and that's what your question's title suggests...)

If so, the FAQ section of the docs has a question/answer pair which may be useful for you:

Q. In a fixed-point application with two decimal places, some inputs have many places and need to be rounded. Others are not supposed to have excess digits and need to be validated. What methods should be used?

A. The quantize() method rounds to a fixed number of decimal places. If the Inexact trap is set, it is also useful for validation:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

The next question reads

Q. Once I have valid two place inputs, how do I maintain that invariant throughout an application?

If you need the answer to that (along with lots of other useful information), see the aforementioned section of the docs. Also, if you keep your Decimals with two digits of precision beyond the decimal point (meaning as much precision as is necessary to keep all digits to the left of the decimal point and two to the right of it and no more...), then converting them to strings with str will work fine:

str(Decimal('10'))
# -> '10'
str(Decimal('10.00'))
# -> '10.00'
str(Decimal('10.000'))
# -> '10.000'
Michał Marczyk
Oh, forgot to mention efficiency in the answer... but I guess I'm no expert anyway. I see no reason why it would be particularly inefficient to keep a fixed number of "fractional digits" around -- although any operations performed on the numbers might necessitate a rounding operation on the result to bring it in line with the requirements... For efficiency's sake, this should probably be done as infrequently as possible -- like just prior to serialisation / printing out for the user.
Michał Marczyk