1 // arith12.cpp Copyright (C) 1990-2021 Codemist
2
3 //
4 // Arithmetic functions... specials for Reduce (esp. factoriser)
5 //
6 //
7
8
9 /**************************************************************************
10 * Copyright (C) 2021, Codemist. A C Norman *
11 * *
12 * Redistribution and use in source and binary forms, with or without *
13 * modification, are permitted provided that the following conditions are *
14 * met: *
15 * *
16 * * Redistributions of source code must retain the relevant *
17 * copyright notice, this list of conditions and the following *
18 * disclaimer. *
19 * * Redistributions in binary form must reproduce the above *
20 * copyright notice, this list of conditions and the following *
21 * disclaimer in the documentation and/or other materials provided *
22 * with the distribution. *
23 * *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
28 * COPYRIGHT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
31 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
34 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
35 * DAMAGE. *
36 *************************************************************************/
37
38
39 // $Id: arith12.cpp 5620 2021-01-26 16:16:36Z arthurcnorman $
40
41
42 #include "headers.h"
43
44
Lfrexp(LispObject env,LispObject a)45 LispObject Lfrexp(LispObject env, LispObject a)
46 {
47 #ifdef HAVE_SOFTFLOAT
48 if (is_long_float(a))
49 { float128_t d;
50 int x;
51 f128M_frexp(reinterpret_cast<float128_t *>(long_float_addr(a)), &d,
52 &x);
53 return cons(fixnum_of_int(x), make_boxfloat128(d));
54 }
55 else
56 #endif // HAVE_SOFTFLOAT
57 if (is_single_float(a))
58 { int x;
59 float d = std::frexp(single_float_val(a), &x);
60 return cons(fixnum_of_int(x), pack_single_float(d));
61 }
62 else if (is_short_float(a))
63 { int x;
64 // I can afford to do the frexp on a double here.
65 double d = std::frexp(value_of_immediate_float(a), &x);
66 return cons(fixnum_of_int(x), pack_short_float(d));
67 }
68 else
69 { int x;
70 double d = std::frexp(float_of_number(a), &x);
71 // I clearly once encountered a C library that failed on this edge case!
72 if (d == 1.0) d = 0.5, x++;
73 return cons(fixnum_of_int(x),make_boxfloat(d));
74 }
75 }
76
77 // N.B. that the modular arithmetic functions must cope with any small
78 // modulus that could fit in a fixnum.
79
Lmodular_difference(LispObject env,LispObject a,LispObject b)80 LispObject Lmodular_difference(LispObject env, LispObject a,
81 LispObject b)
82 { intptr_t r;
83 if (!modulus_is_large)
84 { if (!is_fixnum(a)) return aerror1("modular-difference", a);
85 if (!is_fixnum(b)) return aerror1("modular-difference", b);
86 r = int_of_fixnum(a) - int_of_fixnum(b);
87 if (r < 0) r += current_modulus;
88 return onevalue(fixnum_of_int(r));
89 }
90 a = difference2(a, b);
91 return modulus(a, large_modulus);
92 }
93
Lmodular_minus(LispObject env,LispObject a)94 LispObject Lmodular_minus(LispObject env, LispObject a)
95 { if (!modulus_is_large)
96 { if (!is_fixnum(a)) return aerror1("modular-minus", a);
97 if (a != fixnum_of_int(0))
98 { intptr_t r = current_modulus - int_of_fixnum(a);
99 a = fixnum_of_int(r);
100 }
101 return onevalue(a);
102 }
103 a = negate(a);
104 return modulus(a, large_modulus);
105 }
106
Lmodular_number(LispObject env,LispObject a)107 LispObject Lmodular_number(LispObject env, LispObject a)
108 { intptr_t r;
109 if (!modulus_is_large)
110 { a = Cremainder(a, fixnum_of_int(current_modulus));
111 r = int_of_fixnum(a);
112 if (r < 0) r += current_modulus;
113 return onevalue(fixnum_of_int(r));
114 }
115 return modulus(a, large_modulus);
116 }
117
Lmodular_plus(LispObject env,LispObject a,LispObject b)118 LispObject Lmodular_plus(LispObject env, LispObject a, LispObject b)
119 { intptr_t r;
120 if (!modulus_is_large)
121 { if (!is_fixnum(a)) return aerror1("modular-plus", a);
122 if (!is_fixnum(b)) return aerror1("modular-plus", b);
123 r = int_of_fixnum(a) + int_of_fixnum(b);
124 if (r >= current_modulus) r -= current_modulus;
125 return onevalue(fixnum_of_int(r));
126 }
127 a = plus2(a, b);
128 return modulus(a, large_modulus);
129 }
130
large_modular_reciprocal(LispObject n,bool safe)131 LispObject large_modular_reciprocal(LispObject n, bool safe)
132 { LispObject a, b, x, y;
133 b = n;
134 x = fixnum_of_int(0);
135 y = fixnum_of_int(1);
136 if (b == fixnum_of_int(0))
137 { if (safe) return onevalue(nil);
138 else return aerror1("modular-reciprocal", n);
139 }
140 b = modulus(b, large_modulus);
141 a = large_modulus;
142 while (b != fixnum_of_int(1))
143 { LispObject w, t;
144 if (b == fixnum_of_int(0))
145 { if (safe) return onevalue(nil);
146 else return aerror2("non-prime modulus in modular-reciprocal",
147 large_modulus, n);
148 }
149 { Save save(x, y);
150 w = quot2(a, b);
151 save.restore(x, y);
152 }
153 t = b;
154 { Save save(a, x, y, w, t);
155 b = times2(b, w);
156 save.restore(a, x, y, w, t);
157 }
158 { Save save(x, y, w, t);
159 b = difference2(a, b);
160 save.restore(x, y, w, t);
161 }
162 a = t;
163 t = y;
164 { Save save(a, b, x, t);
165 y = times2(y, w);
166 save.restore(a, b, x, t);
167 }
168 { Save save(a, b, t);
169 y = difference2(x, y);
170 save.restore(a, b, t);
171 }
172 x = t;
173 }
174 y = modulus(y, large_modulus);
175 return onevalue(y);
176 }
177
Lmodular_reciprocal(LispObject,LispObject n)178 LispObject Lmodular_reciprocal(LispObject, LispObject n)
179 { intptr_t a, b, x, y;
180 if (modulus_is_large) return large_modular_reciprocal(n, false);
181 // If the modulus is "small" I can do all this using native integer
182 // arithmetic.
183 if (!is_fixnum(n)) return aerror1("modular-reciprocal", n);
184 a = current_modulus;
185 b = int_of_fixnum(n);
186 x = 0;
187 y = 1;
188 if (b == 0) return aerror1("modular-reciprocal", n);
189 if (b < 0) b = current_modulus - ((-b)%current_modulus);
190 while (b != 1)
191 { intptr_t w, t;
192 if (b == 0)
193 return aerror2("non-prime modulus in modular-reciprocal",
194 fixnum_of_int(current_modulus), n);
195 w = a / b;
196 t = b;
197 b = a - b*w;
198 a = t;
199 t = y;
200 y = x - y*w;
201 x = t;
202 }
203 if (y < 0) y += current_modulus;
204 return onevalue(fixnum_of_int(y));
205 }
206
Lsafe_modular_reciprocal(LispObject env,LispObject n)207 LispObject Lsafe_modular_reciprocal(LispObject env, LispObject n)
208 { intptr_t a, b, x, y;
209 if (modulus_is_large) return large_modular_reciprocal(n, true);
210 if (!is_fixnum(n)) return aerror1("modular-reciprocal", n);
211 a = current_modulus;
212 b = int_of_fixnum(n);
213 x = 0;
214 y = 1;
215 if (b == 0) return onevalue(nil);
216 if (b < 0) b = current_modulus - ((-b)%current_modulus);
217 while (b != 1)
218 { intptr_t w, t;
219 if (b == 0) return onevalue(nil);
220 w = a / b;
221 t = b;
222 b = a - b*w;
223 a = t;
224 t = y;
225 y = x - y*w;
226 x = t;
227 }
228 if (y < 0) y += current_modulus;
229 return onevalue(fixnum_of_int(y));
230 }
231
Lmodular_times(LispObject env,LispObject a,LispObject b)232 LispObject Lmodular_times(LispObject env, LispObject a, LispObject b)
233 { uintptr_t cm;
234 intptr_t aa, bb;
235 if (!modulus_is_large)
236 { if (!is_fixnum(a)) return aerror1("modular-times", a);
237 if (!is_fixnum(b)) return aerror1("modular-times", b);
238 cm = (uintptr_t)current_modulus;
239 aa = int_of_fixnum(a);
240 bb = int_of_fixnum(b);
241 // If I am on a 32-bit machine and the modulus is at worst 16 bits I can use
242 // 32-bit arithmetic to complete the job.
243 if (!SIXTY_FOUR_BIT && cm <= 0xffffU)
244 { uint32_t r = ((uint32_t)aa * (uint32_t)bb) % (uint32_t)cm;
245 return onevalue(fixnum_of_int((intptr_t)r));
246 }
247 // On a 32 or 64-bit machine if the modulus is at worst 32 bits I can do
248 // a 64-bit (unsigned) multiplication and remainder step.
249 else if (cm <= 0xffffffffU)
250 { uint64_t r = ((uint64_t)aa*(uint64_t)bb) % (uint64_t)cm;
251 // Because I am in a state where modulus_is_large is not set I know that the
252 // modulus fits in a fixnum, hence the result will. So even though all value
253 // that are of type uint64_t might not be valid as fixnums the one I have
254 // here will be.
255 return onevalue(fixnum_of_int((intptr_t)r));
256 }
257 // Now my modulus is over 32-bits...
258 // Using an int128_t bit type I can use it and the code is really neat!
259 // On some platforms this goes via C++ templates and operator overloading
260 // into a software implementation of 128-bit integer arithmetic!
261 else
262 { int64_t r = static_cast<int64_t>(
263 (static_cast<int128_t>(aa) * static_cast<int128_t>(bb)) %
264 static_cast<int128_t>(cm));
265 return onevalue(fixnum_of_int((intptr_t)r));
266 }
267 }
268 a = times2(a, b);
269 return modulus(a, large_modulus);
270 }
271
Lmodular_quotient(LispObject env,LispObject a,LispObject b)272 LispObject Lmodular_quotient(LispObject env, LispObject a,
273 LispObject b)
274 { { Save save(a);
275 b = Lmodular_reciprocal(nil, b);
276 errexit();
277 save.restore(a);
278 }
279 return Lmodular_times(nil, a, b);
280 }
281
large_modular_expt(LispObject a,int x)282 LispObject large_modular_expt(LispObject a, int x)
283 { LispObject r, p, w;
284 p = modulus(a, large_modulus);
285 errexit();
286 while ((x & 1) == 0)
287 { p = times2(p, p);
288 errexit();
289 p = modulus(p, large_modulus);
290 errexit();
291 x = x/2;
292 }
293 r = p;
294 while (x != 1)
295 { Save save(r);
296 w = times2(p, p);
297 errexit();
298 p = modulus(w, large_modulus);
299 errexit();
300 save.restore(r);
301 x = x/2;
302 if ((x & 1) != 0)
303 { Save save1(p);
304 w = times2(r, p);
305 errexit();
306 r = modulus(w, large_modulus);
307 errexit();
308 save1.restore(p);
309 }
310 }
311 return onevalue(r);
312 }
313
muldivptr(uintptr_t a,uintptr_t b,uintptr_t c)314 inline intptr_t muldivptr(uintptr_t a, uintptr_t b, uintptr_t c)
315 { if (!SIXTY_FOUR_BIT || c <= 0xffffffffU)
316 return ((uint64_t)a*(uint64_t)b)%(uintptr_t)c;
317 else return (intptr_t)static_cast<int64_t>(
318 (uint128((uint64_t)a) * uint128((uint64_t)a)) % (uintptr_t)c);
319 }
320
Lmodular_expt(LispObject env,LispObject a,LispObject b)321 LispObject Lmodular_expt(LispObject env, LispObject a, LispObject b)
322 { intptr_t x, r, p;
323 x = int_of_fixnum(b);
324 if (x == 0) return onevalue(fixnum_of_int(1));
325 if (modulus_is_large) return large_modular_expt(a, x);
326 p = int_of_fixnum(a);
327 p = p % current_modulus; // In case somebody is being silly!
328 // I now want this to work for any modulus up to the size of the largest
329 // fixnum. That could be 60-bits in the newer world. The function
330 // muldivptr takes unsigned arguments but that should be OK because any
331 // valid modulus and any valid modular number will be positive.
332 while ((x & 1) == 0)
333 { p = muldivptr((uintptr_t)p, (uintptr_t)p,
334 (uintptr_t)current_modulus);
335 x = x/2;
336 }
337 r = p;
338 while (x != 1)
339 { p = muldivptr((uintptr_t)p, (uintptr_t)p,
340 (uintptr_t)current_modulus);
341 x = x/2;
342 if ((x & 1) != 0)
343 { r = muldivptr((uintptr_t)r, (uintptr_t)p,
344 (uintptr_t)current_modulus);
345 }
346 }
347 return onevalue(fixnum_of_int(r));
348 }
349
350 // I can set any (positive) integer as a modulus here. I will treat it
351 // internally as "small" if it fits in a fixnum.
352
Lset_small_modulus(LispObject env,LispObject a)353 LispObject Lset_small_modulus(LispObject env, LispObject a)
354 { LispObject old = modulus_is_large ? large_modulus :
355 fixnum_of_int(current_modulus);
356 if (a==nil) return onevalue(old);
357 else if (!is_fixnum(a))
358 { if (!is_numbers(a) ||
359 !is_bignum(a) ||
360 minusp(a))
361 return aerror1("set-small-modulus", a);
362 modulus_is_large = 1;
363 current_modulus = 0; // should not be referenced.
364 large_modulus = a;
365 return old;
366 }
367 if ((intptr_t)a < 0 || a == fixnum_of_int(0))
368 return aerror1("set!-small!-modulus", a);
369 modulus_is_large = 0;
370 large_modulus = nil; // Should not be referenced.
371 current_modulus = int_of_fixnum(a);;
372 return onevalue(old);
373 }
374
Liadd1(LispObject,LispObject a)375 LispObject Liadd1(LispObject, LispObject a)
376 { if (!is_fixnum(a)) return aerror1("iadd1", a);
377 return onevalue(static_cast<LispObject>((intptr_t)a + 0x10));
378 }
379
Lidifference_2(LispObject,LispObject a,LispObject b)380 LispObject Lidifference_2(LispObject, LispObject a, LispObject b)
381 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("idifference", a, b);
382 return onevalue(static_cast<LispObject>((intptr_t)a -
383 (intptr_t)b + TAG_FIXNUM));
384 }
385
386 // xdifference is provided just for the support of the CASE operator. It
387 // subtracts its arguments but returns NIL if either argument is not
388 // an small integer or if the result overflows. Small is 28-bits in this
389 // context at present, which is maybe strange!
390
Lxdifference(LispObject env,LispObject a,LispObject b)391 LispObject Lxdifference(LispObject env, LispObject a, LispObject b)
392 { int32_t r;
393 if (!is_fixnum(a) || !is_fixnum(b)) return onevalue(nil);
394 r = int_of_fixnum(a) - int_of_fixnum(b);
395 if (r < -0x08000000 || r > 0x07ffffff) return onevalue(nil);
396 return onevalue(fixnum_of_int(r));
397 }
398
Ligreaterp_2(LispObject env,LispObject a,LispObject b)399 LispObject Ligreaterp_2(LispObject env, LispObject a, LispObject b)
400 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("igreaterp", a, b);
401 return onevalue(Lispify_predicate(a > b));
402 }
403
Lilessp_2(LispObject env,LispObject a,LispObject b)404 LispObject Lilessp_2(LispObject env, LispObject a, LispObject b)
405 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("ilessp", a, b);
406 return onevalue(Lispify_predicate(a < b));
407 }
408
Ligeq_2(LispObject env,LispObject a,LispObject b)409 LispObject Ligeq_2(LispObject env, LispObject a, LispObject b)
410 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("igeq", a, b);
411 return onevalue(Lispify_predicate(a >= b));
412 }
413
Lileq_2(LispObject env,LispObject a,LispObject b)414 LispObject Lileq_2(LispObject env, LispObject a, LispObject b)
415 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("ileq", a, b);
416 return onevalue(Lispify_predicate(a <= b));
417 }
418
Lilogand_0(LispObject)419 static LispObject Lilogand_0(LispObject)
420 { return onevalue(fixnum_of_int(-1));
421 }
422
Lilogor_0(LispObject)423 static LispObject Lilogor_0(LispObject)
424 { return onevalue(fixnum_of_int(0));
425 }
426
Lilogxor_0(LispObject)427 static LispObject Lilogxor_0(LispObject)
428 { return onevalue(fixnum_of_int(0));
429 }
430
Lilogand_1(LispObject,LispObject a1)431 static LispObject Lilogand_1(LispObject, LispObject a1)
432 { return onevalue(a1);
433 }
434
Lilogor_1(LispObject,LispObject a1)435 static LispObject Lilogor_1(LispObject, LispObject a1)
436 { return onevalue(a1);
437 }
438
Lilogxor_1(LispObject,LispObject a1)439 static LispObject Lilogxor_1(LispObject, LispObject a1)
440 { return onevalue(a1);
441 }
442
Lilogand_2(LispObject,LispObject a1,LispObject a2)443 static LispObject Lilogand_2(LispObject, LispObject a1, LispObject a2)
444 { if (!is_fixnum(a1) || !is_fixnum(a2)) return aerror2("ilogand", a1, a2);
445 return onevalue(a1 & a2);
446 }
447
Lilogor_2(LispObject,LispObject a1,LispObject a2)448 static LispObject Lilogor_2(LispObject, LispObject a1, LispObject a2)
449 { if (!is_fixnum(a1) || !is_fixnum(a2)) return aerror2("ilogor", a1, a2);
450 return onevalue(a1 | a2);
451 }
452
Lilogxor_2(LispObject,LispObject a1,LispObject a2)453 static LispObject Lilogxor_2(LispObject, LispObject a1, LispObject a2)
454 { if (!is_fixnum(a1) || !is_fixnum(a2)) return aerror2("ilogxor", a1, a2);
455 return onevalue((a1 ^ a2) + TAG_FIXNUM);
456 }
457
Lilogand_3(LispObject,LispObject a1,LispObject a2,LispObject a3)458 static LispObject Lilogand_3(LispObject, LispObject a1, LispObject a2,
459 LispObject a3)
460 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
461 return aerror3("ilogand", a2, a2, a3);
462 return onevalue(a1 & a2 & a3);
463 }
464
Lilogor_3(LispObject,LispObject a1,LispObject a2,LispObject a3)465 static LispObject Lilogor_3(LispObject, LispObject a1, LispObject a2,
466 LispObject a3)
467 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
468 return aerror3("ilogor", a2, a2, a3);
469 return onevalue(a1 | a2 | a3);
470 }
471
Lilogxor_3(LispObject,LispObject a1,LispObject a2,LispObject a3)472 static LispObject Lilogxor_3(LispObject, LispObject a1, LispObject a2,
473 LispObject a3)
474 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
475 return aerror3("ilogxor", a2, a2, a3);
476 return onevalue(a1 ^ a2 ^ a3);
477 }
478
Lilogand_4up(LispObject env,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)479 static LispObject Lilogand_4up(LispObject env, LispObject a1,
480 LispObject a2,
481 LispObject a3, LispObject a4up)
482 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
483 return aerror3("ilogand", a2, a2, a3);
484 a1 = a1 & a2 & a3;
485 while (a4up != nil)
486 { a2 = car(a4up);
487 a4up = cdr(a4up);
488 if (!is_fixnum(a2)) return aerror1("ilogand", a2);
489 a1 = a1 & a2;
490 }
491 return onevalue(a1);
492 }
493
Lilogor_4up(LispObject env,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)494 static LispObject Lilogor_4up(LispObject env, LispObject a1,
495 LispObject a2,
496 LispObject a3, LispObject a4up)
497 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
498 return aerror3("ilogor", a2, a2, a3);
499 a1 = a1 | a2 | a3;
500 while (a4up != nil)
501 { a2 = car(a4up);
502 a4up = cdr(a4up);
503 if (!is_fixnum(a2)) return aerror1("ilogor", a2);
504 a1 = a1 | a2;
505 }
506 return onevalue(a1);
507 }
508
Lilogxor_4up(LispObject env,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)509 static LispObject Lilogxor_4up(LispObject env, LispObject a1,
510 LispObject a2,
511 LispObject a3, LispObject a4up)
512 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
513 return aerror3("ilogxor", a2, a2, a3);
514 a1 = a1 ^ a2 ^ a3;
515 while (a4up != nil)
516 { a2 = car(a4up);
517 a4up = cdr(a4up);
518 if (!is_fixnum(a2)) return aerror1("ilogxor", a2);
519 a1 = a1 ^ a2;
520 }
521 a1 = (a1 & ~static_cast<LispObject>(TAG_BITS)) | TAG_FIXNUM;
522 return onevalue(a1);
523 }
524
Limin_2(LispObject,LispObject a,LispObject b)525 LispObject Limin_2(LispObject, LispObject a, LispObject b)
526 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("imin", a, b);
527 return onevalue(a < b ? a : b);
528 }
529
Limax_2(LispObject,LispObject a,LispObject b)530 LispObject Limax_2(LispObject, LispObject a, LispObject b)
531 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("imax", a, b);
532 return onevalue(a > b ? a : b);
533 }
534
Liminus(LispObject,LispObject a)535 LispObject Liminus(LispObject, LispObject a)
536 { if (!is_fixnum(a)) return aerror1("iminus", a);
537 return onevalue(static_cast<LispObject>(2*TAG_FIXNUM - (intptr_t)a));
538 }
539
Liminusp(LispObject env,LispObject a)540 LispObject Liminusp(LispObject env, LispObject a)
541 { return onevalue(Lispify_predicate((intptr_t)a <
542 (intptr_t)fixnum_of_int(0)));
543 }
544
Liplus_0(LispObject)545 LispObject Liplus_0(LispObject)
546 { return onevalue(fixnum_of_int(1));
547 }
548
Liplus_1(LispObject,LispObject a1)549 LispObject Liplus_1(LispObject, LispObject a1)
550 { return onevalue(a1);
551 }
552
Liplus_2(LispObject,LispObject a1,LispObject a2)553 LispObject Liplus_2(LispObject, LispObject a1, LispObject a2)
554 { if (!is_fixnum(a1) || !is_fixnum(a2)) return aerror2("iplus2", a1, a2);
555 return onevalue(static_cast<LispObject>((intptr_t)a1 +
556 (intptr_t)a2 - TAG_FIXNUM));
557 }
558
Liplus_3(LispObject,LispObject a1,LispObject a2,LispObject a3)559 LispObject Liplus_3(LispObject, LispObject a1, LispObject a2,
560 LispObject a3)
561 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
562 return aerror3("iplus", a1, a2, a3);
563 return onevalue(static_cast<LispObject>((intptr_t)a1 +
564 (intptr_t)a2 - 2*TAG_FIXNUM +
565 (intptr_t)a3));
566 }
567
Liplus_4up(LispObject,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)568 static LispObject Liplus_4up(LispObject, LispObject a1, LispObject a2,
569 LispObject a3, LispObject a4up)
570 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
571 return aerror3("iplus", a1, a2, a3);
572 a1 = (intptr_t)a1 + (intptr_t)a2 - 2*TAG_FIXNUM + (intptr_t)a3;
573 while (a4up != nil)
574 { a2 = car(a4up);
575 a4up = cdr(a4up);
576 if (!is_fixnum(a2)) return aerror1("iplus", a2);
577 a1 = a1 + (intptr_t)a2 - TAG_FIXNUM;
578 }
579 return onevalue(a1);
580 }
581
Liquotient_2(LispObject,LispObject a,LispObject b)582 LispObject Liquotient_2(LispObject, LispObject a, LispObject b)
583 { intptr_t aa, bb, c;
584 if (!is_fixnum(a) || !is_fixnum(b) ||
585 b == fixnum_of_int(0)) return aerror2("iquotient", a, b);
586 // C does not define the exact behaviour of /, % on -ve args
587 aa = int_of_fixnum(a);
588 bb = int_of_fixnum(b);
589 c = aa % bb;
590 if (aa < 0)
591 { if (c > 0) c -= bb;
592 }
593 else if (c < 0) c += bb;
594 return onevalue(fixnum_of_int((aa-c)/bb));
595 }
596
Liremainder_2(LispObject,LispObject a,LispObject b)597 LispObject Liremainder_2(LispObject, LispObject a, LispObject b)
598 { intptr_t aa, bb, c;
599 if (!is_fixnum(a) || !is_fixnum(b) ||
600 b == fixnum_of_int(0)) return aerror2("iremainder", a, b);
601 // C does not define the exact behaviour of /, % on -ve args
602 aa = int_of_fixnum(a);
603 bb = int_of_fixnum(b);
604 c = aa % bb;
605 if (aa < 0)
606 { if (c > 0) c -= bb;
607 }
608 else if (c < 0) c += bb;
609 return onevalue(fixnum_of_int(c));
610 }
611
Lirightshift(LispObject,LispObject a,LispObject b)612 LispObject Lirightshift(LispObject, LispObject a, LispObject b)
613 { if (!is_fixnum(a) || !is_fixnum(b)) return aerror2("irightshift", a, b);
614 return onevalue(fixnum_of_int(int_of_fixnum(a) >> int_of_fixnum(b)));
615 }
616
Lisub1(LispObject,LispObject a)617 LispObject Lisub1(LispObject, LispObject a)
618 { if (!is_fixnum(a)) return aerror1("isub1", a);
619 return onevalue(static_cast<LispObject>((intptr_t)a - 0x10));
620 }
621
Litimes_0(LispObject)622 LispObject Litimes_0(LispObject)
623 { return onevalue(fixnum_of_int(1));
624 }
625
Litimes_1(LispObject,LispObject a1)626 LispObject Litimes_1(LispObject, LispObject a1)
627 { return onevalue(a1);
628 }
629
Litimes_2(LispObject,LispObject a1,LispObject a2)630 LispObject Litimes_2(LispObject, LispObject a1, LispObject a2)
631 { if (!is_fixnum(a1) || !is_fixnum(a2)) return aerror2("itimes2", a1, a2);
632 return onevalue(fixnum_of_int(int_of_fixnum(a1) * int_of_fixnum(a2)));
633 }
634
Litimes_3(LispObject,LispObject a1,LispObject a2,LispObject a3)635 LispObject Litimes_3(LispObject, LispObject a1, LispObject a2,
636 LispObject a3)
637 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
638 return aerror3("itimes", a1, a2, a3);
639 return onevalue(fixnum_of_int(int_of_fixnum(a1) *
640 int_of_fixnum(a2) *
641 int_of_fixnum(a3)));
642 }
643
Litimes_4up(LispObject env,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)644 static LispObject Litimes_4up(LispObject env, LispObject a1,
645 LispObject a2,
646 LispObject a3, LispObject a4up)
647 { if (!is_fixnum(a1) || !is_fixnum(a2) || !is_fixnum(a3))
648 return aerror3("iplus", a1, a2, a3);
649 intptr_t r = int_of_fixnum(a1) * int_of_fixnum(a2) * int_of_fixnum(
650 a3);
651 while (a4up != nil)
652 { a2 = car(a4up);
653 a4up = cdr(a4up);
654 if (!is_fixnum(a2)) return aerror1("itimes", a2);
655 r = r * int_of_fixnum(a2);
656 }
657 return onevalue(fixnum_of_int(r));
658 }
659
Lionep(LispObject env,LispObject a)660 LispObject Lionep(LispObject env, LispObject a)
661 { return onevalue(Lispify_predicate((intptr_t)a ==
662 (intptr_t)fixnum_of_int(1)));
663 }
664
Lizerop(LispObject env,LispObject a)665 LispObject Lizerop(LispObject env, LispObject a)
666 { return onevalue(Lispify_predicate((intptr_t)a ==
667 (intptr_t)fixnum_of_int(0)));
668 }
669
670 static double fp_args[32];
671 static double fp_stack[16];
672
673 // codes 0 to 31 just load up arguments
674 #define FP_RETURN 32
675 #define FP_PLUS 33
676 #define FP_DIFFERENCE 34
677 #define FP_TIMES 35
678 #define FP_QUOTIENT 36
679 #define FP_MINUS 37
680 #define FP_SQUARE 38
681 #define FP_CUBE 39
682 #define FP_SIN 40
683 #define FP_COS 41
684 #define FP_TAN 42
685 #define FP_EXP 43
686 #define FP_LOG 44
687 #define FP_SQRT 45
688
689
Lfp_eval(LispObject env,LispObject code,LispObject args)690 static LispObject Lfp_eval(LispObject env, LispObject code,
691 LispObject args)
692 // The object of this code is to support fast evaluation of numeric
693 // expressions. The first argument is a vector of byte opcodes, while
694 // the second arg is a list of floating point values whose value will (or
695 // at least may) be used. There are at most 32 values in this list.
696 { int n = 0;
697 double w;
698 unsigned char *p;
699 if (!is_vector(code)) return aerror("fp-evaluate");
700 while (consp(args))
701 { fp_args[n++] = float_of_number(car(args));
702 args = cdr(args);
703 }
704 n = 0;
705 p = reinterpret_cast<unsigned char *>(&ucelt(code, 0));
706 for (;;)
707 { int op = *p++;
708 // Opcodes 0 to 31 just load up the corresponding input value.
709 if (op < 32)
710 { fp_stack[n++] = fp_args[op];
711 continue;
712 }
713 switch (op)
714 { default:
715 return aerror("Bad op in fp-evaluate");
716 case FP_RETURN:
717 args = make_boxfloat(fp_stack[0], TYPE_DOUBLE_FLOAT);
718 return onevalue(args);
719 case FP_PLUS:
720 n--;
721 fp_stack[n] += fp_stack[n-1];
722 continue;
723 case FP_DIFFERENCE:
724 n--;
725 fp_stack[n] -= fp_stack[n-1];
726 continue;
727 case FP_TIMES:
728 n--;
729 fp_stack[n] *= fp_stack[n-1];
730 continue;
731 case FP_QUOTIENT:
732 n--;
733 fp_stack[n] /= fp_stack[n-1];
734 continue;
735 case FP_MINUS:
736 fp_stack[n] = -fp_stack[n];
737 continue;
738 case FP_SQUARE:
739 fp_stack[n] *= fp_stack[n];
740 continue;
741 case FP_CUBE:
742 w = fp_stack[n];
743 w *= w;
744 fp_stack[n] *= w;
745 continue;
746 case FP_SIN:
747 fp_stack[n] = std::sin(fp_stack[n]);
748 continue;
749 case FP_COS:
750 fp_stack[n] = std::cos(fp_stack[n]);
751 continue;
752 case FP_TAN:
753 fp_stack[n] = std::tan(fp_stack[n]);
754 continue;
755 case FP_EXP:
756 fp_stack[n] = std::exp(fp_stack[n]);
757 continue;
758 case FP_LOG:
759 fp_stack[n] = std::log(fp_stack[n]);
760 continue;
761 case FP_SQRT:
762 fp_stack[n] = std::sqrt(fp_stack[n]);
763 continue;
764 }
765 }
766 }
767
768 setup_type const arith12_setup[] =
769 { DEF_1("frexp", Lfrexp),
770 DEF_2("modular-difference", Lmodular_difference),
771 DEF_1("modular-minus", Lmodular_minus),
772 DEF_1("modular-number", Lmodular_number),
773 DEF_2("modular-plus", Lmodular_plus),
774 DEF_2("modular-quotient", Lmodular_quotient),
775 DEF_1("modular-reciprocal", Lmodular_reciprocal),
776 DEF_1("safe-modular-reciprocal", Lsafe_modular_reciprocal),
777 DEF_2("modular-times", Lmodular_times),
778 DEF_2("modular-expt", Lmodular_expt),
779 DEF_1("set-small-modulus", Lset_small_modulus),
780 DEF_1("iadd1", Liadd1),
781 DEF_2("idifference", Lidifference_2),
782 DEF_2("xdifference", Lxdifference),
783 DEF_2("igeq", Ligeq_2),
784 DEF_2("igreaterp", Ligreaterp_2),
785 DEF_2("ileq", Lileq_2),
786 DEF_2("ilessp", Lilessp_2),
787 {"ilogand", Lilogand_0, Lilogand_1, Lilogand_2, Lilogand_3, Lilogand_4up},
788 {"ilogor", Lilogor_0, Lilogor_1, Lilogor_2, Lilogor_3, Lilogor_4up},
789 {"ilogxor", Lilogxor_0, Lilogxor_1, Lilogxor_2, Lilogxor_3, Lilogxor_4up},
790 DEF_2("imax", Limax_2),
791 DEF_2("imin", Limin_2),
792 DEF_1("iminus", Liminus),
793 DEF_1("iminusp", Liminusp),
794 {"iplus", Liplus_0, Liplus_1, Liplus_2, Liplus_3, Liplus_4up},
795 DEF_2("iplus2", Liplus_2),
796 DEF_2("iquotient", Liquotient_2),
797 DEF_2("iremainder", Liremainder_2),
798 DEF_2("irightshift", Lirightshift),
799 DEF_1("isub1", Lisub1),
800 {"itimes", Litimes_0, Litimes_1, Litimes_2, Litimes_3, Litimes_4up},
801 DEF_2("itimes2", Litimes_2),
802 DEF_1("ionep", Lionep),
803 DEF_1("izerop", Lizerop),
804 DEF_2("fp-evaluate", Lfp_eval),
805 {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}
806 };
807
808 // end of arith12.cpp
809