1 /*
2 This file is part of GNU APL, a free implementation of the
3 ISO/IEC Standard 13751, "Programming Language APL, Extended"
4
5 Copyright (C) 2008-2015 Dr. Jürgen Sauermann
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24
25 #include <complex>
26
27 #include "Common.hh"
28 #include "ComplexCell.hh"
29 #include "Error.hh"
30 #include "FloatCell.hh"
31 #include "IntCell.hh"
32 #include "UTF8_string.hh"
33 #include "Workspace.hh"
34
35 #include "Cell.icc"
36 #include "Value.hh"
37
38 //-----------------------------------------------------------------------------
39 bool
equal(const Cell & A,double qct) const40 FloatCell::equal(const Cell & A, double qct) const
41 {
42 if (!A.is_numeric()) return false;
43 if (A.is_complex_cell()) return A.equal(*this, qct);
44 return tolerantly_equal(A.get_real_value(), get_real_value(), qct);
45 }
46 //-----------------------------------------------------------------------------
47 bool
greater(const Cell & other) const48 FloatCell::greater(const Cell & other) const
49 {
50 const APL_Float this_val = get_real_value();
51
52 switch(other.get_cell_type())
53 {
54 case CT_INT:
55 {
56 const APL_Float other_val(other.get_int_value());
57 if (this_val == other_val) return this > &other;
58 return this_val > other_val;
59 }
60
61 case CT_FLOAT:
62 {
63 const APL_Float other_val = other.get_real_value();
64 if (this_val == other_val) return this > &other;
65 return this_val > other_val;
66 }
67
68 case CT_CHAR: return true;
69 case CT_COMPLEX: break;
70 case CT_POINTER: return false;
71 case CT_CELLREF: DOMAIN_ERROR;
72 default: Assert(0 && "Bad celltype");
73 }
74
75 const Comp_result comp = compare(other);
76 if (comp == COMP_EQ) return this > &other;
77 return (comp == COMP_GT);
78 }
79 //-----------------------------------------------------------------------------
80 bool
get_near_bool() const81 FloatCell::get_near_bool() const
82 {
83 if (dfval() > INTEGER_TOLERANCE) // maybe 1
84 {
85 if (dfval() > (1.0 + INTEGER_TOLERANCE)) DOMAIN_ERROR;
86 if (dfval() < (1.0 - INTEGER_TOLERANCE)) DOMAIN_ERROR;
87 return true;
88 }
89
90 // maybe 0. We already know that dfval() ≤ qct
91 //
92 if (dfval() < -INTEGER_TOLERANCE) DOMAIN_ERROR;
93 return false;
94 }
95 //-----------------------------------------------------------------------------
96 Comp_result
compare(const Cell & other) const97 FloatCell::compare(const Cell & other) const
98 {
99 if (other.is_integer_cell()) // integer
100 {
101 const double qct = Workspace::get_CT();
102 if (equal(other, qct)) return COMP_EQ;
103 return (dfval() <= other.get_int_value()) ? COMP_LT : COMP_GT;
104 }
105
106 if (other.is_float_cell())
107 {
108 const double qct = Workspace::get_CT();
109 if (equal(other, qct)) return COMP_EQ;
110 return (dfval() <= other.get_real_value()) ? COMP_LT : COMP_GT;
111 }
112
113 if (other.is_complex_cell()) return Comp_result(-other.compare(*this));
114
115 DOMAIN_ERROR;
116 }
117 //-----------------------------------------------------------------------------
118 // monadic built-in functions...
119 //-----------------------------------------------------------------------------
120 ErrorCode
bif_near_int64_t(Cell * Z) const121 FloatCell::bif_near_int64_t(Cell * Z) const
122 {
123 if (!is_near_int64_t()) return E_DOMAIN_ERROR;
124
125 return IntCell::zv(Z, get_near_int());
126 }
127 //-----------------------------------------------------------------------------
128 ErrorCode
bif_within_quad_CT(Cell * Z) const129 FloatCell::bif_within_quad_CT(Cell * Z) const
130 {
131 const double val = dfval();
132 if (val > LARGE_INT) return E_DOMAIN_ERROR;
133 if (val < SMALL_INT) return E_DOMAIN_ERROR;
134
135 const double max_diff = Workspace::get_CT() * val; // scale ⎕CT
136
137 const APL_Float val_dn = floor(val);
138 if (val < (val_dn + max_diff)) return IntCell::zv(Z, val_dn);
139
140 const APL_Float val_up = ceil(val);
141 if (val > (val_up - max_diff)) return IntCell::zv(Z, val_up);
142
143 return E_DOMAIN_ERROR;
144 }
145 //-----------------------------------------------------------------------------
146 ErrorCode
bif_factorial(Cell * Z) const147 FloatCell::bif_factorial(Cell * Z) const
148 {
149 // max N! that fits into double is about 170
150 //
151 if (dfval() > 170.0) return E_DOMAIN_ERROR;
152
153 const APL_Float arg = dfval() + 1.0;
154 return FloatCell::zv(Z, tgamma(arg));
155 }
156 //-----------------------------------------------------------------------------
157 ErrorCode
bif_conjugate(Cell * Z) const158 FloatCell::bif_conjugate(Cell * Z) const
159 {
160 // convert quotients (if any) to double
161 return zv(Z, dfval());
162 }
163 //-----------------------------------------------------------------------------
164 ErrorCode
bif_negative(Cell * Z) const165 FloatCell::bif_negative(Cell * Z) const
166 {
167 #ifdef RATIONAL_NUMBERS_WANTED
168 if (const APL_Integer denom = get_denominator())
169 return zv(Z, -get_numerator(), denom);
170 #endif
171
172 return zv(Z, - dfval());
173 }
174 //-----------------------------------------------------------------------------
175 ErrorCode
bif_direction(Cell * Z) const176 FloatCell::bif_direction(Cell * Z) const
177 {
178 // Note: bif_direction does NOT use ⎕CT
179 //
180 #ifdef RATIONAL_NUMBERS_WANTED
181 if (const APL_Integer denom = get_denominator())
182 {
183 if (get_numerator() > 0) return IntCell::zv(Z, 1);
184 if (get_numerator() < 0) return IntCell::zv(Z, -1);
185 return IntCell::zv(Z, 0);
186 }
187 #endif
188
189 if (dfval() > 0.0) return IntCell::zv(Z, 1);
190 if (dfval() < 0.0) return IntCell::zv(Z, -1);
191 return IntCell::zv(Z, 0);
192 }
193 //-----------------------------------------------------------------------------
194 ErrorCode
bif_magnitude(Cell * Z) const195 FloatCell::bif_magnitude(Cell * Z) const
196 {
197 #ifdef RATIONAL_NUMBERS_WANTED
198 if (const APL_Integer denom = get_denominator())
199 {
200 const APL_Integer numer = get_numerator();
201 return FloatCell::zv(Z, numer < 0 ? -numer : numer, denom);
202 }
203 #endif
204
205 if (dfval() < 0.0) return FloatCell::zv(Z, -dfval());
206 else return FloatCell::zv(Z, dfval());
207 }
208 //-----------------------------------------------------------------------------
209 ErrorCode
bif_reciprocal(Cell * Z) const210 FloatCell::bif_reciprocal(Cell * Z) const
211 {
212 #ifdef RATIONAL_NUMBERS_WANTED
213 if (const APL_Integer denom = get_denominator())
214 {
215 if (uint64_t(denom) < 0x8000000000000000ULL) // small enough for int32
216 {
217 const APL_Integer numer = get_numerator();
218 // simply exchange numerator and denominator, but make sure that
219 // the denominator is positive
220 //
221 if (numer == 1) return IntCell::zv(Z, denom);
222 if (numer == -1) return IntCell::zv(Z, -denom);
223 if (numer < 0) return FloatCell::zv(Z, -denom, -numer);
224 else return FloatCell::zv(Z, denom, numer);
225 }
226
227 // at this point denom does not fit into numer. Fall through
228 }
229 #endif
230
231 const APL_Float z = 1.0/dfval();
232 if (!isfinite(z)) return E_DOMAIN_ERROR;
233
234 return FloatCell::zv(Z, 1.0/dfval());
235 }
236 //-----------------------------------------------------------------------------
237 ErrorCode
bif_roll(Cell * Z) const238 FloatCell::bif_roll(Cell * Z) const
239 {
240 if (!is_near_int()) return E_DOMAIN_ERROR;
241
242 const APL_Integer set_size = get_checked_near_int();
243 if (set_size <= 0) return E_DOMAIN_ERROR;
244
245 const uint64_t rnd = Workspace::get_RL(set_size);
246 return IntCell::zv(Z, Workspace::get_IO() + (rnd % set_size));
247 }
248 //-----------------------------------------------------------------------------
249 ErrorCode
bif_pi_times(Cell * Z) const250 FloatCell::bif_pi_times(Cell * Z) const
251 {
252 return zv(Z, dfval() * M_PI);
253 }
254 //-----------------------------------------------------------------------------
255 ErrorCode
bif_pi_times_inverse(Cell * Z) const256 FloatCell::bif_pi_times_inverse(Cell * Z) const
257 {
258 return zv(Z, dfval() / M_PI);
259 }
260 //-----------------------------------------------------------------------------
261 ErrorCode
bif_ceiling(Cell * Z) const262 FloatCell::bif_ceiling(Cell * Z) const
263 {
264 #ifdef RATIONAL_NUMBERS_WANTED
265 if (const APL_Integer denom = get_denominator())
266 {
267 // since the quotient is exact, we ignore ⎕CT
268 //
269 const APL_Integer numer = get_numerator();
270 APL_Integer quotient = numer / denom;
271 if (numer > (quotient * denom)) ++quotient;
272 return IntCell::zv(Z, quotient);
273 }
274 #endif
275
276 // see comments for bif_floor below.
277
278 const APL_Float b = dfval();
279 // if b is large then return it as is.
280 //
281 if (b >= LARGE_INT) return zv(Z, b);
282 if (b <= SMALL_INT) return zv(Z, b);
283
284 APL_Integer bi = b;
285 while (bi < b) ++bi;
286 while ((bi - 1) > b) --bi;
287 if (bi == b) return IntCell::zv(Z, bi); // b already equal to its floor
288
289 const APL_Float D = bi - b;
290
291 if (D >= (1.0 - Workspace::get_CT())) --bi;
292 return IntCell::zv(Z, bi);
293 }
294 //-----------------------------------------------------------------------------
295 ErrorCode
bif_floor(Cell * Z) const296 FloatCell::bif_floor(Cell * Z) const
297 {
298 #ifdef RATIONAL_NUMBERS_WANTED
299 if (const APL_Integer denom = get_denominator())
300 {
301 // since the quotient is exact, we ignore ⎕CT
302 //
303 const APL_Integer numer = get_numerator();
304 APL_Integer quotient = numer / denom;
305 if (numer < (quotient * denom)) --quotient;
306 return IntCell::zv(Z, quotient);
307 }
308 #endif
309
310 /* Informal description (iso p. 78):
311 For real-numbers, Z is the greatest integer tolerantly less than
312 or equal to B. Uses comparison-tolerance.
313
314 Formal description:
315 Return the tolerant-floor of B within comparison-tolerance.
316
317 tolerant-floor (p.19) is defined for complex A:
318 Let A be a member of the set of numbers in the unit-square at the
319 complex-integer C, and let D be A minus C.
320 If the sum of the real and imaginary parts of D is tolerantly-less-than
321 one within B, then Z is C.
322 Otherwise, if the imaginary-part of D is greater-than the real-part of D,
323 then Z is C plus imaginary-one.
324 Otherwise, Z is C plus one.
325
326 Unfortunately tolerantly-less-than is not defined in the standard. We
327 interpret it as meaning 'less than and not tolerrantly-equal'.
328
329 Replacing B with ⎕CT, and A with B, and considering that the imaginary
330 part of B is always 0 if B is real this becomes:
331
332 tolerant-floor of (real) B within ⎕CT:
333 Let B be a member of the set of numbers in the hals-open interval [C, C+1),
334 and let D be B minus C.
335 If D is tolerantly-less-than one within ⎕CT, then Z is C.
336 Otherwise, Z is C plus one.
337
338 In other word, Let RB be B rounded down. Then Z is RB if B < RB + 1 - ⎕CT
339 and RB+1 otherwise.
340
341 Note: if B cannot fit into int64_t then, due to the smaller precision
342 of double, it is already equal to its floor and we return it unchanged.
343 */
344
345 const APL_Float b = dfval();
346 // if b is large then return it as is.
347 //
348 if (b >= LARGE_INT) return zv(Z, b);
349 if (b <= SMALL_INT) return zv(Z, b);
350
351 APL_Integer bi = b;
352 while (bi > b) --bi;
353 while ((bi + 1) < b) ++bi;
354 if (bi == b) return IntCell::zv(Z, bi); // b already equal to its floor
355
356 const APL_Float D = b - bi;
357
358 if (D >= (1.0 - Workspace::get_CT())) ++bi;
359 return IntCell::zv(Z, bi);
360 }
361 //-----------------------------------------------------------------------------
362 ErrorCode
bif_exponential(Cell * Z) const363 FloatCell::bif_exponential(Cell * Z) const
364 {
365 // e to the B-th power
366 //
367 return FloatCell::zv(Z, exp(dfval()));
368 }
369 //-----------------------------------------------------------------------------
370 ErrorCode
bif_nat_log(Cell * Z) const371 FloatCell::bif_nat_log(Cell * Z) const
372 {
373 const APL_Float val = dfval();
374 if (val == 0.0) return E_DOMAIN_ERROR;
375
376 if (val > 0.0) // real result
377 {
378 return FloatCell::zv(Z, log(val));
379 }
380
381 const APL_Complex bb(val, 0);
382 return ComplexCell::zv(Z, log(bb));
383 }
384 //-----------------------------------------------------------------------------
385 // dyadic built-in functions...
386 //
387 // where possible a function with non-real A is delegated to the corresponding
388 // member function of A. For numeric cells that is the ComplexCell function
389 // and otherwise the default function (that returns E_DOMAIN_ERROR.
390 //
391 //-----------------------------------------------------------------------------
392 ErrorCode
bif_add(Cell * Z,const Cell * A) const393 FloatCell::bif_add(Cell * Z, const Cell * A) const
394 {
395 if (A->is_real_cell())
396 {
397 #ifdef RATIONAL_NUMBERS_WANTED
398 if (const APL_Integer denom_B = get_denominator())
399 if (const APL_Integer denom_A = A->get_denominator())
400 {
401 // both A and B are rational
402 //
403 if (Cell::prod_overflow(denom_A, denom_B)) goto big;
404
405 // compute common denominator...
406 const APL_Integer gcd_AB = gcd(denom_A, denom_B);
407 const APL_Integer mult_A = denom_A / gcd_AB;
408 const APL_Integer mult_B = denom_B / gcd_AB;
409 const APL_Integer denom_AB = denom_A * mult_B;
410 if (Cell::prod_overflow(denom_AB, mult_B)) goto big;
411
412 // compute numerators...
413 const APL_Integer numer_A = A->get_numerator();
414 if (Cell::prod_overflow(numer_A, mult_B)) goto big;
415 const APL_Integer numer_A1 = numer_A * mult_B;
416 const APL_Integer numer_B = get_numerator();
417 if (Cell::prod_overflow(numer_B, mult_A)) goto big;
418 const APL_Integer numer_B1 = numer_B * mult_A;
419
420 const APL_Integer sum_AB = numer_A1 + numer_B1;
421 if (Cell::sum_overflow(sum_AB, numer_A1, numer_B1)) goto big;
422 const APL_Integer sum_gcd = gcd(sum_AB, denom_AB);
423 if (sum_gcd == denom_AB) return IntCell::zv(Z, sum_AB / denom_AB);
424 if (sum_gcd == 1) return FloatCell::zv(Z, sum_AB, denom_AB);
425 return FloatCell::zv(Z, sum_AB/sum_gcd, denom_AB/sum_gcd);
426 }
427 big:
428
429 #endif
430
431 return FloatCell::zv(Z, A->get_real_value() + get_real_value());
432 }
433
434 // delegate to A
435 //
436 return A->bif_add(Z, this);
437 }
438 //-----------------------------------------------------------------------------
439 ErrorCode
bif_add_inverse(Cell * Z,const Cell * A) const440 FloatCell::bif_add_inverse(Cell * Z, const Cell * A) const
441 {
442 return A->bif_subtract(Z, this);
443 }
444 //-----------------------------------------------------------------------------
445 ErrorCode
bif_subtract(Cell * Z,const Cell * A) const446 FloatCell::bif_subtract(Cell * Z, const Cell * A) const
447 {
448 if (A->is_real_cell()) // real result
449 {
450 #ifdef RATIONAL_NUMBERS_WANTED
451 if (const APL_Integer denom_B = get_denominator())
452 if (const APL_Integer denom_A = A->get_denominator())
453 {
454 // both A and B are rational
455 //
456 if (Cell::prod_overflow(denom_A, denom_B)) goto big;
457
458 // compute common denominator...
459 const APL_Integer gcd_AB = gcd(denom_A, denom_B);
460 const APL_Integer mult_A = denom_A / gcd_AB;
461 const APL_Integer mult_B = denom_B / gcd_AB;
462 const APL_Integer denom_AB = denom_A * mult_B;
463
464 // compute numerators...
465 const APL_Integer numer_A = A->get_numerator();
466 if (Cell::prod_overflow(numer_A, mult_B)) goto big;
467 const APL_Integer numer_A1 = numer_A * mult_B;
468 const APL_Integer numer_B = get_numerator();
469 if (Cell::prod_overflow(numer_B, mult_A)) goto big;
470 const APL_Integer numer_B1 = numer_B * mult_A;
471
472 const APL_Integer diff_AB = numer_A1 - numer_B1;
473 if (Cell::diff_overflow(diff_AB, numer_A1, numer_B1)) goto big;
474 const APL_Integer diff_gcd = gcd(diff_AB, denom_AB);
475 if (diff_gcd == denom_AB) return IntCell::zv(Z, diff_AB / denom_AB);
476 if (diff_gcd == 1) return FloatCell::zv(Z, diff_AB, denom_AB);
477 return FloatCell::zv(Z, diff_AB/diff_gcd, denom_AB/diff_gcd);
478 }
479 big:
480
481 #endif
482
483 return zv(Z, A->get_real_value() - get_real_value());
484 }
485
486 if (A->is_complex_cell()) // complex result
487 {
488 return ComplexCell::zv(Z, A->get_real_value() - get_real_value(),
489 A->get_imag_value());
490 }
491
492 return E_DOMAIN_ERROR;
493 }
494 //-----------------------------------------------------------------------------
495 ErrorCode
bif_multiply(Cell * Z,const Cell * A) const496 FloatCell::bif_multiply(Cell * Z, const Cell * A) const
497 {
498 #ifdef RATIONAL_NUMBERS_WANTED
499 if (APL_Integer denom_B = get_denominator())
500 if (APL_Integer denom_A = A->get_denominator())
501 {
502 // both A and B are rational
503 //
504 APL_Integer numer_A = A->get_numerator();
505 APL_Integer numer_B = get_numerator();
506 const APL_Integer gcd_A_B = gcd(numer_A, denom_B);
507 if (gcd_A_B > 1) { numer_A /= gcd_A_B; denom_B /= gcd_A_B; }
508
509 const APL_Integer gcd_B_A = gcd(numer_B, denom_A);
510 if (gcd_B_A > 1) { numer_B /= gcd_B_A; denom_A /= gcd_B_A; }
511
512 if (Cell::prod_overflow(numer_A, numer_B)) goto big;
513 if (Cell::prod_overflow(denom_A, denom_B)) goto big;
514
515 const APL_Integer numer = numer_A * numer_B;
516 const APL_Integer denom = denom_A * denom_B;
517 const APL_Integer prod_gcd = gcd(numer, denom);
518 if (prod_gcd == denom) return IntCell::zv(Z, numer / denom);
519 if (prod_gcd == 1) return FloatCell::zv(Z, numer, denom);
520 return FloatCell::zv(Z, numer/prod_gcd, denom/prod_gcd);
521 }
522 big:
523
524 #endif
525
526 if (!A->is_numeric()) return E_DOMAIN_ERROR;
527
528 const APL_Float ar = A->get_real_value();
529 const APL_Float ai = A->get_imag_value();
530
531 if (ai == 0.0) // real result
532 {
533 const APL_Float z = ar * dfval();
534 if (!isfinite(z)) return E_DOMAIN_ERROR;
535 return FloatCell::zv(Z, z);
536 }
537
538 // complex result
539 //
540 const double zr = ar * dfval();
541 const double zi = ai * dfval();
542 if (!isfinite(zr)) return E_DOMAIN_ERROR;
543 if (!isfinite(zi)) return E_DOMAIN_ERROR;
544 return ComplexCell::zv(Z, zr, zi);
545 }
546 //-----------------------------------------------------------------------------
547 ErrorCode
bif_multiply_inverse(Cell * Z,const Cell * A) const548 FloatCell::bif_multiply_inverse(Cell * Z, const Cell * A) const
549 {
550 return A->bif_divide(Z, this);
551 }
552 //-----------------------------------------------------------------------------
553 ErrorCode
bif_divide(Cell * Z,const Cell * A) const554 FloatCell::bif_divide(Cell * Z, const Cell * A) const
555 {
556 #ifdef RATIONAL_NUMBERS_WANTED
557 if (const APL_Integer B_denom = get_denominator()) // B is rational
558 {
559 const APL_Integer B_numer = get_numerator();
560 if (B_numer == 0) // A ÷ 0
561 {
562 if (A->is_near_zero()) return IntCell::z1(Z); // 0÷0 is 1
563 return E_DOMAIN_ERROR;
564 }
565 const FloatCell inv_B(B_denom, B_numer);
566 return inv_B.bif_multiply(Z, A);
567 }
568 #endif
569
570 if (!A->is_numeric()) return E_DOMAIN_ERROR;
571
572 const APL_Float ar = A->get_real_value();
573 const APL_Float ai = A->get_imag_value();
574
575 if (dfval() == 0.0) // A ÷ 0
576 {
577 if (ar != 0.0) return E_DOMAIN_ERROR;
578 if (ai != 0.0) return E_DOMAIN_ERROR;
579
580 return IntCell::z1(Z); // 0÷0 is 1 in APL
581 }
582
583
584 if (ai == 0.0) // real result
585 {
586 const APL_Float real = ar / dfval() ;
587 if (isfinite(real)) return FloatCell::zv(Z, real);
588 return E_DOMAIN_ERROR;
589 }
590
591 // complex result
592 //
593 const double zar = ar / dfval();
594 const double zai = ai / dfval();
595 if (!isfinite(zar)) return E_DOMAIN_ERROR;
596 if (!isfinite(zai)) return E_DOMAIN_ERROR;
597 return ComplexCell::zv(Z, zar, zai);
598 }
599 //-----------------------------------------------------------------------------
600 ErrorCode
bif_power(Cell * Z,const Cell * A) const601 FloatCell::bif_power(Cell * Z, const Cell * A) const
602 {
603 // some A to the real B-th power
604 //
605 if (!A->is_numeric()) return E_DOMAIN_ERROR;
606
607 const APL_Float ar = A->get_real_value();
608 const APL_Float ai = A->get_imag_value();
609
610 // 1. A == 0
611 //
612 if (ar == 0.0 && ai == 0.0)
613 {
614 if (dfval() == 0.0) return IntCell::z1(Z); // 0⋆0 is 1
615 if (dfval() > 0.0) return IntCell::z0(Z); // 0⋆N is 0
616 return E_DOMAIN_ERROR; // 0⋆¯N = 1÷0
617 }
618
619 // 2. real A > 0 (real result)
620 //
621 if (ai == 0.0)
622 {
623 if (ar == 1.0) return IntCell::z1(Z); // 1⋆b = 1
624 const APL_Float z = pow(ar, dfval());
625 if (isfinite(z)) return zv(Z, z);
626
627 /* fall through */
628 }
629
630 // 3. complex result
631 //
632 const APL_Complex a(ar, ai);
633 const APL_Complex z = complex_power(a, dfval());
634 if (!isfinite(z.real())) return E_DOMAIN_ERROR;
635 if (!isfinite(z.imag())) return E_DOMAIN_ERROR;
636
637 return ComplexCell::zv(Z, z);
638 }
639 //-----------------------------------------------------------------------------
640 inline double
p_modulo_q(double P,double Q)641 p_modulo_q(double P, double Q)
642 {
643 // return R ← P - (×P) ⌊ | Q × ⌊ | P ÷ Q as described in ISO p. 89
644 // │ │ │ │ │ │ │ │
645 // │ │ │ │ │ │ │ └──────── quotient
646 // │ │ │ │ │ │ └────────── abs_quotient
647 // │ │ │ │ │ └──────────── floor_quotient
648 // │ │ │ │ └──────────────── floor_quotient
649 // │ │ │ └────────────────── prod
650 // │ │ └──────────────────── abs_prod
651 // │ └───────────────────────── prod2
652 // └───────────────────────────── r
653 //
654
655 const APL_Float quotient = P / Q; // quotient←b÷a and check overflows
656 if (!isfinite(quotient)) return 0.0; // exponent overflow
657
658 if (!isfinite(Q / P)) // exponent underflow
659 return ((P < 0) == (Q < 0)) ? P : 0.0;
660
661 {
662 const double qct = Workspace::get_CT();
663 if ((qct != 0) && Cell::integral_within(quotient, qct)) return 0.0;
664 }
665
666 const APL_Float null(0.0);
667 const APL_Float abs_quotient = quotient < null ? -quotient : quotient;
668 if (abs_quotient > 4.5E15)
669 {
670 // if "| P ÷ Q" is too large then 'abs_quotient' is not exact any more.
671 // In this case, for every R with 0 ≤ R < Q there ie an A such that
672 // A has the same floating point representation as 'abs_quotient' and
673 // (P - R) is an integer multiple of Q.
674 //
675 // Normally we would raise a DOMAIN ERROR to inform the user about the
676 // problem, but the ISO standard does not allow that. We therefore
677 // return 0 which is a valid remainder (although not the only one).
678 //
679 return 0.0;
680 }
681
682 if (abs_quotient < 1.0)
683 {
684 // P is smaller in magnitude than Q. If P and Q have the same sign then
685 // P mod Q is P, otherwise Q - P.
686 //
687 return (P < null) == (Q < null) ? P : Q + P;
688 }
689
690 const APL_Float floor_quotient = floor(abs_quotient);
691 const APL_Float prod = Q * floor_quotient;
692 const APL_Float abs_prod = prod < null ? -prod : prod;
693 const APL_Float prod2 = P < 0 ? -abs_prod : abs_prod;
694 const APL_Float r = P - prod2;
695
696 return r;
697
698 /*
699 // Q(P)
700 // Q(Q)
701 // Q(quotient)
702 // Q(abs_quotient)
703 // Q(floor_quotient)
704 // Q(abs_prod)
705 // Q(prod2)
706 // Q(r)
707
708 Assert(isnormal(abs_quotient) || abs_quotient == 0.0);
709 Assert(isnormal(floor_quotient) || floor_quotient == 0.0);
710 Assert(isnormal(abs_prod) || abs_prod == 0.0);
711 Assert(isnormal(prod2) || prod2 == 0.0);
712 Assert(isnormal(r) || r == 0.0);
713
714 return r;
715 */
716 }
717 //-----------------------------------------------------------------------------
718 ErrorCode
bif_residue(Cell * Z,const Cell * A) const719 FloatCell::bif_residue(Cell * Z, const Cell * A) const
720 {
721 if (!A->is_numeric()) return E_DOMAIN_ERROR;
722
723 if (A->get_imag_value() != 0.0) // complex A
724 {
725 ComplexCell B(get_real_value());
726 return B.bif_residue(Z, A);
727 }
728
729 const APL_Float a = A->get_real_value();
730 const APL_Float b = dfval();
731
732 // if A is zero, return B
733 //
734 if (a == 0.0) return zv(Z, b);
735
736 // IBM: if B is zero , return 0
737 //
738 if (b == 0.0) return IntCell::z0(Z);
739
740 // if ⎕CT != 0 and B ÷ A is close to an integer within ⎕CT then return 0.
741 //
742 // Note: In that case, the integer to which A ÷ B is close is either
743 // floor(A ÷ B) or ceil(A ÷ B).
744 //
745 const APL_Float null(0.0);
746 const APL_Float z = p_modulo_q(b, a);
747 Assert(isnormal(z) || z == null);
748
749 APL_Float r2;
750 if (z < null && a < null) r2 = z; // (×R) = ×Q)
751 else if (z > null && a > null) r2 = z; // (×R) = ×Q)
752 else r2 = z + a; // (×R) ≠ ×Q)
753 Assert(isnormal(r2) || r2 == null);
754
755 if (r2 == null) return IntCell::z0(Z);
756 if (r2 == a) return IntCell::z0(Z);
757 else return zv(Z, r2);
758 }
759 //-----------------------------------------------------------------------------
760 ErrorCode
bif_maximum(Cell * Z,const Cell * A) const761 FloatCell::bif_maximum(Cell * Z, const Cell * A) const
762 {
763 if (A->is_integer_cell())
764 {
765 const APL_Integer a = A->get_int_value();
766 if (a >= dfval()) return IntCell::zv(Z, a);
767 else return this->zv(Z); // copy as is
768 }
769
770 if (A->is_float_cell())
771 {
772 const APL_Float a = A->get_real_value();
773 if (a >= dfval())
774 return reinterpret_cast<const FloatCell *>(A)->zv(Z); // copy as is
775 else return this->zv(Z); // copy as is
776 }
777
778 // delegate to A
779 //
780 return A->bif_maximum(Z, this);
781 }
782 //-----------------------------------------------------------------------------
783 ErrorCode
bif_minimum(Cell * Z,const Cell * A) const784 FloatCell::bif_minimum(Cell * Z, const Cell * A) const
785 {
786 if (A->is_integer_cell())
787 {
788 const APL_Integer a = A->get_int_value();
789 if (a <= dfval()) return IntCell::zv(Z, a);
790 else return this->zv(Z); // copy as is
791 }
792
793 if (A->is_float_cell())
794 {
795 const APL_Float a = A->get_real_value();
796 if (a <= dfval())
797 return reinterpret_cast<const FloatCell *>(A)->zv(Z); // copy as is
798 else return this->zv(Z); // copy as is
799 }
800
801 // delegate to A
802 //
803 return A->bif_minimum(Z, this);
804 }
805 //=============================================================================
806 // throw/nothrow boundary. Functions above MUST NOT (directly or indirectly)
807 // throw while funcions below MAY throw.
808 //=============================================================================
809 PrintBuffer
character_representation(const PrintContext & pctx) const810 FloatCell::character_representation(const PrintContext & pctx) const
811 {
812 #ifdef RATIONAL_NUMBERS_WANTED
813 if (const APL_Integer denom = get_denominator())
814 {
815 if (Workspace::get_v_Quad_PS().get_print_quotients()) // show A÷B
816 {
817 ColInfo info;
818 info.flags |= CT_FLOAT;
819
820 UCS_string ucs;
821 APL_Integer numer = get_numerator();
822 if (numer < 0)
823 {
824 ucs.append(UNI_OVERBAR);
825 numer = -numer;
826 }
827 ucs.append(UCS_string::from_uint(numer));
828 info.int_len = ucs.size();
829
830 ucs.append(UNI_DIVIDE);
831
832 ucs.append(UCS_string::from_uint(denom));
833 info.denom_len = ucs.size() - info.int_len;
834 info.real_len = ucs.size();
835 return PrintBuffer(ucs, info);
836 }
837 }
838 #endif
839
840 bool scaled = pctx.get_scaled(); // may be changed by print function
841 UCS_string ucs = UCS_string(dfval(), scaled, pctx);
842
843 ColInfo info;
844 info.flags |= CT_FLOAT;
845 if (scaled) info.flags |= real_has_E;
846
847 // assume integer.
848 //
849 int int_fract = ucs.size();
850 info.real_len = ucs.size();
851 info.int_len = ucs.size();
852 loop(u, ucs.size())
853 {
854 if (ucs[u] == UNI_ASCII_FULLSTOP)
855 {
856 info.int_len = u;
857 if (!pctx.get_scaled()) break;
858 continue;
859 }
860
861 if (ucs[u] == UNI_ASCII_E)
862 {
863 if (info.int_len > u) info.int_len = u;
864 int_fract = u;
865 break;
866 }
867 }
868
869 info.fract_len = int_fract - info.int_len;
870
871 return PrintBuffer(ucs, info);
872 }
873 //-----------------------------------------------------------------------------
874 bool
is_big(APL_Float val,int quad_pp)875 FloatCell::is_big(APL_Float val, int quad_pp)
876 {
877 static const APL_Float big[MAX_Quad_PP + 1] =
878 {
879 1ULL, // not used since MIN_Quad_PP == 1
880 10ULL,
881 100ULL,
882 1000ULL,
883 10000ULL,
884 100000ULL,
885 1000000ULL,
886 10000000ULL,
887 100000000ULL,
888 1000000000ULL,
889 10000000000ULL,
890 100000000000ULL,
891 1000000000000ULL,
892 10000000000000ULL,
893 100000000000000ULL,
894 1000000000000000ULL,
895 10000000000000000ULL,
896 1000000000000000000ULL,
897 };
898
899 return val >= big[quad_pp] || val <= -big[quad_pp];
900 }
901 //-----------------------------------------------------------------------------
902 bool
need_scaling(APL_Float val,int quad_pp)903 FloatCell::need_scaling(APL_Float val, int quad_pp)
904 {
905 // A number is printed in scaled format if (see lrm pp. 11-13) either:
906 //
907 // (1) its integer part is longer that quad-PP, or
908
909 // (2a) is non-zero, and
910 // (2b) its integer part is 0, and
911 // (2c) its fractional part starts with at least 5 zeroes.
912 //
913 if (val < 0.0) val = - val; // simplify comparisons
914
915 if (is_big(val, quad_pp)) return true; // case 1.
916
917 if (val == 0.0) return false; // not 2a.
918
919 if (val < 0.000001) return true; // case 2
920
921 return false;
922 }
923 //-----------------------------------------------------------------------------
924 void
map_FC(UCS_string & ucs)925 FloatCell::map_FC(UCS_string & ucs)
926 {
927 loop(u, ucs.size())
928 {
929 switch(ucs[u])
930 {
931 case UNI_ASCII_FULLSTOP: ucs[u] = Workspace::get_FC(0); break;
932 case UNI_ASCII_COMMA: ucs[u] = Workspace::get_FC(1); break;
933 case UNI_OVERBAR: ucs[u] = Workspace::get_FC(5); break;
934 default: break;
935 }
936 }
937 }
938 //-----------------------------------------------------------------------------
939