#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 */

/* Variables and functions */
int /*<<< orphan*/ exit(int);
int /*<<< orphan*/ printf(char *);
double factorial(int n) {
  if (n < 0) {
    printf("Error!  Negative factorial not defined.\n");
    exit(65);
  }
  static const double Fact[] = {
      1.00000000000000000000E0,          1.00000000000000000000E0,
      2.00000000000000000000E0,          6.00000000000000000000E0,
      2.40000000000000000000E1,          1.20000000000000000000E2,
      7.20000000000000000000E2,          5.04000000000000000000E3,
      4.03200000000000000000E4,          3.62880000000000000000E5,
      3.62880000000000000000E6,          3.99168000000000000000E7,
      4.79001600000000000000E8,          6.22702080000000000000E9,
      8.71782912000000000000E10,         1.30767436800000000000E12,
      2.09227898880000000000E13,         3.55687428096000000000E14,
      6.40237370572800000000E15,         1.21645100408832000000E17,
      2.43290200817664000000E18,         5.10909421717094400000E19,
      1.12400072777760768000E21,         2.58520167388849766400E22,
      6.20448401733239439360E23,         1.55112100433309859840E25,
      4.03291461126605635584E26,         1.0888869450418352160768E28,
      3.04888344611713860501504E29,      8.841761993739701954543616E30,
      2.6525285981219105863630848E32,    8.22283865417792281772556288E33,
      2.6313083693369353016721801216E35, 8.68331761881188649551819440128E36};
  double nFact = 1.0;
  int c;
  if (n <= 33) {
    return Fact[n];
  } else {
    nFact = Fact[33];
    for (c = 34; c < nFact; c++) {
      nFact *= c;
    }
    return nFact;
  }
}


x86 assembly (clang, -O0):
<factorial>:
push   %rbp
mov    %rsp,%rbp
sub    $0x20,%rsp
mov    %edi,-0xc(%rbp)
cmpl   $0x0,-0xc(%rbp)
jge    114b <factorial+0x2b>
lea    0xecc(%rip),%rdi
call   1030 <printf@plt>
mov    $0x41,%edi
call   1040 <exit@plt>
movsd  0xead(%rip),%xmm0
movsd  %xmm0,-0x18(%rbp)
cmpl   $0x21,-0xc(%rbp)
jg     117c <factorial+0x5c>
movslq -0xc(%rbp),%rcx
lea    0xed3(%rip),%rax
movsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x8(%rbp)
jmp    11cb <factorial+0xab>
movsd  0xfc4(%rip),%xmm0
movsd  %xmm0,-0x18(%rbp)
movl   $0x22,-0x1c(%rbp)
cvtsi2sdl -0x1c(%rbp),%xmm1
movsd  -0x18(%rbp),%xmm0
ucomisd %xmm1,%xmm0
jbe    11c1 <factorial+0xa1>
cvtsi2sdl -0x1c(%rbp),%xmm0
mulsd  -0x18(%rbp),%xmm0
movsd  %xmm0,-0x18(%rbp)
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x1c(%rbp)
jmp    1190 <factorial+0x70>
movsd  -0x18(%rbp),%xmm0
movsd  %xmm0,-0x8(%rbp)
movsd  -0x8(%rbp),%xmm0
add    $0x20,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<factorial>:
push   %rax
test   %edi,%edi
js     1166 <factorial+0x46>
cmp    $0x22,%edi
jae    113a <factorial+0x1a>
mov    %edi,%eax
lea    0xedd(%rip),%rcx
movsd  (%rcx,%rax,8),%xmm0
pop    %rax
ret
movsd  0xebe(%rip),%xmm0
movsd  0xebe(%rip),%xmm1
mov    $0x23,%eax
nop
mulsd  %xmm1,%xmm0
xorps  %xmm1,%xmm1
cvtsi2sd %eax,%xmm1
add    $0x1,%eax
ucomisd %xmm1,%xmm0
ja     1150 <factorial+0x30>
pop    %rax
ret
lea    0xfb3(%rip),%rdi
call   1030 <puts@plt>
mov    $0x41,%edi
call   1040 <exit@plt>

