15
\$\begingroup\$

Gringotts isn't just a vault, but a reputable financial institution and wizards need loans too. Since you don't want to be screwed over by the Gringotts goblins, you decided it would be a good idea to write a program to calculate interest. Interest is compounded only yearly.

Your task is to calculate total owed amount after interest given the principal, interest rate, and time (whole years), operating in whole denominations of wizard money, rounding down to the nearest whole Knut. There are 29 Bronze Knuts in a Silver Sickle and 17 Sickles in a Gold Galleon.

Example

Loan taken out:
 23 Knuts
 16 Sickles
103 Galleons
@ 7.250%
For 3 years

Total owed after interest:
 24 Knuts
  4 Sickles
128 Galleons

Notes and Rules

  • Input and output may be in any convenient format. You must take in Knuts, Sickles, Galleons, interest rate, and time. All but interest rate will be whole numbers. The interest rate is in increments of 0.125%.
  • Input money is not guaranteed to be canonical (i.e. you can have 29 or more Knuts and 17 or more Sickles.)
  • Output must be the canonical representation. (i.e. less than 29 Knuts and less than 17 Sickles)
  • Totals owed, up to 1,000 Galleons, should be accurate to within 1 Knut per year of interest when compared with arbitrary precision calculations.
    • You may round down after each year of interest or only at the end. Reference calculations can take this into account for accuracy checks.

Happy golfing!

\$\endgroup\$
  • 4
    \$\begingroup\$ Can we take the interest rate as a decimal instead of a percentage? (e.g., 0.0725 instead of 7.25) \$\endgroup\$ – Shaggy Mar 2 at 19:44
  • \$\begingroup\$ @Shaggy I would also like to know this \$\endgroup\$ – senox13 Mar 2 at 21:01
  • \$\begingroup\$ If the loan is exactly 1 Knut, and the interest is 99% per year, and the term is 1 year, should the result be "1 Knut" or "2 Knuts"? \$\endgroup\$ – Chas Brown Mar 2 at 23:34
  • \$\begingroup\$ In other words, please clarify the mathematical meaning of the phrase rounding down \$\endgroup\$ – senox13 Mar 2 at 23:38
  • 1
    \$\begingroup\$ @ChasBrown: 1 Knut. Truncate/floor function to the nearest whole Knut. \$\endgroup\$ – Beefster Mar 3 at 4:16

16 Answers 16

6
\$\begingroup\$

R, 70 62 bytes

function(d,i,y)(x=d%*%(a=c(1,29,493))*(1+i)^y)%/%a%%c(29,17,x)

Try it online!

Takes input as d: deposit in knuts, sickles, galleons; i: interest rate as decimal; y: years. Outputs final deposit in knuts, sickles, galleons. Thanks to @Giuseppe for using matrix multiplication to save some bytes (and pointing out how to avoid the need to wrap at 1e99).

