Calculate my income tax

Background

Here in the UK1, these are the income tax rules:

• You get a personal allowance (untaxed) of up to £12,570:
• If you earn less than £100,000, you get the full £12,570 as personal allowance
• For every £2 over £100,000, your personal allowance goes down by £1
• After the personal allowance, the next £37,700 is taxed at the "basic rate" of 20%
• After that, the next £99,730 is taxed at the "higher rate" of 40%
• Finally, anything above this is taxed at the "additional rate" of 45%

1: This isn't actually the case in Scotland; only England, Wales and Northern Ireland.

Using the above tax rules, take in an annual salary (as a positive integer) and calculate the income tax.

Test cases

Input    Output
12570    0
50000    7486
80000    19432
120000   39432
200000   75588.5


Note: the final test case can be any of 75588, 75588.5, or 75589 (any is fine)

Clarifications

• You can choose whether to make the personal allowance an integer or keep it as a float
• e.g. if the input is £100,003, the personal allowance can be £12,569, £12,568.50, or £12,568
• The same goes for the final output. If it ends up as a float, you can make it an integer or keep it as a float
• (see the final test case)
• This is , so shortest answer in bytes wins!
• Sandbox Commented Dec 25, 2022 at 9:49
• Presumably your personal allowance can never be negative.
– Simd
Commented Dec 25, 2022 at 10:06
• @Simd yes, after something like £125,140 you have £0 personal allowance. Commented Dec 25, 2022 at 10:08
• This is actually quite similar to how Australian taxation works, which makes sense given we're part of y'all anyway :p Commented Dec 25, 2022 at 10:11
• @matteo_c done. Commented Dec 25, 2022 at 10:15

JavaScript (ES6), 99 bytes

Works with floats and rounds the final result.

n=>[137430.45,37700.4,.2].map(v=>x+=v%1*(n-(n-=m(n-~~v))),x=0,n-=(m=v=>v>0&&v)(12570-m(n-1e5)/2))|x


Try it online!

n =>                 // n = input
[                    // in this array, the integer part is the threshold (T)
// and the decimal part is the tax rate (R)
137430.45,         //   T = 99730 + 37700, R = 45%
37700.4,           //   T = 37700, R = 40%
.2                 //   T = 0, R = 20%
]                    //
.map(v =>            // for each entry v:
x +=               //   add to x:
v % 1 *          //     the tax rate multiplied by
( n -            //     the difference between the current value of n
( n -=         //     and the updated value of n, which is:
m(n - ~~v) //       n - max(0, n - threshold)
)              //
),               //
n -=               //   start by applying the personal allowance
( m = v =>       //   m is a helper function taking v ...
v > 0 && v     //   ... and returning max(0, v)
)                //
(                //   personal allowance:
12570 -        //     12570 - max(0, n - 100000) / 2
m(n - 1e5) / 2 //
)                //
)                    // end of map()
| x                  // return the final value of x


Python, 8380 77 bytes

-3 thanks to @Max by removing the 0 from the beginning of the floating points.

-3 thanks to @tsh by using integers which are then divided instead of floats and changing the personal allowance operation.

