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