8
\$\begingroup\$

Fred is a quasi-friendly guy, but in reality he is mean.

Because of this, Fred lives alone in a small apartment in Los Altos, CA. Fred is so mean because he is very particular about water. He, therefore, needs your help with figuring out what his water bill is.

Your job is to write a function or program that returns his water bill given the amount of water used as input (which is always an integer).

Water consumption comes in tiers. This means that there are ranges of prices depending on the amount of water.

These are the tiers, their prices, and the amounts of water they correspond to:

Tier I
   First 10 Ccf: $3.8476/Ccf
Tier II
   Next 17 Ccf: $4.0932/Ccf
Tier III
   All subsequent water: $4.9118/Ccf

For n hundreds of cubic feet (Ccf), there are the following additional charges as well:

CPUC fee: 1.5% of above charges
LIRA quantity surcharge: $0.047*n
PBOP amoritization surcharge: $0.004*n

The sum of the Tier I, Tier II, Tier III, CPUC, LIRA, and PBOP fees is the total water bill. This sum you should either return or print to the console rounded to two decimal places.

Here are two examples:

Input: 15
... Calculations which you do not need to output but here to help explain:
Tier I: 10*3.8476 = 38.476
Tier II: (15-10)*4.0932 = 20.466
Tier III: 0*4.9118 = 0
Tiers sum: 58.942
CPUC: 1.5% of 58.942 = 0.88413
LIRA: 0.047*15 = 0.705
PBOP: 0.004*15 = 0.06
Total sum: 58.942 + 0.88413 + 0.705 + 0.06 = 60.59113
...
Output: 60.59

Input: 100
... Calculations which you do not need to output but here to help explain:
Tier I: 10*3.8476 = 38.476
Tier II: 17*4.0932 = 69.5844
Tier III: (100-10-17)*4.9118 = 358.5614
Tiers sum: 466.6218
CPUC: 1.5% of  = 6.999327
LIRA: 0.047*100 = 4.7
PBOP: 0.004*100 = 0.4
Total sum: 478.721127
...
Output: 478.72

This is code golf so shortest code in bytes wins!

\$\endgroup\$
7
  • \$\begingroup\$ Please check that my edit matches your intent. \$\endgroup\$
    – msh210
    Jun 28, 2016 at 6:33
  • \$\begingroup\$ Yeah thanks @msh210, that's much clearer than what I had \$\endgroup\$
    – Daniel
    Jun 28, 2016 at 6:35
  • \$\begingroup\$ If you are willing to waste reputation on down-voting could you at least please explain why? \$\endgroup\$
    – Daniel
    Jun 28, 2016 at 7:02
  • \$\begingroup\$ @Dopapp Some people just might not like the challenge. Nothing you can do there. For what it's worth, downvoting challenges doesn't subtract from the downvoter's reputation - only answers. \$\endgroup\$
    – user45941
    Jun 28, 2016 at 8:23
  • \$\begingroup\$ Do we have to handle non-integer n? \$\endgroup\$ Jun 28, 2016 at 13:38

9 Answers 9

2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

Pyth, 55 41 bytes

.R+s*Vv.",9t¬®Ï0NwÝ"lMcUQ,T27*.051Q2

The code contains unprintable characters, so here's a xxd hexdump.

00000000: 2e52 2b73 2a56 762e 222c 3904 1874 c2ac  .R+s*Vv.",9..t..
00000010: c2ae c280 c293 c38f 301c 4e77 c39d 226c  ........0.Nw.."l
00000020: 4d63 5551 2c54 3237 2a2e 3035 3151 32    McUQ,T27*.051Q2

Explanation

  1. ."…" is a packed string that contains 3.8476,4.0932,4.9118.
  2. v evaluates that to the tuple (3.8476, 4.0932, 4.9118). These are the tiers' prices multiplied with CPUC added.
  3. UQ generates the range 0n-1.
  4. c,T27 splits that range at indices 10 and 27, with extra empty lists in the end if the range is too short.
  5. lM finds the length of each part, giving the amount of water for each tier.
  6. *V multiplies that by the tuple from step 2 to get the prices for the tiers.
  7. s sums the results.
  8. +*Q.051 adds the input multiplied by 0.051, i.e. LIRA + PBOP.
  9. .R2 rounds the result to 2 decimals.

Try it online.

\$\endgroup\$
1
\$\begingroup\$

Perl 5, 73 bytes

The obvious solution. 72 bytes, plus 1 for -ne instead of -e.

printf'%.2f',$_*3.956314+($_-10)*($_>10)*.249284+($_-27)*($_>27)*.830879

Saved 5 bytes thanks to LLlAMnYP. Thanks!

