Fred's water bill

Mathematica, 83 76 69 bytes

1.015{3.8476,.2456(b=Boole)[#>10],.8186b[#>27],51/1015}&~Array~#~Total~2~Round~.01&

Anonymous function that constructs an array of the three tiers in the first column plus the LIRA and PBOP represented as an arbitrary-precision number in the fourth column. The whole thing is multiplied by 1.015 and all elements of the array are summed and rounded to .01. Since 51/1015*1.015 will be the desired 0.051 the output is exactly as precise, as the specification in OP.

A shorter solution, in 76 bytes, as I have suggested in my comment under the Perl solution

{3.956314,.249284(b=Boole)[#>10],.830879b[#>27]}&~Array~#~Total~2~Round~.01&

where 1.015 is factored into the prices from the start and then the LIRA and PBOP is added on top of the first tier.

73 bytes (but I'm reluctant to update my byte-count since this is quite close to the straightforward Perl solution):

69 bytes -- ah what the heck, golfing took some effort too.

.01Round[395.6314#+{24.9284,83.0879}.(UnitStep[#-1]#&/@{#-10,#-27})]&

EDIT regarding floating point error
The first three iterations of my answer are indeed exact in their decimal representation, since all coefficients involved have terminating decimal representations. However, since the coefficients are explicitly floats, stored in binary and having non-terminating binary representations, large enough inputs will start to accumulate errors in the least-significant digits of the binary representation. I would guess, when the float is so large, that it fits only 3-4 digits to the right of the decimal point, we can expect errors of around 1 cent. See below for an exact answer.

72 bytes, somewhat-immune to float inaccuracies

.01Round[{3956314,249284,830879}.(UnitStep[#-1]#&)/@(#-{0,10,27})/10^4]&

The multiplication by the leading .01 is done at the very last step. Until that point, all calculation are done with integers. This means, that if the .01 is omitted, there will be an exact result, but expressed in cents, rather than dollars. Of course, the multiplication by a float converts the entire thing to a float, and, as mentioned, it needs to be small enough to fit into 64 bits and still be accurate to .01.


05AB1E, 64 58 51 bytes

0T27¹)vy¹‚ï{0è})¥•_ÄÄ™wu24@•2'.:7ô)ø€PO¹"5.1"*+ïTn/

Explained

0T27¹)                                               # list of price brackets
      vy¹‚ï{0è})                                     # min of each with input
                ¥                                    # calculate deltas to get amounts within each bracket
                 •_ÄÄ™wu24@•2'.:7ô                   # list of price rates with CPUC included
                                  )ø                 # zip with amounts for each rate
                                    €PO              # multiply amounts by their rates and sum
                                       ¹"5.1"*+      # add LIRA/PBOP
                                               ïTn/  # round to 2 decimals

Try it online

Tags:

Math

Code Golf