From 281fd68db3e429cabc1edc6445c3d7fdd2d2a04a Mon Sep 17 00:00:00 2001
From: Ayoub Chegraoui <ayoubch807@gmail.com>
Date: Mon, 23 Oct 2023 07:25:38 +0100
Subject: [PATCH] Feat: add euler's totient function

---
 maths/euler_totient.ts           | 20 ++++++++++++++++++++
 maths/test/euler_totient.test.ts | 24 ++++++++++++++++++++++++
 2 files changed, 44 insertions(+)
 create mode 100644 maths/euler_totient.ts
 create mode 100644 maths/test/euler_totient.test.ts

diff --git a/maths/euler_totient.ts b/maths/euler_totient.ts
new file mode 100644
index 00000000..482281c4
--- /dev/null
+++ b/maths/euler_totient.ts
@@ -0,0 +1,20 @@
+/**
+ * @description counts the positive integers up to a given integer n that are relatively prime to n.
+ * @param {number} n - A natural number.
+ * @return {number} - euler's totient.
+ * @see https://en.wikipedia.org/wiki/Euler%27s_totient_function
+ * @example phi(4) = 2
+ * @example phi(5) = 4
+ */
+export const phi = (n: number): number => {
+    let result: number = n;
+    for (let i = 2; i * i <= n; i++) {
+        if (n % i == 0) {
+            while (n % i == 0) n = n / i;
+            result -= Math.floor(result / i);
+        }
+    }
+    if (n > 1) result -= Math.floor(result / n);
+
+    return result;
+};
diff --git a/maths/test/euler_totient.test.ts b/maths/test/euler_totient.test.ts
new file mode 100644
index 00000000..4d1ec6b7
--- /dev/null
+++ b/maths/test/euler_totient.test.ts
@@ -0,0 +1,24 @@
+import { phi } from "../euler_totient";
+
+
+const cases: [number, number][] = [
+    [4, 2],
+    [5, 4],
+    [7, 6],
+    [10, 4],
+    [999, 648],
+    [1000, 400],
+    [1000000, 400000],
+    [999999, 466560],
+    [999999999999878, 473684210526240],
+];
+
+describe("phi", () => {
+
+    test.each(cases)(
+        "phi of %i should be %i",
+        (num, expected) => {
+            expect(phi(num)).toBe(expected);
+        },
+    );
+});