\$\endgroup\$
4
  • \$\begingroup\$ Re my previous comment, this edit turns out to actually eliminate the floating point errors you had in the original. \$\endgroup\$
    – LLlAMnYP
    Jun 28, 2016 at 8:08
  • \$\begingroup\$ @LLlAMnYP, surely any approximation must have an error for high enough value of the input. Hopefully that bound is high enough that the OP doesn't care (because it's an unreasonable amount of water for a single person's residence). \$\endgroup\$
    – msh210
    Jun 28, 2016 at 14:51
  • \$\begingroup\$ @msh210 You don't know Fred's story!! \$\endgroup\$
    – cat
    Jun 28, 2016 at 15:07
  • \$\begingroup\$ No, because you are multiplying and adding numbers with finite decimal representation. Of course, when you represent them as floats, they may have a not so great binary representation. You can then expect errors when the float representation allows for only 3-4 digits to the right of the decimal. My "bonus-answer" at the bottom of my post overcomes this, using integers until the very last step (which converts cents to dollars). If I were to omit multiplication by .01, it would remain accurate so long as the integer can be stored. \$\endgroup\$
    – LLlAMnYP
    Jun 28, 2016 at 16:29
1
\$\begingroup\$

Oracle SQL 11.2, 151 bytes

SELECT ((DECODE(SIGN(:1-10),1,10,:1)*3.8476)+(DECODE(SIGN(:1-27),1,17,:1-10)*4.0932)+(DECODE(SIGN(:1-27),-1,0,:1-27)*4.9118))*1.015+:1*0.051 FROM DUAL;

Un-golfed

SELECT ((DECODE(SIGN(:1-10),1,10,:1)*3.8476)+
       (DECODE(SIGN(:1-27),1,17,:1-10)*4.0932)+
       (DECODE(SIGN(:1-27),-1,0,:1-27)*4.9118))*1.015+
       :1*0.051
FROM DUAL
\$\endgroup\$
3
  • \$\begingroup\$ Get rid of the space between SELECT and ((DECODE to save one byte. Save more 10 bytes using a named table! 7 by removing the colons and using a one char column name plus three using a one char table name. \$\endgroup\$ Jun 28, 2016 at 12:51
  • \$\begingroup\$ @Giacomo Garabello : removing the space always returns null with toad and returns an error with SQLDeveloper. The create table script adds more than 10 bytes. \$\endgroup\$
    – Jeto
    Jun 28, 2016 at 13:17
  • \$\begingroup\$ you don't have to add the creation script... look here \$\endgroup\$ Jun 28, 2016 at 13:44
1
\$\begingroup\$

JavaScript ES6, 77 bytes

x=>(x>27?(x-27)*4.985477+109.681:(x>10?(x-10)*4.1546+39.053:x*3.9053))+.051*x

Un-golfed

f = x => {
  if (x > 27) {
    res = (x - 27) * 4.985477 + 109.681306
  } else if (x > 10) {
    res = (x - 10) * 4.154598 + 39.05314
  } else {
    res = x * 3.905314
  }
  return res + 0.051 * x
}

I factored in the LIRA and PBOP coefficients. The extra 1.5% gets added at the end.

Probably not the most efficient solution in terms of golfing but somewhat different from the Perl one.

Floating point error should occur with larger numbers and can be fixed by adding 1 or 2 extra bytes to each coefficient.

f=x=>(x>27?(x-27)*4.985477+109.681:(x>10?(x-10)*4.1546+39.053:x*3.9053))+.051*x

console.log(f(15))
console.log(f(100))
console.log(f(200000))

\$\endgroup\$
1
  • \$\begingroup\$ You don't need the ()s around the x>10?:, ?: associates right-to-left. I think you can also save some bytes by multiplying out the parentheticals e.g. (x-10)*4.154598+39.05314 equals x*4.154598-41.54598+39.05314 equals x*4.154598-2.49284. \$\endgroup\$
    – Neil
    Jul 4, 2016 at 12:18
1
\$\begingroup\$

R, 52 bytes

approxfun(c(0,10,27,10^6),c(0,39.56,111.06,5036475))

Try it online!

Generates a linear approximation function, based on my previous answer's values at 0,10,27 and 10^6. The catch: the upper limit on the input is 10^6.

approxfun (with ecdf, stepfun, splinefun, etc.) is one of the many nice features of R.

\$\endgroup\$
0
\$\begingroup\$

VBA, 88 bytes

Function W(V):W=Round(.051*V+.203*(V*19.238-(V-10)*(V>10)*1.228-(V-27)*(V>27)*4.093),2)
 

The base rate and higher use differential rates have been multiplied by 5, and the CPUC fee multiplier divided by 5 (0.203).

The VB editor will add an End Function line, which is why the terminal line feed is included.

\$\endgroup\$
0
\$\begingroup\$

Pyth - 58 51 bytes

.Rs+*Bs*V++m3.8476Tm4.0932 17m4.9118Qm1Q.015*.051Q2

Test Suite.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.