g | x | w | all
Bytes Lang Time Link
315Python3240831T180636ZAjax1234
086R210611T205507ZDominic
021Jelly210611T172529Zhyper-ne
060Charcoal210612T234453ZNeil
129JavaScript ES6210611T192550ZArnauld
022Jelly210611T211658ZNick Ken
021Jelly210611T204035ZJonathan
093Julia 0.7210611T192429ZMarcMush

Python3, 315 bytes

import math
def f(d):
 A=[8,11.25,22.5,45,90]
 q,s=[(A,[])],[]
 for a,b in q:
  if sum(b)>359 or[]==a:continue
  for i in range(math.ceil((d-sum(b))/a[0])+1):q+=[(a[1:],T:=b+[a[0]]*i)];s+=[T]
 m={}
 for i in s:K=abs(sum(i)-d);m[K]=m.get(K,[])+[i]
 P=[0]*5
 for i in min(m[min(m)],key=len):P[A.index(i)]+=1
 return P

Try it online!

R, 95 88 87 86 bytes

Edit: -1 byte thanks to pajonk

function(a,b=expand.grid(rep(list(23:0),5)))b[order((c(8,90/2^(3:0))%*%t(b)-a)^2)[1],]

Try it online!

Ungolfed code

fittings=
function(a){                        # a=desired angle
b=expand.grid(rep(list(23:0),5))    # b=all combinations of 5 elements of 23..0 (note: largest-to-smallest - see below)
                                    # (23 is number of smallest (8-degree) fittings needed to get over 180 degrees)
c=colSums(t(b)*c(8,2^(-2:1)*45))    # c=the total angle made by each combination of fittings
d=which.min((d-a)^2)                # d=the first combination that minimized the absolute difference to angle a
                                    # (we take the square to save a byte getting the absolute difference,
                                    # and we automatically get the combination with the smallest numbrer of fittings
                                    # since we constructed the combinations largest-to-smallest)
return(b[d,])                       # finally, return that element of b

Jelly, 21 bytes

Ḷṗ5SÞðḋ90H3С;8¤ạðÞḢṚ

Try it online!

Note - after Nick Kennedy's golfs, this answer is actually identical to Jonathan Allan's answer, which they arrived at independently. Make sure to upvote them.

-9 bytes thanks to Nick Kennedy by rewriting the conversion from counts to total angle

ḶṗSÞ5ðḋ90H3С;8¤ạðÞḢṚ  Main Link
Ḷ                      Lowered range; [0, 1, ..., N-1]
 ṗ5                    Cartesian product; size 5 lists of the above elements
   SÞ                  Sort by sum
     ð           ðÞ    Sort by:
                ạ      - absolute difference of the following and the input:
      ḋ                - dot product with
       90H3С;8¤       - [90, 45, 22.5, 11.25, 8] via the following
       90                - 90
          3С            - repeat 3 times and collect results:
         H               - halve
             ;8          - append 8
                   Ḣ   take the first one (since it'll already be sorted by count and it's stable)
                    Ṛ  reverse it

Charcoal, 60 bytes

≔↔⁻NEφ⁺×¹¹·²⁵﹪ι¹⁶×⁸÷ι¹⁶θ≔E⌕Aθ⌊θ…⮌⊞O↨⁺¹⁶ι²÷ι¹⁶¦⁵θI⊟Φθ⁼Σι⌊EθΣλ

Try it online! Link is to verbose version of code. Outputs using Charcoal's default array format i.e. each element on its own line. Explanation:

≔↔⁻NEφ⁺×¹¹·²⁵﹪ι¹⁶×⁸÷ι¹⁶θ

Calculate the possible angles using sets of up to 999 8° fittings and optionally one each of each of the other fittings, and see how closely they compare to the input.

≔E⌕Aθ⌊θ…⮌⊞O↨⁺¹⁶ι²÷ι¹⁶¦⁵θ

Find the indices of the most accurate sets and calculate the fittings corresponding to each of those indices.

I⊟Φθ⁼Σι⌊EθΣλ

Output the last set with the fewest fittings.

JavaScript (ES6), 129 bytes

f=(n,a=[0,0,0,0,0],c=e=C=1/0)=>n<(n*n<e|n*n==e&c<C&&[e=n*n,C=c,o=a])?o:a.map((_,i,[...a])=>f(n-(i?90/(16>>i):8),a,-~c,a[i]++))&&o

Try it online!

Commented

f = (                    // f is a recursive function taking:
  n,                     //   n = input
  a = [0, 0, 0, 0, 0],   //   a[] = pipe counters
  c =                    //   c = current number of pipes
  e =                    //   e = best (smallest) squared error
  C = 1 / 0              //   C = number of pipes for the best solution
) =>                     //
n < (                    //
  n * n < e |            // if the current error is less than the best error
  n * n == e & c < C &&  // or they're equal but we're using less pipes:
  [ e = n * n,           //   update the best error
    C = c,               //   update the best count
    o = a                //   update the output
  ]                      // if e, C and o have been updated, we compare n with
                         // an array, which is always falsy
) ?                      // otherwise, we test whether n is negative:
  o                      //   in which case we return o[]
:                        // else:
  a.map(                 //
  (_, i, [...a]) =>      //   for each value at position i in a[], using a copy
                         //   of a[]:
    f(                   //     do a recursive call:
      n - (              //       subtract from n:
        i ?              //         if i is not equal to 0:
          90 / (16 >> i) //           11.25, 22.5, 45 or 90
        :                //         else:
          8              //           8
      ),                 //
      a,                 //       pass the copy of a[]
      -~c,               //       increment c
      a[i]++             //       increment a[i]
    )                    //     end of recursive call
  ) && o                 //   end of map(); return o[]

Jelly, 22 bytes

ṗⱮẎSạ¥ÞḢċⱮ⁸
90H3С;8Ṛç

Try it online!

A pair of links which takes a single argument, the number of degrees to match, and returns a list of 5 integers. Hopelessly slow for increasing values, but should theoretically work for all of the required range.

This is a much more efficient implementation but is three bytes longer.

Jelly, 21 bytes

Ḷṗ5SÞḋ90H3С;8¤ạɗÞ⁸ḢṚ

A monadic Link that accepts an integer in \$[0,180]\$ and yields a list of the five pipe counts in the prescribed order.

Try it online! although it'll time out for inputs above \$15\$ :(

How?

Builds all selections of pipes consisting of less than input-angle of each pipe, sorts these by their number of pipes, then (stable) sorts by the difference between the angle-sum and input-angle and yields the first.

Ḷṗ5SÞḋ90H3С;8¤ạɗÞ⁸ḢṚ - Link: angle, A
Ḷṗ5                   - (A) Cartesian product 5 -> all selections of the five pipes with
                                                   up to A-1 of each pipe
   SÞ                 - sort by sum (number of pipes)
                 Þ    - sort (the elements X of that) by:
                ɗ ⁸   -   last three links as a dyad - f(X, A)
              ¤       -     nilad followed by links as a nilad:
      90              -       90
         3С          -       collect & repeat three times:
        H             -         halve -> [90, 45, 22.5, 11.25]
            ;8        -       concatenate 8 -> [90, 45, 22.5, 11.25, 8]
     ḋ                -     (X) dot-product (that)
               ạ      -     (that) absolute-difference (A)
                   Ḣ  - head
                    Ṛ - reverse (to the prescribed order of pipe counts)

Julia 0.7, 93 bytes

!x=minimum(i->((4x-[32,45,90,180,360]⋅i)^2,sum(i),i),Iterators.product(fill(0:22,5)...))[3]

Try it online!