universal method for working with currency with no rounding, two decimal places, and thousands separators

user1063287 picture user1063287 · Mar 27, 2013 · Viewed 8.4k times · Source

i am a newbie learning python (2.7.3) and was given a simple exercise calculating costs but soon became interested in really being able to control or understand the 'exactness' of the results that were being produced. if i use the calculator on my computer i get the results i think i am after (ie they seem very specific), but if i use python it seems i have to be very exact about how i add formatting information to the values being used and printed.

the short version of my question is:

is there an easy solution that i can use whenever i am working with currency that returns:

  • two decimal places to the right of the decimal point
  • does no rounding up (ie basically just 'truncates' whatever is to the right of the second place after the decimal point)
  • adds thousand separators if necessary

i've been mucking around with the interpreter (see code below) testing variations if anyone wants to run it to see the results and variations.

thank you.

# basic entry - both are seen as integers
print 'A:  ', 7/3

# test by printing out the types
print 'B:  ', type(7)
print 'C:  ', type(3)

# this is not necessary as they are already integers
print 'D:  ', int(7/3)

# converts the result of 7/3 into a floating number
print 'E:  ', float(7/3)

# defines the float version of 7 by the float version of 3
print 'F:  ', float(7) / float(3)

# coverts the results of the above into a string and assigns to variable
string_var = str(float(7) / float(3))

# print the string
print 'G:  ', string_var

# prints 4 characters of the string, but returns two decimal places
print 'H:  ', string_var[:4]

string_var = str(25.8545678888)

# prints 5 characters of the string, but returns two decimal places
print 'I:  ',string_var[:5]

# import the locale module
import locale
# sets to user's default settings (don't know what empty quotes are)
locale.setlocale( locale.LC_ALL, '' )

#set an arbitrary float number to a variable
float_var = 25.859

# apply locale.currency formatting
print 'J:  ',locale.currency(float_var)

# import the decimal module
from decimal import *

# the decimal version of the variable
print 'K:  ',Decimal(float_var)

# divide the decimal version by 2
print 'L:  ',Decimal(float_var) / 2

# divide the decimal version by the decimal verson of 2
print 'M:  ', Decimal(float_var) / Decimal(2)

# change decimal precision to 6
getcontext().prec = 6

# note there is no change in this value as precision only applied to
# result of calculations, see
#http://stackoverflow.com/questions/6483440/python-decimal-precision
print 'N:  ', Decimal(float_var)

# the following equation returns decimal precision to 6 (6 characters displayed)
print 'O:  ', Decimal(float_var) / 2

# example of 6 characters printed, not decimal places
# to the right of the decimal
print 'P:  ', Decimal(55550) / 130

# if you want to control places to the right of the decimal
# displayed without rounding and show thousand separators if
# necessary ?

EDIT:

thanks all for replies, this is the solution i went with which is sort of a mix of all replies:

def make_it_money(number):
    """
    always:
    - shows 2 decimal places
    - shows thousands separator if necessary
    - retains integrity of original var for later re-use
    - allows for concise calling
    """
    import math
    return '$' + str(format(math.floor(number * 100) / 100, ',.2f'))

# tests

var1 = 25.867
var2 = 25.864
var3 = 25.865
var4 = 2500.7869

print make_it_money(var1)
print make_it_money(var2)
print make_it_money(var3)
print make_it_money(var4)

Answer

Martijn Pieters picture Martijn Pieters · Mar 27, 2013

Use the format() function to format float or Decimal types:

format(value, ',.2f')

which results in:

>>> format(12345.678, ',.2f')
'12,345.68'

The , adds a comma as a thousands separator in the output.

You generally do not want to indiscriminately round down after floating point or Decimal calculations. If you feel you have to do that anyway, do so explicitly before formatting:

>>> import math
>>> format(math.floor(12345.678 * 100) / 100, ',.2f')
'12,345.67'