void DiscreteGammaMedian(double rates[], const double alpha, const double beta,
                         unsigned n_cat) {
  unsigned i;
  double total = 0.0;
  const double cat_freq = 1.0 / ((double)n_cat);
  double prop = cat_freq * 0.5;
  double lnga1;
  assert(n_cat > 0);
  assert(rates != 0L);
  assert(alpha > 0.0);
  assert(beta > 0.0);
  if (n_cat < 2) {
    rates[0] = 1.0;
    return;
  }
  lnga1 = LnGamma(alpha + 1.0);
  for (i = 0; i < n_cat; ++i) {
    rates[i] = PointChi2(prop, 2.0 * alpha);
    total += rates[i];
    prop += cat_freq;
  }
  total /= (double)n_cat;
  for (i = 0; i < n_cat; ++i)
    rates[i] /= total;
}


x86 assembly (clang, -O0):
<DiscreteGammaMedian>:
push   %rbp
mov    %rsp,%rbp
sub    $0x40,%rsp
mov    %rdi,-0x8(%rbp)
movsd  %xmm0,-0x10(%rbp)
movsd  %xmm1,-0x18(%rbp)
mov    %esi,-0x1c(%rbp)
movq   $0x0,-0x28(%rbp)
mov    -0x1c(%rbp),%eax
cvtsi2sd %rax,%xmm1
movsd  0xea7(%rip),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,-0x30(%rbp)
movsd  0xe8e(%rip),%xmm0
mulsd  -0x30(%rbp),%xmm0
movsd  %xmm0,-0x38(%rbp)
cmpl   $0x0,-0x1c(%rbp)
seta   %al
and    $0x1,%al
movzbl %al,%edi
mov    $0x0,%al
call   1030 <assert@plt>
cmpq   $0x0,-0x8(%rbp)
setne  %al
and    $0x1,%al
movzbl %al,%edi
mov    $0x0,%al
call   1030 <assert@plt>
movsd  -0x10(%rbp),%xmm0
xorps  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
seta   %al
and    $0x1,%al
movzbl %al,%edi
mov    $0x0,%al
call   1030 <assert@plt>
movsd  -0x18(%rbp),%xmm0
xorps  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
seta   %al
and    $0x1,%al
movzbl %al,%edi
mov    $0x0,%al
call   1030 <assert@plt>
cmpl   $0x2,-0x1c(%rbp)
jae    11f8 <DiscreteGammaMedian+0xc8>
mov    -0x8(%rbp),%rax
movsd  0xe19(%rip),%xmm0
movsd  %xmm0,(%rax)
jmp    12d5 <DiscreteGammaMedian+0x1a5>
movsd  0xe08(%rip),%xmm0
addsd  -0x10(%rbp),%xmm0
mov    $0x1,%al
call   1050 <LnGamma@plt>
cvtsi2sd %eax,%xmm0
movsd  %xmm0,-0x40(%rbp)
movl   $0x0,-0x20(%rbp)
mov    -0x20(%rbp),%eax
cmp    -0x1c(%rbp),%eax
jae    1284 <DiscreteGammaMedian+0x154>
movsd  -0x38(%rbp),%xmm0
movsd  0xddb(%rip),%xmm1
mulsd  -0x10(%rbp),%xmm1
mov    $0x2,%al
call   1040 <PointChi2@plt>
cvtsi2sd %eax,%xmm0
mov    -0x8(%rbp),%rax
mov    -0x20(%rbp),%ecx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x8(%rbp),%rax
mov    -0x20(%rbp),%ecx
movsd  (%rax,%rcx,8),%xmm0
addsd  -0x28(%rbp),%xmm0
movsd  %xmm0,-0x28(%rbp)
movsd  -0x30(%rbp),%xmm0
addsd  -0x38(%rbp),%xmm0
movsd  %xmm0,-0x38(%rbp)
mov    -0x20(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x20(%rbp)
jmp    121c <DiscreteGammaMedian+0xec>
mov    -0x1c(%rbp),%eax
cvtsi2sd %rax,%xmm1
movsd  -0x28(%rbp),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,-0x28(%rbp)
movl   $0x0,-0x20(%rbp)
mov    -0x20(%rbp),%eax
cmp    -0x1c(%rbp),%eax
jae    12d5 <DiscreteGammaMedian+0x1a5>
movsd  -0x28(%rbp),%xmm1
mov    -0x8(%rbp),%rax
mov    -0x20(%rbp),%ecx
movsd  (%rax,%rcx,8),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x20(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x20(%rbp)
jmp    12a1 <DiscreteGammaMedian+0x171>
add    $0x40,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<DiscreteGammaMedian>:
push   %rbp
push   %r15
push   %r14
push   %rbx
sub    $0x38,%rsp
mov    %esi,%r14d
movsd  %xmm1,0x10(%rsp)
movsd  %xmm0,0x8(%rsp)
mov    %rdi,%rbx
xor    %edi,%edi
test   %esi,%esi
setne  %dil
xor    %eax,%eax
call   1030 <assert@plt>
xor    %edi,%edi
test   %rbx,%rbx
setne  %dil
xor    %eax,%eax
call   1030 <assert@plt>
xorpd  %xmm1,%xmm1
xor    %edi,%edi
movsd  0x8(%rsp),%xmm0
ucomisd %xmm1,%xmm0
seta   %dil
xor    %eax,%eax
call   1030 <assert@plt>
xor    %edi,%edi
xorpd  %xmm0,%xmm0
movapd %xmm0,0x20(%rsp)
movsd  0x10(%rsp),%xmm0
ucomisd 0xe70(%rip),%xmm0
seta   %dil
xor    %eax,%eax
call   1030 <assert@plt>
cmp    $0x1,%r14d
ja     11c3 <DiscreteGammaMedian+0x93>
movabs $0x3ff0000000000000,%rax
mov    %rax,(%rbx)
jmp    1317 <DiscreteGammaMedian+0x1e7>
mov    %r14d,%r15d
xorps  %xmm0,%xmm0
cvtsi2sd %r15,%xmm0
movsd  0xe2a(%rip),%xmm1
movsd  %xmm0,0x30(%rsp)
divsd  %xmm0,%xmm1
movsd  %xmm1,0x18(%rsp)
movsd  0xe12(%rip),%xmm0
addsd  0x8(%rsp),%xmm0
mov    $0x1,%al
call   1050 <LnGamma@plt>
movsd  0x8(%rsp),%xmm0
addsd  %xmm0,%xmm0
movsd  %xmm0,0x8(%rsp)
movsd  0xdf5(%rip),%xmm0
mulsd  0x18(%rsp),%xmm0
xor    %ebp,%ebp
nopl   0x0(%rax,%rax,1)
movsd  %xmm0,0x10(%rsp)
movsd  0x10(%rsp),%xmm0
movsd  0x8(%rsp),%xmm1
mov    $0x2,%al
call   1040 <PointChi2@plt>
xorps  %xmm0,%xmm0
cvtsi2sd %eax,%xmm0
movsd  %xmm0,(%rbx,%rbp,8)
movapd 0x20(%rsp),%xmm1
addsd  %xmm0,%xmm1
movsd  0x10(%rsp),%xmm0
movapd %xmm1,0x20(%rsp)
addsd  0x18(%rsp),%xmm0
add    $0x1,%rbp
cmp    %rbp,%r15
jne    1220 <DiscreteGammaMedian+0xf0>
movapd 0x20(%rsp),%xmm3
divsd  0x30(%rsp),%xmm3
cmp    $0x2,%r14d
mov    $0x1,%eax
cmovae %r14d,%eax
cmp    $0x2,%eax
jae    128c <DiscreteGammaMedian+0x15c>
xor    %ecx,%ecx
jmp    1300 <DiscreteGammaMedian+0x1d0>
mov    %eax,%ecx
and    $0xfffffffe,%ecx
movapd %xmm3,%xmm0
unpcklpd %xmm3,%xmm0
lea    -0x2(%rcx),%rsi
mov    %rsi,%rdx
shr    %rdx
add    $0x1,%rdx
test   %rsi,%rsi
je     1322 <DiscreteGammaMedian+0x1f2>
mov    %rdx,%rdi
and    $0xfffffffffffffffe,%rdi
xor    %esi,%esi
cs nopw 0x0(%rax,%rax,1)
nop
movupd (%rbx,%rsi,8),%xmm1
movupd 0x10(%rbx,%rsi,8),%xmm2
divpd  %xmm0,%xmm1
movupd %xmm1,(%rbx,%rsi,8)
divpd  %xmm0,%xmm2
movupd %xmm2,0x10(%rbx,%rsi,8)
add    $0x4,%rsi
add    $0xfffffffffffffffe,%rdi
jne    12c0 <DiscreteGammaMedian+0x190>
test   $0x1,%dl
je     12fb <DiscreteGammaMedian+0x1cb>
movupd (%rbx,%rsi,8),%xmm1
divpd  %xmm0,%xmm1
movupd %xmm1,(%rbx,%rsi,8)
cmp    %rax,%rcx
je     1317 <DiscreteGammaMedian+0x1e7>
movsd  (%rbx,%rcx,8),%xmm0
divsd  %xmm3,%xmm0
movsd  %xmm0,(%rbx,%rcx,8)
add    $0x1,%rcx
cmp    %rcx,%rax
jne    1300 <DiscreteGammaMedian+0x1d0>
add    $0x38,%rsp
pop    %rbx
pop    %r14
pop    %r15
pop    %rbp
ret
xor    %esi,%esi
test   $0x1,%dl
jne    12ed <DiscreteGammaMedian+0x1bd>
jmp    12fb <DiscreteGammaMedian+0x1cb>

LLVM IR (-O0):
define void @DiscreteGammaMedian(double* %0, double %1, double %2, i32 %3) {
%5 = alloca double*
%6 = alloca double
%7 = alloca double
%8 = alloca i32
%9 = alloca i32
%10 = alloca double
%11 = alloca double
%12 = alloca double
%13 = alloca double
store double* %0, double** %5
store double %1, double* %6
store double %2, double* %7
store i32 %3, i32* %8
store double 0.000000e+00, double* %10
%14 = load i32, i32* %8
%15 = uitofp i32 %14 to double
%16 = fdiv double 1.000000e+00, %15
store double %16, double* %11
%17 = load double, double* %11
%18 = fmul double %17, 5.000000e-01
store double %18, double* %12
%19 = load i32, i32* %8
%20 = icmp ugt i32 %19, 0
%21 = zext i1 %20 to i32
%22 = call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %21)
%23 = load double*, double** %5
%24 = icmp ne double* %23, null
%25 = zext i1 %24 to i32
%26 = call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %25)
%27 = load double, double* %6
%28 = fcmp ogt double %27, 0.000000e+00
%29 = zext i1 %28 to i32
%30 = call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %29)
%31 = load double, double* %7
%32 = fcmp ogt double %31, 0.000000e+00
%33 = zext i1 %32 to i32
%34 = call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %33)
%35 = load i32, i32* %8
%36 = icmp ult i32 %35, 2
br i1 %36, label %37, label %40
37: ; preds = %4
%38 = load double*, double** %5
%39 = getelementptr inbounds double, double* %38, i64 0
store double 1.000000e+00, double* %39
br label %92
40: ; preds = %4
%41 = load double, double* %6
%42 = fadd double %41, 1.000000e+00
%43 = call i32 (double, ...) bitcast (i32 (...)* @LnGamma to i32 (double, ...)*)(double %42)
%44 = sitofp i32 %43 to double
store double %44, double* %13
store i32 0, i32* %9
br label %45
45: ; preds = %69, %40
%46 = load i32, i32* %9
%47 = load i32, i32* %8
%48 = icmp ult i32 %46, %47
br i1 %48, label %49, label %72
49: ; preds = %45
%50 = load double, double* %12
%51 = load double, double* %6
%52 = fmul double 2.000000e+00, %51
%53 = call i32 (double, double, ...) bitcast (i32 (...)* @PointChi2 to i32 (double, double, ...)*)(double %50, double %52)
%54 = sitofp i32 %53 to double
%55 = load double*, double** %5
%56 = load i32, i32* %9
%57 = zext i32 %56 to i64
%58 = getelementptr inbounds double, double* %55, i64 %57
store double %54, double* %58
%59 = load double*, double** %5
%60 = load i32, i32* %9
%61 = zext i32 %60 to i64
%62 = getelementptr inbounds double, double* %59, i64 %61
%63 = load double, double* %62
%64 = load double, double* %10
%65 = fadd double %64, %63
store double %65, double* %10
%66 = load double, double* %11
%67 = load double, double* %12
%68 = fadd double %67, %66
store double %68, double* %12
br label %69
69: ; preds = %49
%70 = load i32, i32* %9
%71 = add i32 %70, 1
store i32 %71, i32* %9
br label %45
72: ; preds = %45
%73 = load i32, i32* %8
%74 = uitofp i32 %73 to double
%75 = load double, double* %10
%76 = fdiv double %75, %74
store double %76, double* %10
store i32 0, i32* %9
br label %77
77: ; preds = %89, %72
%78 = load i32, i32* %9
%79 = load i32, i32* %8
%80 = icmp ult i32 %78, %79
br i1 %80, label %81, label %92
81: ; preds = %77
%82 = load double, double* %10
%83 = load double*, double** %5
%84 = load i32, i32* %9
%85 = zext i32 %84 to i64
%86 = getelementptr inbounds double, double* %83, i64 %85
%87 = load double, double* %86
%88 = fdiv double %87, %82
store double %88, double* %86
br label %89
89: ; preds = %81
%90 = load i32, i32* %9
%91 = add i32 %90, 1
store i32 %91, i32* %9
br label %77
92: ; preds = %37, %77
ret void
}

