# Compound Interest… with Wizard Money

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!

• Can we take the interest rate as a decimal instead of a percentage? (e.g., 0.0725 instead of 7.25) – Shaggy Mar 2 at 19:44
• @Shaggy I would also like to know this – senox13 Mar 2 at 21:01
• 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"? – Chas Brown Mar 2 at 23:34
• In other words, please clarify the mathematical meaning of the phrase rounding down – senox13 Mar 2 at 23:38
• @ChasBrown: 1 Knut. Truncate/floor function to the nearest whole Knut. – Beefster Mar 3 at 4:16

# 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).

• I don't know R; what does having them wrap around win you? – dfeuer Mar 4 at 17:53
• @dfeuer they’re taken mod 1e99, so if your galleons get that high they’ll drop to zero – Nick Kennedy Mar 4 at 21:40
• What I'm wondering is what you gain by taking them mod 1e99. – dfeuer Mar 4 at 21:52
• 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!]) – Nick Kennedy Mar 4 at 22:26
• @NickKennedy you could do 9e99 as well...Also, you can golf down to 63 bytes – Giuseppe Mar 4 at 22:50

# Python 3.8 (pre-release), 7574 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!

• Good catch. Updating answer – senox13 Mar 2 at 21:58
• 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 – senox13 Mar 2 at 22:55
• 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 :) ). – Chas Brown Mar 2 at 23:35
• 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 – senox13 Mar 2 at 23:41
• 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. – xnor Mar 3 at 0:28

# 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.

• ⌊a⊤(⎕⊥⍨a←0 17 29)×⎕*⍨1+⎕ for 24? – lirtosiast Mar 3 at 6:32
• @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. – Graham Mar 3 at 6:45
• @lirtosiast Thanks again I have taken the 2 bytes resulting from the assignment to a. – Graham Mar 3 at 7:05

# 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

• 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 ************************* ;-) – guifa Mar 7 at 3:18
• @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 (**) – Jo King Mar 7 at 3:23
• 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 – guifa Mar 7 at 3:26

# 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                  - 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)
÷             - divide (all amounts in Galleons)
S           - sum (total Galleons owed)
×          - 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)


# 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
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
FMUL            ; multiply sickles to get 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

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

# 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!

(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

• Save two bytes with (truncate$... ) -> truncate( ... ) and (g#s)k r n instead of c g s k r n. – Laikoni Mar 4 at 21:23 • @Laikoni, thanks a lot! – dfeuer Mar 4 at 21:50 • @Laikoni, I'd really appreciate if you could find me a couple bytes in codegolf.stackexchange.com/questions/55960/…, if you have the time. – dfeuer Mar 6 at 4:23 • 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. – Laikoni Mar 6 at 10:50 # 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  # 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 # 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 # 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! ## 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. # 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. # 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) # Perl 5, 70 bytes $,=$";say 0|($_=(<>+<>*29+<>*493)*(1+<>)**<>)/493,0|($_%=493)/29,$_%29


Try it online!