\$\endgroup\$
  • \$\begingroup\$ I don't know R; what does having them wrap around win you? \$\endgroup\$ – dfeuer Mar 4 at 17:53
  • \$\begingroup\$ @dfeuer they’re taken mod 1e99, so if your galleons get that high they’ll drop to zero \$\endgroup\$ – Nick Kennedy Mar 4 at 21:40
  • \$\begingroup\$ What I'm wondering is what you gain by taking them mod 1e99. \$\endgroup\$ – dfeuer Mar 4 at 21:52
  • \$\begingroup\$ Most R functions are vectorised. In this case, I'm passing the output through the %% function, which is mod. Ideally, I'd like to leave the galleons alone, but taking a number mod infinity returns NaN, and so I've just used a really large number (but one that is small in bytes). The alternatives I've come up with are longer (e.g. [tio.run/##JYrLCsIwEEV/… Try it online!]) \$\endgroup\$ – Nick Kennedy Mar 4 at 22:26
  • \$\begingroup\$ @NickKennedy you could do 9e99 as well...Also, you can golf down to 63 bytes \$\endgroup\$ – Giuseppe Mar 4 at 22:50
4
\$\begingroup\$

Python 3.8 (pre-release), 75 74 71 bytes

-1 bytes thanks to @EmbodimentofIgnorance
-3 bytes thanks to @xnor

This takes Knuts, Sickles, and Galleons as ints, interest as a float (decimal, not percentage), and years as an int. It returns a tuple containing the number after interest of Knuts, Sickles, and Galleons, respectively.

lambda K,S,G,R,Y:((k:=int((K+G*493+S*29)*(1+R)**Y))%29,k//29%17,k//493)

Usage:

>>> print(I(23,16,103,0.0725,3))
(24, 4, 128)

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Good catch. Updating answer \$\endgroup\$ – senox13 Mar 2 at 21:58
  • \$\begingroup\$ The question says operating in whole denominations of wizard money, rounding down. I took rounding down to mean chop off everything after the decimal point. Using the header definitely sounds like an easier way to do things. I'll do that for future posts, thanks \$\endgroup\$ – senox13 Mar 2 at 22:55
  • \$\begingroup\$ That sounds a lot more like "truncating" than "rounding"; but I have asked the OP for clarification (because nit-picking is the name of the game here at PPCG :) ). \$\endgroup\$ – Chas Brown Mar 2 at 23:35
  • \$\begingroup\$ I don't disagree with you, that's just the meaning I've always seen used for rounding down, because you always round to the integer below your result. Otherwise it's just normal rounding. Letting OP decide is a good idea \$\endgroup\$ – senox13 Mar 2 at 23:41
  • \$\begingroup\$ FYI, a useful trick to make anonymous functions testable on TIO is to put I\= in the header like this. Also, it looks like k//29//17 can be k//493. \$\endgroup\$ – xnor Mar 3 at 0:28
3
\$\begingroup\$

APL+WIN, 37 28 26 bytes

⌊a⊤((a←0 17 29)⊥⎕)×(1+⎕)*⎕

2 bytes saved thanks to lirtosiast

Try it online! Courtesy of Dyalog Classic

Explanation:

(1+⎕)*⎕ prompts for years followed by decimal interest rate and calculates
         compounding multiplier

((a←0 17 29)⊥⎕) prompts for Galleons, Sickles and Knuts and converts to Knuts

⌊a⊤ converts back to Galleons, Sickles and Knuts and floor 
    after applying compound interest. 
\$\endgroup\$
  • \$\begingroup\$ ⌊a⊤(⎕⊥⍨a←0 17 29)×⎕*⍨1+⎕ for 24? \$\endgroup\$ – lirtosiast Mar 3 at 6:32
  • \$\begingroup\$ @lirtosiast Thanks but I am afraid my ancient APL+WIN interpreter does not have the ⍨ function. By all means submit this as your own APL solution. \$\endgroup\$ – Graham Mar 3 at 6:45
  • \$\begingroup\$ @lirtosiast Thanks again I have taken the 2 bytes resulting from the assignment to a. \$\endgroup\$ – Graham Mar 3 at 7:05
3
\$\begingroup\$

Perl 6, 47 bytes

((1+*)*** *(*Z*1,29,493).sum+|0).polymod(29,17)

Try it online!

I'm surprised I managed to get this into an anonymous Whatever lambda! Especially the part where it's more *s than anything else. Takes input as interest rate (e.g. 0.0725), years, [Knuts, Sickles, Galleons] and returns a list of currencies in the same order.

Explanation:

 (1+*)           # Add one to the interest rate
      ***        # Raise to the power of the year
          *      # And multiply by
           (*Z*1,29,493).sum      # The number of Knuts in the input
                            +|0   # And floor it
(                              ).polymod(29,17)   # Get the modulos after divmoding by 29 and 17
\$\endgroup\$
  • \$\begingroup\$ I'm surprised you didn't come up with a way to also get the number of Knuts/Sickles/Galleons also to fit into whatevers. Then it'd just be eh, like ************************* ;-) \$\endgroup\$ – guifa Mar 7 at 3:18
  • \$\begingroup\$ @guifa The Whatevers are the inputs, so there can only really be 3 of them (though I can split up the currency input for some more *s but more bytes). The rest of the *s are from multiplication (*) and exponentials (**) \$\endgroup\$ – Jo King Mar 7 at 3:23
  • \$\begingroup\$ I meant if you got the conversion rates (the 29/17 number) into them too. But of course it was a joke because you need to use those numbers more than once. Sorry if my humor didn't go through \$\endgroup\$ – guifa Mar 7 at 3:26
2
\$\begingroup\$

Jelly, 29 bytes

“¢×ø‘©×\
÷ȷ2‘*⁵×÷¢S×¢d®U1¦Ṫ€Ḟ

A full program accepting arguments: rate; [Galleons, Sickles, Knuts]; years.
Prints [Galleons, Sickles, Knuts].

Try it online!

Floors at the end of the entire term.
÷ȷ2 may be removed if we may accept the rate as a ratio rather than a percentage.

How?

“¢×ø‘©×\ - Link 1 multipliers: no arguments
“¢×ø‘    - list of code-age indices = [1,17,29]
     ©   - (copy this to the register for later use)
       \ - reduce by:
      ×  -   multiplication  = [1,17,493]

÷ȷ2‘*⁵×÷¢S×¢d®U1¦Ṫ€Ḟ - Main Link
 ȷ2                  - 10^2 = 100
÷                    - divide = rate/100
   ‘                 - increment = 1+rate/100
     ⁵               - 5th command line argument (3rd input) = years
    *                - exponentiate = (1+rate/100)^years --i.e. multiplicand
      ×              - multiply (by the borrowed amounts)
        ¢            - call last Link as a nilad
       ÷             - divide (all amounts in Galleons)
         S           - sum (total Galleons owed)
           ¢         - call last Link as a nilad
          ×          - multiply (total owed in each of Galleons, Sickles, Knuts)
             ®       - recall from register = [1,17,29]
            d        - divmod (vectorises) = [[G/1, G%1], [S/17, S^17], [K/17, K%17]]
              U1¦    - reverse first one = [[G%1, G/1], [S/17, S%17], [K/17, K%17]]
                 Ṫ€  - tail €ach = [G/1, S%17, K%17]
                   Ḟ - floor (vectorises)
\$\endgroup\$
2
\$\begingroup\$

Intel 8087 FPU assembly, 86 bytes

d9e8 d906 7f01 dec1 8b0e 8301 d9e8 d8c9 e2fc df06 7901 df06 8701 df06
7b01 df06 8501 df06 7d01 dec9 dec1 dec9 dec1 dec9 9bd9 2e89 01df 0687
01df 0685 01d9 c1de c9d9 c2d9 f8d8 f2df 1e7b 01d8 fadf 1e7d 01d9 c9d9
f8df 1e79 01

Unassembled and documented:

; calculate P+I of loan from wizard
; input:
;   G: number of Galleons (mem16)
;   S: number of Sickles (mem16)
;   K: number of Knuts (mem16)
;   R: interest rate (float)
;   T: time in years (mem16)
;   GS: Galleons to Sickles exchange rate (mem16)
;   SK: Sickles to Knuts exchange rate (mem16)
; output:
;   G: number of Galleons (mem16)
;   S: number of Sickles (mem16)
;   K: number of Knuts (mem16)
WIZ_INT_CALC    MACRO   G, S, K, R, T, GS, SK
                LOCAL   LOOP_EXP
                    ; - calculate interet rate factor
    FLD1            ; load 1
    FLD   R         ; load interest rate
    FADD            ; ST = rate + 1
    MOV   CX, T     ; Exponent is count for loop
    FLD1            ; load 1 into ST as initial exponent value
LOOP_EXP:           ; loop calculate exponent
    FMUL  ST,ST(1)  ; multiply ST = ST * ST(1)
    LOOP  LOOP_EXP
                    ; - convert demonimations to Knuts
    FILD  K         ; load existing Knuts
    FILD  SK        ; load Sickles to Knuts rate 
    FILD  S         ; load existing Sickles
    FILD  GS        ; load Galleons-to-Sickles exchange rate
    FILD  G         ; load existing Galleons
    FMUL            ; multiply galleons to get sickles
    FADD            ; add existing sickles
    FMUL            ; multiply sickles to get knuts
    FADD            ; add existing knuts
    FMUL            ; calculate P+I (P in Knuts * Interest factor)
                    ; - redistribute demonimations to canonical form
    FLDCW  FRD      ; put FPU in round-down mode
    FILD   SK       ; load Sickles to Knuts rate
    FILD   GS       ; load Galleons-to-Sickles exchange rate
    FLD    ST(1)    ; copy Galleons-to-Sickles exchange rate to stack for later
    FMUL            ; multiply to get Galleons-to-Knuts rate
    FLD    ST(2)    ; push original total Knuts from ST(2) into ST (lost by FPREM)
    FPREM           ; get remainder
    FDIV   ST,ST(2) ; divide remainder to get number of Sickles
    FISTP  S        ; store Sickles to S
    FDIVR  ST,ST(2) ; divide to get number of Galleons
    FISTP  G        ; store Galleons to G
    FXCH            ; swap ST, ST(1) for FPREM
    FPREM           ; get remainder to get number of Knuts
    FISTP  K        ; store Knuts to K
        ENDM

Implemented as a MACRO (basically a function), this is non-OS-specific machine-code using only the Intel 80x87 FPU / math co-processor for calculation.

Example test program with output:

    FINIT           ; reset FPU

    WIZ_INT_CALC    G,S,K,R,T,GS,SK     ; do the "Wizardy"

    MOV  AX, K      ; display Knuts
    CALL OUTDEC     ; generic decimal output routine
    CALL NL         ; CRLF

    MOV  AX, S      ; display Sickles
    CALL OUTDEC     ; generic decimal output routine
    CALL NL         ; CRLF

    MOV  AX, G      ; display Galleons
    CALL OUTDEC     ; generic decimal output routine
    CALL NL         ; CRLF

    RET             ; return to DOS

K   DW  23          ; initial Kunts
S   DW  16          ; initial Sickles
G   DW  103         ; initial Galleons
R   DD  0.0725      ; interest rate
T   DW  3           ; time (years)
GS  DW  17          ; Galleons to Sickles exchange rate
SK  DW  29          ; Sickles to Knuts exchange rate
FRD DW  177FH       ; 8087 control word to round down

Output

enter image description here

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

Japt, 48 bytes

XÄ pY *(U*493+V*29+W)f
Uu493
[Uz493 ,Vz29 ,Vu29]

My first try at Japt, going for @Shaggy's bounty! Needless to say, this isn't very golfy :(

Try it Online!

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

Haskell, 73 bytes

(g#s)k r n|(x,y)<-truncate((493*g+29*s+k)*(1+r)^n)%29=(x%17,y)
(%)=divMod

Try it online!

Thanks to @Laikoni for two bytes.

The dirty tricks: the number of coins in the input is floating point (Double), while the number of coins in the output is integral (Integer). The result is a nested pair ((Galleons, Sickles), Knotts) to avoid having to flatten to a triple.

Explanation

-- Define a binary operator # that
-- takes the number of Galleons
-- and Slivers and produces a
-- function taking the number of
-- Knots, the rate, and the
-- number of years and producing
-- the result.
(g#s) k r n
   -- Calculate the initial value
   -- in Knotts, calculate the
   -- final value in Knotts,
   -- and divide to get the number
   -- of Galleons and the
   -- remainder.
  |(x,y)<-truncate((493*g+29*s+k)*(1+r)^n)%29
  -- Calculate the number of Slivers
  -- and remaining Knotts.
  =(x%17,y)
(%)=divMod
\$\endgroup\$
  • 1
    \$\begingroup\$ Save two bytes with (truncate$ ... ) -> truncate( ... ) and (g#s)k r n instead of c g s k r n. \$\endgroup\$ – Laikoni Mar 4 at 21:23
  • \$\begingroup\$ @Laikoni, thanks a lot! \$\endgroup\$ – dfeuer Mar 4 at 21:50
  • \$\begingroup\$ @Laikoni, I'd really appreciate if you could find me a couple bytes in codegolf.stackexchange.com/questions/55960/…, if you have the time. \$\endgroup\$ – dfeuer Mar 6 at 4:23
  • 1
    \$\begingroup\$ I'll look into it when I find the time. Meanwhile, I can point you to our Haskell chat room Of Monads and Men and also to this question which you might enjoy given your Hugs/GHC polyglots. \$\endgroup\$ – Laikoni Mar 6 at 10:50
1
\$\begingroup\$

Stax, 24 bytes

»♀(╪M╢ú!!«ε◘÷╛SI►U/)-f!ö

Run and debug it

Input is space separated values. interest years knuts sickles galleons

Output is newline separated.

knuts
sickles
galleons
\$\endgroup\$
1
\$\begingroup\$

TI-BASIC (TI-84), 96 90 Bytes

:SetUpEditor C:Ans→∟C:∟C(1)+29∟C(2)+493∟C(3)→T:T(1+∟C(4))^∟C(5)→T:remainder(iPart(T),493→R:{remainder(R,29),iPart(R/29),iPart(T/493)}

Input is Ans, a list with 5 items: Knuts, Sickles, Galleons, Interest (decimal), and Time (years).
Output is in Ans and is automatically printed out when the program completes.

Un-golfed:

:SetUpEditor C 
:Ans→∟C
:∟C(1)+29∟C(2)+493∟C(3)→T
:T(1+∟C(4))^∟C(5)→T
:remainder(iPart(T),493→R
:{remainder(R,29),iPart(R/29),iPart(T/493)}

Example:

{32,2,5,0.05,5}
       {32 2 5 .05 5}
prgmCDGF1
            {12 10 6}

Explanation:

:SetUpEditor C
:Ans→∟C

A new list, ∟C, is created and Ans is stored into it.

:∟C(1)+29∟C(2)+493∟C(3)→T

The Knuts, Sickles, and Galleons are converted into Knuts and stored into T.

:T(1+∟C(4))^∟C(5)→T

Takes the amount of Knuts and applies compound interest to it.
Interest is calculated here.

:remainder(iPart(T),493→R

Stores the Integer Part of T modulo 493 into R. Used to shorten byte count.

:{remainder(R,29),iPart(R/29),iPart(T/493)}

Evaluates a list with 3 items (Knuts, Sickles, and Galleons). The list is automatically stored into Ans.


Note: Byte count is evaluated by taking the byte count given in [MEM][2][7] (program list in RAM) and subtracting the amount of characters in the program name and an extra 8 bytes used for the program:

103 - 5 - 8 = 90 bytes

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

K, 46 Bytes

c:1000 17 29
t:{c\:{z(y*)/x}[c/:x;1+y%100;z]}

c store the list for base-conversion

t is the function that calculates total amount

Use example:

t[103 16 23;7.25;3]

writes (128;4;24.29209)

Explanation:

  • c/:x transform the list (galleon; sickle; knuts) to kuts

  • 1+y%100 calculate rate of interest (example 1.0725 for 7.25% rate)

  • lambda {z(y*)\x} does the work: iterate 3 times, applying interes*main, and returns final main.

  • c\: generates galleon, sickles, knuts from knuts

NOTE.- if you don't need a names-function, we can use a lambda, saving 2 bytes {c\:{z(y*)/x}[c/:x;1+y%100;z]}inputArgs

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

C# (Visual C# Interactive Compiler), 86 bytes

(a,b,c)=>((k=(int)((a.a*493+a.b*29+a.c)*Math.Pow(1+b,c)))/493,(k%=493)/29,k%29);int k;

Takes inout as a named tuple with 3 values representing knuts, sickles, and galleons, and interest rate as a double (not a percentage). I really wish C# had an exponentation operator. Math.Pow is way too long :(

Try it online!

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

Batch, 171 bytes

@set i=%4
@set/af=0,i=8*%i:.=,f=%,f*=8
@set/ai+=%f:~,1%,k=%1*493+%2*29+%3
@for /l %%y in (1,1,%5)do @set/ak+=k*i/800
@set/ag=k/493,s=k/29%%17,k%%=29
@echo %g% %s% %k%

Takes input as command-line arguments in the order Galleons, Sickles, Knuts, interest, years. Interest is a percentage but expressed without the % sign. Truncates after every year. Output is in the order Galleons, Sickles, Knuts. Supports at least 5000 Galleons. Explanation:

@set i=%4
@set/af=0,i=8*%i:.=,f=%,f*=8

Batch only has integer arithmetic. Fortunately, the interest rate is always a multiple of 0.125. We start by splitting on the decimal point, so that i becomes the integer part of the interest rate and f the decimal fraction. These are then multiplied by 8. The first digit of f is now the number of eighths in the percentage interest rate.

@set/ai+=%f:~,1%,k=%1*493+%2*29+%3

This is then extracted using string slicing and added on to give an interest rate in 1/800ths. The number of Knuts is also calculated.

@for /l %%y in (1,1,%5)do @set/ak+=k*i/800

Calculate and add on each year's interest.

@set/ag=k/493,s=k/29%%17,k%%=29
@echo %g% %s% %k%

Convert back to Galleons and Sickles.

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

05AB1E (legacy), 24 bytes

>Im•1ýÑ•3L£I*O*ï29‰ć17‰ì

Port of @JoKing's Perl 6 answer, so make sure to upvote him as well if you like this answer!

I'm using the legacy version due to a bug in the new version where £ doesn't work on integers, so an explicit cast to string § (between the second and 3) is required (until the bug is fixed).

Takes the interest as decimal, followed by the year, followed by the list of [Knuts, Sickles, Galleons].

Try it online.

Explanation:

>                      # Increase the (implicit) interest decimal by 1
                       #  i.e. 0.0725 → 1.0725
 Im                    # Take this to the power of the year input
                       #  i.e. 1.0725 and 3 → 1.233...
•1ýÑ•                  # Push compressed integer 119493
     3L                # Push list [1,2,3]
       £               # Split the integer into parts of that size: [1,19,493]
        I*             # Multiply it with the input-list
                       #  i.e. [1,19,493] * [23,16,103] → [23,464,50779]
          O            # Take the sum of this list
                       #  i.e. [23,464,50779] → 51266
           *           # Multiply it by the earlier calculated number
                       #  i.e. 51266 * 1.233... → 63244.292...
            ï          # Cast to integer, truncating the decimal values
                       #  i.e. 63244.292... → 63244
             29‰       # Take the divmod 29
                       #  i.e. 63244 → [2180,24]
                ć      # Extract the head; pushing the remainder-list and head separately
                       #  i.e. [2180,24] → [24] and 2180
                 17‰   # Take the divmod 17 on this head
                       #  i.e. 2180 → [128,4]
                    ì  # And prepend this list in front of the remainder-list
                       #  i.e. [24] and [128,4] → [128,4,24]
                       # (which is output implicitly as result)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •1ýÑ• is 119493.

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

APL(NARS), 37 char, 74 bytes

{(x y z)←⍵⋄⌊¨a⊤(z⊥⍨a←0 17 29)×x*⍨1+y}

translation of the very good and very few bytes APL solution by Graham user to a solution that use one function instead of standard input... test and how to use it:

  f←{(x y z)←⍵⋄⌊¨a⊤(z⊥⍨a←0 17 29)×x*⍨1+y}
  f 3 0.0725 (103 16 23)
128 4 24

(i don't say i had understood algorithm)

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

Perl 5, 70 bytes

$,=$";say 0|($_=(<>+<>*29+<>*493)*(1+<>)**<>)/493,0|($_%=493)/29,$_%29

Try it online!

\$\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.