LLVM IR (-O2):
define void @DiscreteGammaMedian(double* %0, double %1, double %2, i32 %3) {
%5 = uitofp i32 %3 to double
%6 = fdiv double 1.000000e+00, %5
%7 = icmp ne i32 %3, 0
%8 = zext i1 %7 to i32
%9 = tail call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %8)
%10 = icmp ne double* %0, null
%11 = zext i1 %10 to i32
%12 = tail call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %11)
%13 = fcmp ogt double %1, 0.000000e+00
%14 = zext i1 %13 to i32
%15 = tail call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %14)
%16 = fcmp ogt double %2, 0.000000e+00
%17 = zext i1 %16 to i32
%18 = tail call i32 (i32, ...) bitcast (i32 (...)* @assert to i32 (i32, ...)*)(i32 %17)
%19 = icmp ult i32 %3, 2
br i1 %19, label %20, label %21
20: ; preds = %4
store double 1.000000e+00, double* %0
br label %91
21: ; preds = %4
%22 = fadd double %1, 1.000000e+00
%23 = tail call i32 (double, ...) bitcast (i32 (...)* @LnGamma to i32 (double, ...)*)(double %22)
%24 = fmul double %1, 2.000000e+00
%25 = fmul double %6, 5.000000e-01
%26 = zext i32 %3 to i64
br label %27
27: ; preds = %21, %27
%28 = phi i64 [ 0, %21 ], [ %36, %27 ]
%29 = phi double [ %25, %21 ], [ %35, %27 ]
%30 = phi double [ 0.000000e+00, %21 ], [ %34, %27 ]
%31 = tail call i32 (double, double, ...) bitcast (i32 (...)* @PointChi2 to i32 (double, double, ...)*)(double %29, double %24)
%32 = sitofp i32 %31 to double
%33 = getelementptr inbounds double, double* %0, i64 %28
store double %32, double* %33
%34 = fadd double %30, %32
%35 = fadd double %6, %29
%36 = add nuw nsw i64 %28, 1
%37 = icmp eq i64 %36, %26
br i1 %37, label %38, label %27
38: ; preds = %27
%39 = fdiv double %34, %5
%40 = call i32 @llvm.umax.i32(i32 %3, i32 1)
%41 = zext i32 %40 to i64
%42 = icmp ult i32 %40, 2
br i1 %42, label %82, label %43
43: ; preds = %38
%44 = and i64 %41, 4294967294
%45 = insertelement <2 x double> poison, double %39, i64 0
%46 = shufflevector <2 x double> %45, <2 x double> poison, <2 x i32> zeroinitializer
%47 = add nsw i64 %44, -2
%48 = lshr exact i64 %47, 1
%49 = add nuw i64 %48, 1
%50 = and i64 %49, 1
%51 = icmp eq i64 %47, 0
br i1 %51, label %71, label %52
52: ; preds = %43
%53 = and i64 %49, -2
br label %54
54: ; preds = %54, %52
%55 = phi i64 [ 0, %52 ], [ %68, %54 ]
%56 = phi i64 [ 0, %52 ], [ %69, %54 ]
%57 = getelementptr inbounds double, double* %0, i64 %55
%58 = bitcast double* %57 to <2 x double>*
%59 = load <2 x double>, <2 x double>* %58
%60 = fdiv <2 x double> %59, %46
%61 = bitcast double* %57 to <2 x double>*
store <2 x double> %60, <2 x double>* %61
%62 = or i64 %55, 2
%63 = getelementptr inbounds double, double* %0, i64 %62
%64 = bitcast double* %63 to <2 x double>*
%65 = load <2 x double>, <2 x double>* %64
%66 = fdiv <2 x double> %65, %46
%67 = bitcast double* %63 to <2 x double>*
store <2 x double> %66, <2 x double>* %67
%68 = add nuw i64 %55, 4
%69 = add nuw i64 %56, 2
%70 = icmp eq i64 %69, %53
br i1 %70, label %71, label %54
71: ; preds = %54, %43
%72 = phi i64 [ 0, %43 ], [ %68, %54 ]
%73 = icmp eq i64 %50, 0
br i1 %73, label %80, label %74
74: ; preds = %71
%75 = getelementptr inbounds double, double* %0, i64 %72
%76 = bitcast double* %75 to <2 x double>*
%77 = load <2 x double>, <2 x double>* %76
%78 = fdiv <2 x double> %77, %46
%79 = bitcast double* %75 to <2 x double>*
store <2 x double> %78, <2 x double>* %79
br label %80
80: ; preds = %71, %74
%81 = icmp eq i64 %44, %41
br i1 %81, label %91, label %82
82: ; preds = %38, %80
%83 = phi i64 [ 0, %38 ], [ %44, %80 ]
br label %84
84: ; preds = %82, %84
%85 = phi i64 [ %89, %84 ], [ %83, %82 ]
%86 = getelementptr inbounds double, double* %0, i64 %85
%87 = load double, double* %86
%88 = fdiv double %87, %39
store double %88, double* %86
%89 = add nuw nsw i64 %85, 1
%90 = icmp eq i64 %89, %41
br i1 %90, label %91, label %84
91: ; preds = %84, %80, %20
ret void
}