-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodular.ts
More file actions
141 lines (116 loc) · 3.77 KB
/
modular.ts
File metadata and controls
141 lines (116 loc) · 3.77 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import divide from "./divide";
import multiply from "./multiply";
import subtract from "./subtract";
import compare, { isEqual } from "./compare";
import { floor } from "./rounding";
import { parseStringNumber, isInteger, isZero } from "./utils";
import abs from "./abs";
import add from "./add";
/**
* Modulo operation (remainder after division)
* For positive numbers: a mod n = a - n * floor(a/n)
* Result always has the same sign as the divisor n
* @param dividend The number being divided
* @param divisor The number to divide by
* @returns Remainder as string
*/
export function mod(dividend: string, divisor: string): string {
if (isZero(divisor)) {
throw new Error("Division by zero in modulo operation");
}
if (!isInteger(dividend) || !isInteger(divisor)) {
throw new Error("Modulo operation requires integer arguments");
}
if (isZero(dividend)) {
return "0";
}
// Calculate quotient using floor division
const quotient = divide(dividend, divisor, 0);
const flooredQuotient = floor(quotient);
// Calculate remainder: dividend - divisor * floor(dividend/divisor)
const product = multiply(divisor, flooredQuotient);
const remainder = subtract(dividend, product);
// Ensure result has same sign as divisor (mathematical modulo)
const divisorParsed = parseStringNumber(divisor);
const remainderParsed = parseStringNumber(remainder);
if (isZero(remainder)) {
return "0";
}
// If remainder and divisor have different signs, adjust
if (divisorParsed.sign !== remainderParsed.sign) {
return add(remainder, divisor);
}
return remainder;
}
/**
* Euclidean algorithm for Greatest Common Divisor
* @param a First number as string
* @param b Second number as string
* @returns GCD as string
*/
export function gcd(a: string, b: string): string {
if (!isInteger(a) || !isInteger(b)) {
throw new Error("GCD requires integer arguments");
}
// Work with absolute values
let numA = abs(a);
let numB = abs(b);
if (isZero(numA)) {
return numB;
}
if (isZero(numB)) {
return numA;
}
// Euclidean algorithm: gcd(a,b) = gcd(b, a mod b)
while (!isZero(numB)) {
const temp = numB;
numB = mod(numA, numB);
numA = temp;
}
return numA;
}
/**
* Least Common Multiple using the formula: lcm(a,b) = |a*b| / gcd(a,b)
* @param a First number as string
* @param b Second number as string
* @returns LCM as string
*/
export function lcm(a: string, b: string): string {
if (!isInteger(a) || !isInteger(b)) {
throw new Error("LCM requires integer arguments");
}
if (isZero(a) || isZero(b)) {
return "0";
}
// lcm(a,b) = |a*b| / gcd(a,b)
const product = multiply(abs(a), abs(b));
const gcdResult = gcd(a, b);
return divide(product, gcdResult, 0);
}
/**
* Remainder operation (different from modulo for negative numbers)
* Result has the same sign as the dividend
* @param dividend The number being divided
* @param divisor The number to divide by
* @returns Remainder as string
*/
export function remainder(dividend: string, divisor: string): string {
if (isZero(divisor)) {
throw new Error("Division by zero in remainder operation");
}
if (!isInteger(dividend) || !isInteger(divisor)) {
throw new Error("Remainder operation requires integer arguments");
}
if (isZero(dividend)) {
return "0";
}
// For remainder operation, we use truncated division
const quotient = divide(dividend, divisor, 0);
// Truncate towards zero (different from floor for negative numbers)
const truncatedQuotient = quotient.startsWith("-") ?
"-" + floor(quotient.substring(1)) :
floor(quotient);
// Calculate remainder: dividend - divisor * truncate(dividend/divisor)
const product = multiply(divisor, truncatedQuotient);
return subtract(dividend, product);
}