Decimales a 2 lugares por dinero en Python 3

¿Cómo consigo que mis decimales se queden en 2 lugares para representar el dinero usando el módulo decimal ?

He establecido la precisión, y casi todo lo demás, y me encontré con el fracaso.

Cuando trabaje con dinero, generalmente querrá limitar la precisión lo más tarde posible para que cosas como la multiplicación no acumulen errores de redondeo. En Python 2 y 3, puedes .quantize() un Decimal con la precisión que desees:

 unit_price = decimal.Decimal('8.0107') quantity = decimal.Decimal('0.056') price = unit_price * quantity cents = decimal.Decimal('.01') money = price.quantize(cents, decimal.ROUND_HALF_UP) 

La respuesta aceptada es correcta en su mayoría, excepto la constante que se debe utilizar para la operación de redondeo. Debe usar ROUND_HALF_UP lugar de ROUND_05UP para las operaciones de divisas. Según los documentos :

decimal. ROUND_HALF_UP

Redondea al más cercano con los lazos que salen de cero

decimal. ROUND_05UP

Redondear fuera de cero si el último dígito después del redondeo hacia cero hubiera sido 0 o 5; De lo contrario, redondea hacia cero.

Usar ROUND_05UP solo se redondearía (para números positivos) si el número en el lugar de las centésimas era un 5 o un 0, lo que no es correcto para el cálculo de moneda.

Aquí hay unos ejemplos:

 >>> from decimal import Decimal, ROUND_05UP, ROUND_HALF_UP >>> cents = Decimal('0.01') >>> Decimal('1.995').quantize(cents, ROUND_HALF_UP) Decimal('2.00') # Correct >>> Decimal('1.995').quantize(cents, ROUND_05UP) Decimal('1.99') # Incorrect >>> Decimal('1.001').quantize(cents, ROUND_HALF_UP) Decimal('1.00') # Correct >>> Decimal('1.001').quantize(cents, ROUND_05UP) Decimal('1.01') # Incorrect 

Los falsos progtwigdores creen sobre el dinero:

  • Los valores monetarios se pueden almacenar o representar como un punto flotante.
  • Todas las monedas tienen una precisión decimal de 2.
  • Todas las monedas definidas ISO 4217 tienen una precisión decimal.
  • Todas las monedas están definidas en ISO 4217.
  • El oro no es una moneda.
  • Mi sistema nunca tendrá que manejar monedas oscuras con más de 2 decimales.
  • Los valores de punto flotante están bien si el valor monetario de las transacciones es “pequeño”.
  • Un sistema siempre manejará la misma moneda (por lo tanto, no persistimos la moneda, solo el valor monetario).
  • Almacenar valores monetarios como enteros largos con signo hará que sea más fácil trabajar con ellos, simplemente multiplíquelos por 100 una vez que se haya realizado toda la aritmética.
  • Los clientes nunca se quejarán de mis métodos de redondeo.
  • Cuando convierto mi aplicación del idioma X al idioma Y, no tengo que verificar si el comportamiento de redondeo es el mismo.
  • Al cambiar la moneda A por la moneda B, el tipo de cambio se vuelve irrelevante después de la transacción.

Una forma de resolver esto es almacenar los valores monetarios en centavos como enteros y solo convertirlos a la representación decimal cuando se imprimen valores. Esto se llama aritmética de punto fijo .

 >>> decimal.getcontext().prec = 2 >>> d = decimal.Decimal('2.40') >>> d/17 Decimal('0.14') 

Solo tiene que establecer la precisión en 2 (la primera línea) y todos ellos no usarán más de 2 decimales.

Sólo para comparación:

 >>> 2.4 / 17 0.1411764705882353