LLVM IR (-O0):
@.str = [41 x i8] c"Error! Negative factorial not defined.\0A\00"
@factorial.Fact = internal constant [34 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, double 0x4406283BE9B5C620, double 0x444E77526159F06C, double 0x4495E5C335F8A4CE, double 0x44E06C52687A7B9A, double 0x4529A940C33F6121, double 0x4574D9849EA37EEB, double 0x45C19787E5D9F316, double 0x460EC92DD23D6967, double 0x465BE6518687A785, double 0x46AA27EC6E1F2D0D, double 0x46F956AD0AAE33A4, double 0x474956AD0AAE33A4, double 0x479A21627303A541]
define double @factorial(i32 %0) {
%2 = alloca double
%3 = alloca i32
%4 = alloca double
%5 = alloca i32
store i32 %0, i32* %3
%6 = load i32, i32* %3
%7 = icmp slt i32 %6, 0
br i1 %7, label %8, label %11
8: ; preds = %1
%9 = call i32 @printf(i8* getelementptr inbounds ([41 x i8], [41 x i8]* @.str, i64 0, i64 0))
%10 = call i32 @exit(i32 65)
unreachable
11: ; preds = %1
store double 1.000000e+00, double* %4
%12 = load i32, i32* %3
%13 = icmp sle i32 %12, 33
br i1 %13, label %14, label %19
14: ; preds = %11
%15 = load i32, i32* %3
%16 = sext i32 %15 to i64
%17 = getelementptr inbounds [34 x double], [34 x double]* @factorial.Fact, i64 0, i64 %16
%18 = load double, double* %17
store double %18, double* %2
br label %36
19: ; preds = %11
%20 = load double, double* getelementptr inbounds ([34 x double], [34 x double]* @factorial.Fact, i64 0, i64 33)
store double %20, double* %4
store i32 34, i32* %5
br label %21
21: ; preds = %31, %19
%22 = load i32, i32* %5
%23 = sitofp i32 %22 to double
%24 = load double, double* %4
%25 = fcmp olt double %23, %24
br i1 %25, label %26, label %34
26: ; preds = %21
%27 = load i32, i32* %5
%28 = sitofp i32 %27 to double
%29 = load double, double* %4
%30 = fmul double %29, %28
store double %30, double* %4
br label %31
31: ; preds = %26
%32 = load i32, i32* %5
%33 = add nsw i32 %32, 1
store i32 %33, i32* %5
br label %21
34: ; preds = %21
%35 = load double, double* %4
store double %35, double* %2
br label %36
36: ; preds = %34, %14
%37 = load double, double* %2
ret double %37
}

LLVM IR (-O2):
@factorial.Fact = internal unnamed_addr constant [34 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, double 0x4406283BE9B5C620, double 0x444E77526159F06C, double 0x4495E5C335F8A4CE, double 0x44E06C52687A7B9A, double 0x4529A940C33F6121, double 0x4574D9849EA37EEB, double 0x45C19787E5D9F316, double 0x460EC92DD23D6967, double 0x465BE6518687A785, double 0x46AA27EC6E1F2D0D, double 0x46F956AD0AAE33A4, double 0x474956AD0AAE33A4, double 0x479A21627303A541]
@str = [40 x i8] c"Error! Negative factorial not defined.\00"
define double @factorial(i32 %0) {
%2 = icmp slt i32 %0, 0
br i1 %2, label %3, label %6
3: ; preds = %1
%4 = tail call i32 @puts(i8* dereferenceable(1) getelementptr inbounds ([40 x i8], [40 x i8]* @str, i64 0, i64 0))
%5 = tail call i32 @exit(i32 65)
unreachable
6: ; preds = %1
%7 = icmp ult i32 %0, 34
br i1 %7, label %8, label %12
8: ; preds = %6
%9 = zext i32 %0 to i64
%10 = getelementptr inbounds [34 x double], [34 x double]* @factorial.Fact, i64 0, i64 %9
%11 = load double, double* %10
br label %20
12: ; preds = %6, %12
%13 = phi double [ %18, %12 ], [ 3.400000e+01, %6 ]
%14 = phi i32 [ %17, %12 ], [ 34, %6 ]
%15 = phi double [ %16, %12 ], [ 0x479A21627303A541, %6 ]
%16 = fmul double %15, %13
%17 = add nuw nsw i32 %14, 1
%18 = sitofp i32 %17 to double
%19 = fcmp ogt double %16, %18
br i1 %19, label %12, label %20
20: ; preds = %12, %8
%21 = phi double [ %11, %8 ], [ %16, %12 ]
ret double %21
}