round() to nearest .05 ?

Bengt Richter bokr at oz.net
Mon Nov 15 23:54:15 CET 2004


On Mon, 15 Nov 2004 22:52:42 +0200, tertius <terti at mighty.co.za> wrote:

>Hi,
>
>I'm trying to round my float total to the nearest .05 cents.
Nearest which way? IWT 2.28 is nearer 2.30 than 2.25 ;-)
ISTM you are rounding _down_ to the nearest nickel. So you want to
drop fractional nickels. Which int will do if you calculate the number
of nickels. Then you can divide by 20. to get dollars again
>
>12.01    should produce 12.00
>  0.14    should produce 0.10
>  2.28          "        2.25
>703.81         "        703.80
>
>"%.02f"%100.0099 produces 100.01 (which I know is right)
>No combination of round and/or "%.02f" works for me.
>
>What's the best way to get there? Should I write a function to manage my 
>rounding or is there a simpler/better way?

One way, just to play with subclassing float for constrained initial value:

 >>> values = [12.01, 0.14, 2.28, 703.81]
 >>> class Nickels(float):
 ...     def __new__(cls, val):
 ...         return float.__new__(cls, int(val*20.0)/20.)
 ...     def __repr__(self): return '<Nickels %.2f>'%float(self)
 ...
 >>> [Nickels(v) for v in values]
 [<Nickels 12.00>, <Nickels 0.10>, <Nickels 2.25>, <Nickels 703.80>]
 >>> for value in values: print '%8.2f => %8.2f'%(value,Nickels(value))
 ...
    12.01 =>    12.00
     0.14 =>     0.10
     2.28 =>     2.25
   703.81 =>   703.80

but it's probably silly compared to

 >>> def roundnickel(dollars): return int(dollars*20.0)/20.0
 ...
 >>> for value in values: print '%8.2f => %8.2f'%(value, roundnickel(value))
 ...
    12.01 =>    12.00
     0.14 =>     0.10
     2.28 =>     2.25
   703.81 =>   703.80

What do you want to do for negative numbers? int "rounds" towards zero.

 >>> for value in -.01,.01,-.09,.09: print '%8.2f => %8.2f'%(value, roundnickel(value))
 ...
    -0.01 =>     0.00
     0.01 =>     0.00
    -0.09 =>    -0.05
     0.09 =>     0.05

BTW, if you wanted to use the class with all float operators, you'd have
to define the methods one way or another (there's some sneaky ways, but I think
the class is just a side trip ;-)

 >>> Nickels(.09)
 <Nickels 0.05>
 >>> Nickels(.09) + .01
 0.060000000000000005

Being a subclass of float, python figured out how to coerce Nickels
to float for the addition. If we add an adding method, we get

 >>> Nickels.__add__ = lambda self,other: Nickels(float(self)+ float(other))
 >>> Nickels(.09) + .01
 <Nickels 0.05>
 >>> Nickels(.09) + .06
 <Nickels 0.10>

too much work ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list