#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */
typedef int uint64_t;

/* Variables and functions */
double _factorial(uint64_t n) {
  long double result;
  double small_vals[21] = {1.0,
                           1.0,
                           2.0,
                           6.0,
                           24.0,
                           120.0,
                           720.0,
                           5040.0,
                           40320.0,
                           362880.0,
                           3628800.0,
                           39916800.0,
                           479001600.0,
                           6227020800.0,
                           87178291200.0,
                           1307674368000.0,
                           20922789888000.0,
                           355687428096000.0,
                           6402373705728000.0,
                           121645100408832000.0,
                           2432902008176640000.0};
  if (n < 21) {
    return small_vals[n];
  }
  result = n;
  do {
    result *= --n;
  } while (n > 21);
  return (double)(result * (small_vals[n - 1]));
}


x86 assembly (clang, -O0):
<_factorial>:
push   %rbp
mov    %rsp,%rbp
sub    $0xe0,%rsp
mov    %edi,-0xc(%rbp)
lea    -0xd0(%rbp),%rdi
lea    0xed4(%rip),%rsi
mov    $0xa8,%edx
call   1030 <memcpy@plt>
cmpl   $0x15,-0xc(%rbp)
jge    1157 <_factorial+0x47>
movslq -0xc(%rbp),%rax
movsd  -0xd0(%rbp,%rax,8),%xmm0
ff ff
movsd  %xmm0,-0x8(%rbp)
jmp    11b7 <_factorial+0xa7>
mov    -0xc(%rbp),%eax
mov    %eax,-0xd4(%rbp)
fildl  -0xd4(%rbp)
fstpt  -0x20(%rbp)
mov    -0xc(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0xc(%rbp)
mov    %eax,-0xd8(%rbp)
fildl  -0xd8(%rbp)
fldt   -0x20(%rbp)
fmulp  %st,%st(1)
fstpt  -0x20(%rbp)
cmpl   $0x15,-0xc(%rbp)
jg     1169 <_factorial+0x59>
fldt   -0x20(%rbp)
mov    -0xc(%rbp),%eax
add    $0xffffffff,%eax
cltq
fldl   -0xd0(%rbp,%rax,8)
fmulp  %st,%st(1)
fstpl  -0xe0(%rbp)
movsd  -0xe0(%rbp),%xmm0
ff
movsd  %xmm0,-0x8(%rbp)
movsd  -0x8(%rbp),%xmm0
add    $0xe0,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<_factorial>:
cmp    $0x14,%edi
jg     1115 <_factorial+0x15>
movslq %edi,%rax
lea    0xef1(%rip),%rcx
movsd  (%rcx,%rax,8),%xmm0
ret
mov    %edi,-0xc(%rsp)
fildl  -0xc(%rsp)
lea    0x1(%rdi),%eax
lea    -0x2(%rax),%ecx
mov    %ecx,-0x10(%rsp)
fimull -0x10(%rsp)
add    $0xffffffff,%eax
cmp    $0x16,%eax
ja     1120 <_factorial+0x20>
cmp    $0x16,%edi
mov    $0x16,%eax
cmovb  %edi,%eax
add    $0xfffffffe,%eax
lea    0xeb8(%rip),%rcx
fmull  (%rcx,%rax,8)
fstpl  -0x8(%rsp)
movsd  -0x8(%rsp),%xmm0
ret

LLVM IR (-O0):
@__const._factorial.small_vals = [21 x double] [double 1.000000e+00, double 1.000000e+00, double 2.000000e+00, double 6.000000e+00, double 2.400000e+01, double 1.200000e+02, double 7.200000e+02, double 5.040000e+03, double 4.032000e+04, double 3.628800e+05, double 3.628800e+06, double 3.991680e+07, double 0x41BC8CFC00000000, double 0x41F7328CC0000000, double 0x42344C3B28000000, double 0x4273077775800000, double 0x42B3077775800000, double 0x42F437EEECD80000, double 0x4336BEECCA730000, double 0x437B02B930689000, double 0x43C0E1B3BE415A00]
define double @_factorial(i32 %0) {
%2 = alloca double
%3 = alloca i32
%4 = alloca x86_fp80
%5 = alloca [21 x double]
store i32 %0, i32* %3
%6 = bitcast [21 x double]* %5 to i8*
%7 = load i32, i32* %3
%8 = icmp slt i32 %7, 21
br i1 %8, label %9, label %14
9: ; preds = %1
%10 = load i32, i32* %3
%11 = sext i32 %10 to i64
%12 = getelementptr inbounds [21 x double], [21 x double]* %5, i64 0, i64 %11
%13 = load double, double* %12
store double %13, double* %2
br label %36
14: ; preds = %1
%15 = load i32, i32* %3
%16 = sitofp i32 %15 to x86_fp80
store x86_fp80 %16, x86_fp80* %4
br label %17
17: ; preds = %23, %14
%18 = load i32, i32* %3
%19 = add nsw i32 %18, -1
store i32 %19, i32* %3
%20 = sitofp i32 %19 to x86_fp80
%21 = load x86_fp80, x86_fp80* %4
%22 = fmul x86_fp80 %21, %20
store x86_fp80 %22, x86_fp80* %4
br label %23
23: ; preds = %17
%24 = load i32, i32* %3
%25 = icmp sgt i32 %24, 21
br i1 %25, label %17, label %26
26: ; preds = %23
%27 = load x86_fp80, x86_fp80* %4
%28 = load i32, i32* %3
%29 = sub nsw i32 %28, 1
%30 = sext i32 %29 to i64
%31 = getelementptr inbounds [21 x double], [21 x double]* %5, i64 0, i64 %30
%32 = load double, double* %31
%33 = fpext double %32 to x86_fp80
%34 = fmul x86_fp80 %27, %33
%35 = fptrunc x86_fp80 %34 to double
store double %35, double* %2
br label %36
36: ; preds = %26, %9
%37 = load double, double* %2
ret double %37
}

LLVM IR (-O2):
@__const._factorial.small_vals = [21 x double] [double 1.000000e+00, double 1.000000e+00, double 2.000000e+00, double 6.000000e+00, double 2.400000e+01, double 1.200000e+02, double 7.200000e+02, double 5.040000e+03, double 4.032000e+04, double 3.628800e+05, double 3.628800e+06, double 3.991680e+07, double 0x41BC8CFC00000000, double 0x41F7328CC0000000, double 0x42344C3B28000000, double 0x4273077775800000, double 0x42B3077775800000, double 0x42F437EEECD80000, double 0x4336BEECCA730000, double 0x437B02B930689000, double 0x43C0E1B3BE415A00]
define double @_factorial(i32 %0) {
%2 = icmp slt i32 %0, 21
br i1 %2, label %3, label %7
3: ; preds = %1
%4 = sext i32 %0 to i64
%5 = getelementptr inbounds [21 x double], [21 x double]* @__const._factorial.small_vals, i64 0, i64 %4
%6 = load double, double* %5
br label %25
7: ; preds = %1
%8 = sitofp i32 %0 to x86_fp80
br label %9
9: ; preds = %9, %7
%10 = phi i32 [ %0, %7 ], [ %12, %9 ]
%11 = phi x86_fp80 [ %8, %7 ], [ %14, %9 ]
%12 = add nsw i32 %10, -1
%13 = sitofp i32 %12 to x86_fp80
%14 = fmul x86_fp80 %11, %13
%15 = icmp ugt i32 %10, 22
br i1 %15, label %9, label %16
16: ; preds = %9
%17 = call i32 @llvm.umin.i32(i32 %0, i32 22)
%18 = add nsw i32 %17, -2
%19 = zext i32 %18 to i64
%20 = getelementptr inbounds [21 x double], [21 x double]* @__const._factorial.small_vals, i64 0, i64 %19
%21 = load double, double* %20
%22 = fpext double %21 to x86_fp80
%23 = fmul x86_fp80 %14, %22
%24 = fptrunc x86_fp80 %23 to double
br label %25
25: ; preds = %16, %3
%26 = phi double [ %6, %3 ], [ %24, %16 ]
ret double %26
}