1/*
2 * mod - routines to handle numbers modulo a specified number
3 *
4 * Copyright (C) 1999  David I. Bell
5 *
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
9 *
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU Lesser General
13 * Public License for more details.
14 *
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL.  You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 *
20 * Under source code control:	1990/02/15 01:50:34
21 * File existed as early as:	before 1990
22 *
23 * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/
24 */
25
26
27obj mod {a};			/* definition of the object */
28
29global mod_value = 100;		/* modulus value (value of N) */
30
31
32define lmod(a)
33{
34	local obj mod	x;
35
36	if (!isreal(a) || !isint(a))
37		quit "Bad argument for lmod function";
38	x.a = a % mod_value;
39	return x;
40}
41
42
43define mod_print(a)
44{
45	if (digits(mod_value) <= 20)
46		print a.a, "(mod", mod_value : ")" :;
47	else
48		print a.a, "(mod N)" :;
49}
50
51
52define mod_one()
53{
54	return lmod(1);
55}
56
57
58define mod_cmp(a, b)
59{
60	if (isnum(a))
61		return (a % mod_value) != b.a;
62	if (isnum(b))
63		return (b % mod_value) != a.a;
64	return a.a != b.a;
65}
66
67
68define mod_rel(a, b)
69{
70	if (isnum(a))
71		a = lmod(a);
72	if (isnum(b))
73		b = lmod(b);
74	if (a.a < b.a)
75		return -1;
76	return a.a != b.a;
77}
78
79
80define mod_add(a, b)
81{
82	local obj mod	x;
83
84	if (isnum(b)) {
85		if (!isint(b))
86			quit "Adding non-integer";
87		x.a = (a.a + b) % mod_value;
88		return x;
89	}
90	if (isnum(a)) {
91		if (!isint(a))
92			quit "Adding non-integer";
93		x.a = (a + b.a) % mod_value;
94		return x;
95	}
96	x.a = (a.a + b.a) % mod_value;
97	return x;
98}
99
100
101define mod_sub(a, b)
102{
103	return a + (-b);
104}
105
106
107define mod_neg(a)
108{
109	local obj mod	x;
110
111	x.a = mod_value - a.a;
112	return x;
113}
114
115
116define mod_mul(a, b)
117{
118	local obj mod	x;
119
120	if (isnum(b)) {
121		if (!isint(b))
122			quit "Multiplying by non-integer";
123		x.a = (a.a * b) % mod_value;
124		return x;
125	}
126	if (isnum(a)) {
127		if (!isint(a))
128			quit "Multiplying by non-integer";
129		x.a = (a * b.a) % mod_value;
130		return x;
131	}
132	x.a = (a.a * b.a) % mod_value;
133	return x;
134}
135
136
137define mod_square(a)
138{
139	local obj mod	x;
140
141	x.a = a.a^2 % mod_value;
142	return x;
143}
144
145
146define mod_inc(a)
147{
148	local x;
149
150	x = a;
151	if (++x.a == mod_value)
152		x.a = 0;
153	return x;
154}
155
156
157define mod_dec(a)
158{
159	local x;
160
161	x = a;
162	if (--x.a < 0)
163		x.a = mod_value - 1;
164	return x;
165}
166
167
168define mod_inv(a)
169{
170	local obj mod	x;
171
172	x.a = minv(a.a, mod_value);
173	return x;
174}
175
176
177define mod_div(a, b)
178{
179	local c;
180	local obj mod x;
181	local obj mod y;
182	if (isnum(a))
183		a = lmod(a);
184	if (isnum(b))
185		b = lmod(b);
186	c = gcd(a.a, b.a);
187	x.a = a.a / c;
188	y.a = b.a / c;
189	return x * inverse(y);
190}
191
192
193define mod_pow(a, b)
194{
195	local x, y, z;
196
197	obj mod x;
198	y = a;
199	z = b;
200	if (b < 0) {
201		y = inverse(a);
202		z = -b;
203	}
204	x.a = pmod(y.a, z, mod_value);
205	return x;
206}
207
208
209if (config("resource_debug") & 3) {
210    print "obj mod {a} defined";
211    print "mod_value defined";
212    print "set mod_value as needed";
213}
214