lambda m:sum(([4]*37700+[8]*99730+[9]*m)[:m-max(0,min(62570-m//2,12570))])/20


Attempt This Online!

Fun use of Python indexing and list multiplication.

• I think you can remove the leading zero from 0.2 etc.
– Max
Commented Dec 26, 2022 at 15:39
• lambda m:sum(([4]*37700+[8]*99730+[9]*m)[:m-max(0,min(62570-m//2,12570))])/20
– tsh
Commented Dec 27, 2022 at 5:34

Charcoal, 49 bytes

ＩΣ×Ｉ⪪”‴⌈↷¶»^w⁷k²zV” Ｅ⁻ＮＩ⪪”←¶➙～!¬‴″ζＣＥR⁵kςⅈ” ∧›ι⁰ι


Attempt This Online! Link is to verbose version of code. Explanation:

           Ｎ            Input as a number
⁻             Vectorised subtract
...       Compressed string 12570 50270 100000 125140 137430
⪪          Split on spaces
Ｉ           Cast to number
Ｅ              Map over values
ι   Current value
›    Is greater than
⁰  Literal integer 0
∧     Logical And
ι Current value
×                     Vectorised multiply by
...                Compressed string .2 .2 .2 -.2 .05
⪪                   Split on spaces
Ｉ                    Cast to number
Σ                      Take the sum
Ｉ                       Cast to string
Implicitly print


73 bytes for a version that calculates the personal allowance as an integer first:

Ｎθ≔⟦⁹⁹⁷³⁰¦³⁷⁷⁰⁰⌈⟦⁰⁻¹²⁵⁷⁰÷⌈⟦⁰⁻θＸχ⁵⟧²⟧⟧η≔⁰ζＦ³«≔⌊⟦θ⊟η⟧ε≧⁺×∕ι⁵εζ≧⁻εθ»Ｉ⁺ζ×θ·⁴⁵


Try it online! Link is to verbose version of code.

-3 bytes thanks to @The Thonnu

r#(-1.0)=r;r#l=min r l
g(t,r)(l,p)=(t+r#l*p/20,r-r#l)
f x=fst$foldl g(0,x)$zip[max(12570-max(x-1e5)0/2)0,37700,99730,-1][0,4,8,9]


Attempt This Online!

• Nice answer (+1). I think you could change 100000 to 1e5 to save 3 bytes: Attempt This Online! Commented Dec 25, 2022 at 19:10

05AB1E, 32 31 bytes

5ÐD(20)zI•5HwŸJ}Ütæ•žFвT*-Dd**O


Port of @Neil's Charcoal answer, so make sure to upvote him as well!

Explanation:

5            # Push a 5
ÐD          # Triplicate + Duplicate so there are four 5s on the stack
(         # Negate the top one
20       # Push 20
)      # Wrap all five values on the stack into a list: [5,5,5,-5,20]
z     # Get 1/value for each of them: [0.2,0.2,0.2,-0.2,0.05]
I            # Push the input
•5HwŸJ}Ütæ• # Push compressed integer 90598507370046338479
žFв        # Convert 90598507370046338479 to base-16384 as list:
#  [1257,5027,10000,12514,13743]
T*      # Multiply each by 10: [12570,50270,100000,125140,137430]
I      -     # Subtract each from the input
D    # Duplicate this list
d   # Pop and do a non-negative (>=0) check for each
*  # Multiply the values at the same positions (negative values have become 0)
*            # Multiply the values at the same positions with list [0.2,0.2,0.2,-0.2,0.05]
O           # Sum everything together
# (which is output implicitly as result)


See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •5HwŸJ}Ütæ• is 90598507370046338479 and •5HwŸJ}Ütæ•žFв is [1257,5027,10000,12514,13743].

Vyxal, 58 48 33 bytes

5D:N20WĖ⁰»+gḊ6ß/ċi∴o@t»k4τ-:0≥**∑


Try it online!

• -15 thanks to lyxal

Explanation

5D:                             # Push 5 and quadruplicate
N                            # Negate the top one
20                          # Push 20
W                         # Wrap the stack in a list
Ė                        # Reciprocal of each
⁰                       # Push the input
»...»                  # Push the base-255 compressed integer 12570050270100000125140137430
k4τ               # Convert to list: [12570,50270,100000,125140,137430]
-              # Subtract each from the input
:             # Duplicate this list
0≥           # Check if each element is ≥0
*          # Multiply with the list so negative values are now 0
*         # Multiply together
∑        # And sum, outputting implicitly

• Try it Online! for 40 bytes Commented Dec 31, 2022 at 12:46
• or Try it Online! for 33 Commented Dec 31, 2022 at 12:50
• @lyxal thanks, updated Commented Dec 31, 2022 at 13:10

QB64, 183 bytes

p=12570:If i>100000Then
p=p-Int((i-100000)/2):If p<0Then p=0
endif
l=p+37700:m=l+99730:If i>m Then
t=.45*(i-m):i=m
endif
If i>l Then
t=t+.4*(i-l):i=l
endif
If i>p Then t=t+.2*(i-p)
?t

• Suggest (i-p)/5 instead of .2*(i-p) Commented Jan 3, 2023 at 2:41

C (gcc), 120107 102 bytes

• -18 thanks to ceilingcat
#define F+fdim(i
f(i){i=fmin(37700,i=F,F-i+12570,F,1e5)/2)))/5+.4*fmin(99730,i=F,37700))F,99730)*.45;}


Try it online!