-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfactorials.lean
More file actions
113 lines (87 loc) · 3.23 KB
/
factorials.lean
File metadata and controls
113 lines (87 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import Mathlib.Data.Real.Basic -- NON-COMPUTABLE
import Mathlib.Analysis.SpecialFunctions.Pow.Real
import Init.Data.Float
import Init.Data.Nat.Basic -- basic operations built-in
import Mathlib.Data.Nat.Basic --stronger lemmas, theorem automation, or advanced properties
import Lean
set_option diagnostics true
set_option diagnostics.threshold 1000
#eval Lean.versionString
-- def tau : ℝ := 2 * 3.141592653589793
def Float.pi : Float := 3.1415926535897932385
def tau := 2 * Float.pi
def factorial : Nat -> Nat -- ℕ → ℕ
| 0 => 1
| (n + 1) => (n + 1) * factorial n
-- Compute mode
#eval factorial 5 -- Outputs 120
#eval factorial 10 -- Outputs 3628800
-- n! ≈ Gamma(n+1)
-- Stirling's approximation of factorial
def ffactorial (x : Float) : Float :=
x ^ x * Float.exp (-x) * Float.sqrt (tau * x) -- Stirling's approximation, off by ≈1%
#eval ffactorial 5.0 -- Outputs 118.019
#eval (ffactorial 10.0).toUInt64 -- 3598695 ≈ 3628800
-- #eval (ffactorial 10.0).toNat -- 3598695 ≈ 3628800
-- Iterative factorial function for non-integer Float values
def fac_iter (n : Float) : Float :=
let rec loop (acc : Float) (i : Float) : Float :=
if i > n then acc
else loop (acc * i) (i + 1.0)
if n < 1.0 then 1.0
else loop 1.0 1.0
termination_by n - i
#eval fac_iter 5.0
def factorian : ℕ → ℝ
| (0 : Nat) => 1
| (n + 1) => (n + 1 : ℝ) * factorial n
-- def factoreal : ℝ → ℝ unsalvageable!
-- | 0 => 1
-- | (n + 1) => (n + 1) * factorial n
-- invalid patterns, `n` is an explicit pattern variable, but it only occurs in positions that are inaccessible to pattern matching .(Real.add✝ n 1)
open Real
noncomputable
def factoreal (x : ℝ) : ℝ := -- via gamma_approx
x ^ x * exp (-x) * sqrt (2 * π * x) -- Stirling's approximation
theorem factorial_pos (n : Nat) (h : n > 0) : factorial n > 0 :=
match n, h with
| 0, h => False.elim (Nat.not_succ_le_zero 0 h)
| n+1, _ =>
by
show (n + 1) * factorial n > 0
apply Nat.mul_pos
apply Nat.succ_pos
apply factorial_pos n -- induction hypothesis, assumes factorial n is positive for n
-- exact factorial_pos n (Nat.lt_trans (Nat.zero_lt_succ n) h)
-- Proof mode
theorem factorial_nonzero (n : ℕ) : factorial n ≠ 0 := by
induction n with d hd,
-- base case
simp [factorial], -- Compute mode simplification within proof mode
-- inductive step
simp [factorial], -- Simplify factorial definition
apply mul_ne_zero,
linarith, -- `linarith` tactic proves non-zero property based on linear arithmetic
exact hd,
-- theorem factorial_pos2 : ∀ (n : Nat), n > 0 → factorial n > 0 := by
-- intro n
-- cases n with
-- | zero => intro h; contradiction
-- | succ n =>
-- intro h
-- calc
-- factorial (n.succ) = (n.succ) * factorial n : by rfl
-- _ > 0 * factorial n : by
-- apply Nat.mul_pos; exact Nat.succ_pos n; apply factorial_pos n; exact Nat.succ_pos n
-- Stirling's approximation of factorial using floating-point arithmetic
def fac (n : Float) : Float :=
if n ≥ 1.0 then
Float.exp (n * Float.log n - n + 1.0)
else
0.0
noncomputable def fac (n : ℝ) : ℝ :=
if h : n ≥ 1 then
Real.exp (n * Real.log n - n + 1)
else
0
#eval fac 5