FORM v5.0.2-2-gfb12f2e
float.c
Go to the documentation of this file.
1
11/* #[ License : */
12/*
13 * Copyright (C) 1984-2026 J.A.M. Vermaseren
14 * When using this file you are requested to refer to the publication
15 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
16 * This is considered a matter of courtesy as the development was paid
17 * for by FOM the Dutch physics granting agency and we would like to
18 * be able to track its scientific use to convince FOM of its value
19 * for the community.
20 *
21 * This file is part of FORM.
22 *
23 * FORM is free software: you can redistribute it and/or modify it under the
24 * terms of the GNU General Public License as published by the Free Software
25 * Foundation, either version 3 of the License, or (at your option) any later
26 * version.
27 *
28 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
29 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
31 * details.
32 *
33 * You should have received a copy of the GNU General Public License along
34 * with FORM. If not, see <http://www.gnu.org/licenses/>.
35 */
36/* #] License : */
37/*
38 #[ Includes : float.c
39*/
40
41#include "form3.h"
42#include <math.h>
43#include <gmp.h>
44
45#define WITHCUTOFF
46
47#define GMPSPREAD (GMP_LIMB_BITS/BITSINWORD)
48
49
50void Form_mpf_init(mpf_t t);
51void Form_mpf_clear(mpf_t t);
52void Form_mpf_set_prec_raw(mpf_t t,ULONG newprec);
53void FormtoZ(mpz_t z,UWORD *a,WORD na);
54void ZtoForm(UWORD *a,WORD *na,mpz_t z);
55long FloatToInteger(UWORD *out, mpf_t floatin, long *bitsused);
56void IntegerToFloat(mpf_t result, UWORD *formlong, int longsize);
57int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin);
58int AddFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2);
59int MulFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2);
60int DivFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2);
61int AddRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat);
62int MulRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat);
63void SimpleDelta(mpf_t sum, int m);
64void SimpleDeltaC(mpf_t sum, int m);
65void SingleTable(mpf_t *tabl, int N, int m, int pow);
66void DoubleTable(mpf_t *tabout, mpf_t *tabin, int N, int m, int pow);
67void EndTable(mpf_t sum, mpf_t *tabin, int N, int m, int pow);
68void deltaMZV(mpf_t, WORD *, int);
69void deltaEuler(mpf_t, WORD *, int);
70void deltaEulerC(mpf_t, WORD *, int);
71void CalculateMZVhalf(mpf_t, WORD *, int);
72void CalculateMZV(mpf_t, WORD *, int);
73void CalculateEuler(mpf_t, WORD *, int);
74int ExpandMZV(WORD *term, WORD level);
75int ExpandEuler(WORD *term, WORD level);
76int PackFloat(WORD *,mpf_t);
77int UnpackFloat(mpf_t, WORD *);
78void RatToFloat(mpf_t result, UWORD *formrat, int ratsize);
79
80/*
81 #] Includes :
82 #[ Some GMP float info :
83
84 From gmp.h:
85
86 typedef struct
87 {
88 int _mp_prec; Max precision, in number of `mp_limb_t's.
89 Set by mpf_init and modified by
90 mpf_set_prec. The area pointed to by the
91 _mp_d field contains `prec' + 1 limbs.
92 int _mp_size; abs(_mp_size) is the number of limbs the
93 last field points to. If _mp_size is
94 negative this is a negative number.
95 mp_exp_t _mp_exp; Exponent, in the base of `mp_limb_t'.
96 mp_limb_t *_mp_d; Pointer to the limbs.
97 } __mpf_struct;
98
99 typedef __mpf_struct mpf_t[1];
100
101 Currently:
102 sizeof(int) = 4
103 sizeof(mpf_t) = 24
104 sizeof(mp_limb_t) = 8,
105 sizeof(mp_exp_t) = 8,
106 sizeof a pointer is 8.
107 If any of this changes in the future we would have to change the
108 PackFloat and UnpackFloat routines.
109
110 Our float_ function is packed with the 4 arguments:
111 -SNUMBER _mp_prec
112 -SNUMBER _mp_size
113 exponent which can be -SNUMBER or a regular term
114 the limbs as n/1 in regular term format, or just an -SNUMBER.
115 During normalization the sign is taken away from the second argument
116 and put as the sign of the complete term. This is easier for the
117 WriteInnerTerm routine in sch.c
118
119 Wildcarding of functions excludes matches with float_
120 Float_ always ends up inside the bracket, just like poly(rat)fun.
121
122 From mpfr.h
123
124 The formats here are different. This has, among others, to do with
125 the rounding. The result is that we need different aux variables
126 when working with mpfr and we need a different conversion routine
127 to float. It also means that we need to treat the mzv_ etc functions
128 completely separately. For now we try to develop that in the file
129 Evaluate.c. At a later stage we may merge the two files.
130 Originally we had the sqrt in float.c but it seems better to put
131 it in Evaluate.c
132
133 #] Some GMP float info :
134 #[ Low Level :
135
136 In the low level routines we interact directly with the content
137 of the GMP structs. This can be done safely, because their
138 layout is documented. We pay particular attention to the init
139 and clear routines, because they involve malloc/free calls.
140
141 #[ Explanations :
142
143 We need a number of facilities inside Form to deal with floating point
144 numbers, taking into account that they are only meant for sporadic use.
145 1: We need a special function float_ who's arguments contain a limb
146 representation of the mpf_t of the gmp.
147 2: Some functions may return a floating point number. This is then in
148 the form of an occurrence of the function float_.
149 3: We need a print routine to print this float_.
150 4: We need routines for conversions:
151 a: (long) int to float.
152 b: rat to float.
153 c: float to rat (if possible)
154 d: float to integer (with rounding toward zero).
155 5: We need calculational operations for add, sub, mul, div, exp.
156 6: We need service routines to pack and unpack the function float_.
157 7: The coefficient should be pulled inside float_.
158 8: Float_ cannot occur inside PolyRatFun.
159 9: We need to be able to treat float_ as the coefficient during sorting.
160 10: For now, we need the functions mzvf_ and eulerf_ for the evaluation
161 of mzv's and euler sums.
162 11: We need a setting for the default precision.
163 12: We need a special flag for the dirty field of arguments to avoid
164 the normalization of the argument with the limbs.
165 Alternatively, the float_ should be not a regular function, but
166 get a status < FUNCTION. Just like SNUMBER, LNUMBER etc.
167
168 Note that we can keep this thread-safe. The only routine that is not
169 thread-safe is the print routine, but that is in accordance with all
170 other print routines in Form. When called from MesPrint it needs to
171 be protected by a lock, as is done standard inside Form.
172
173 #] Explanations :
174 #[ Form_mpf_init :
175*/
176/* UNFINISHED_FEATURE_EXCL_START */
177void Form_mpf_init(mpf_t t)
178{
179 mp_limb_t *d;
180 int i, prec;
181 if ( t->_mp_d ) { M_free(t->_mp_d,"Form_mpf_init"); t->_mp_d = 0; }
182 prec = (AC.DefaultPrecision + 8*sizeof(mp_limb_t)-1)/(8*sizeof(mp_limb_t)) + 1;
183 t->_mp_prec = prec;
184 t->_mp_size = 0;
185 t->_mp_exp = 0;
186 d = (mp_limb_t *)Malloc1(prec*sizeof(mp_limb_t),"Form_mpf_init");
187 if ( d == 0 ) {
188 MesPrint("Fatal error in Malloc1 call in Form_mpf_init. Trying to allocate %ld bytes.",
189 prec*sizeof(mp_limb_t));
190 Terminate(-1);
191 }
192 t->_mp_d = d;
193 for ( i = 0; i < prec; i++ ) d[i] = 0;
194}
195/* UNFINISHED_FEATURE_EXCL_STOP */
196/*
197 #] Form_mpf_init :
198 #[ Form_mpf_clear :
199*/
200/* UNFINISHED_FEATURE_EXCL_START */
201void Form_mpf_clear(mpf_t t)
202{
203 if ( t->_mp_d ) { M_free(t->_mp_d,"Form_mpf_init"); t->_mp_d = 0; }
204 t->_mp_prec = 0;
205 t->_mp_size = 0;
206 t->_mp_exp = 0;
207}
208/* UNFINISHED_FEATURE_EXCL_STOP */
209/*
210 #] Form_mpf_clear :
211 #[ Form_mpf_empty :
212*/
213
214void Form_mpf_empty(mpf_t t)
215{
216 int i;
217 for ( i = 0; i < t->_mp_prec; i++ ) t->_mp_d[i] = 0;
218 t->_mp_size = 0;
219 t->_mp_exp = 0;
220}
221
222/*
223 #] Form_mpf_empty :
224 #[ Form_mpf_set_prec_raw :
225*/
226/* UNFINISHED_FEATURE_EXCL_START */
227void Form_mpf_set_prec_raw(mpf_t t,ULONG newprec)
228{
229 ULONG newpr = (newprec + 8*sizeof(mp_limb_t)-1)/(8*sizeof(mp_limb_t)) + 1;
230 if ( newpr <= (ULONG)(t->_mp_prec) ) {
231 int i, used = ABS(t->_mp_size) ;
232 if ( newpr > (ULONG)used ) {
233 for ( i = used; i < (int)newpr; i++ ) t->_mp_d[i] = 0;
234 }
235 if ( t->_mp_size < 0 ) newpr = -newpr;
236 t->_mp_size = newpr;
237 }
238 else {
239/*
240 We can choose here between "forget about it" or making a new malloc.
241 If the program is well designed, we should never get here though.
242 For now we choose the "forget it" option.
243*/
244 MesPrint("Trying too big a precision %ld in Form_mpf_set_prec_raw.",newprec);
245 MesPrint("Old maximal precision is %ld.",
246 (size_t)(t->_mp_prec-1)*sizeof(mp_limb_t)*8);
247 Terminate(-1);
248 }
249}
250/* UNFINISHED_FEATURE_EXCL_STOP */
251/*
252 #] Form_mpf_set_prec_raw :
253 #[ PackFloat :
254
255 Puts an object of type mpf_t inside a function float_
256 float_(prec, nlimbs, exp, limbs);
257 Complication: the limbs and the exponent are long's. That means
258 two times the size of a Form (U)WORD.
259 To save space we could split the limbs in two because Form stores
260 coefficients as rationals with equal space for numerator and denominator.
261 Hence for each limb we could put the most significant UWORD in the
262 numerator and the least significant limb in the denominator.
263 This gives a problem with the compilation and subsequent potential
264 normalization of the 'fraction'. Hence for now we take the wasteful
265 approach. At a later stage we can try to veto normalization of FLOATFUN.
266 Caution: gmp/fmp is little endian and Form is big endian.
267
268 Zero is represented by zero limbs (and zero exponent).
269*/
270
271int PackFloat(WORD *fun,mpf_t infloat)
272{
273 WORD *t, nlimbs, num, nnum;
274 mp_limb_t *d = infloat->_mp_d; /* Pointer to the limbs. */
275 int i;
276 long e = infloat->_mp_exp;
277 t = fun;
278 *t++ = FLOATFUN;
279 t++;
280 FILLFUN(t);
281 *t++ = -SNUMBER;
282 *t++ = infloat->_mp_prec;
283 *t++ = -SNUMBER;
284 *t++ = infloat->_mp_size;
285/*
286 Now the exponent which is a signed long
287*/
288 if ( e < 0 ) {
289 e = -e;
290 if ( ( e >> (BITSINWORD-1) ) == 0 ) {
291 *t++ = -SNUMBER; *t++ = -e;
292 }
293 else {
294 *t++ = ARGHEAD+6; *t++ = 0; FILLARG(t);
295 *t++ = 6;
296 *t++ = (UWORD)e;
297 *t++ = (UWORD)(e >> BITSINWORD);
298 *t++ = 1; *t++ = 0; *t++ = -5;
299 }
300 }
301 else {
302 if ( ( e >> (BITSINWORD-1) ) == 0 ) {
303 *t++ = -SNUMBER; *t++ = e;
304 }
305 else {
306 *t++ = ARGHEAD+6; *t++ = 0; FILLARG(t);
307 *t++ = 6;
308 *t++ = (UWORD)e;
309 *t++ = (UWORD)(e >> BITSINWORD);
310 *t++ = 1; *t++ = 0; *t++ = 5;
311 }
312 }
313/*
314 and now the limbs. Note that the number of active limbs could be less
315 than prec+1 in which case we copy the smaller number.
316*/
317 nlimbs = infloat->_mp_size < 0 ? -infloat->_mp_size: infloat->_mp_size;
318 if ( nlimbs == 0 ) {
319 *t++ = -SNUMBER;
320 *t++ = 0;
321 }
322 else if ( nlimbs == 1 && (ULONG)(*d) < ((ULONG)1)<<(BITSINWORD-1) ) {
323 *t++ = -SNUMBER;
324 *t++ = (UWORD)(*d);
325 }
326 else {
327 if ( d[nlimbs-1] < ((ULONG)1)<<BITSINWORD ) {
328 num = 2*nlimbs-1; /* number of UWORDS needed */
329 }
330 else {
331 num = 2*nlimbs; /* number of UWORDS needed */
332 }
333 nnum = num;
334 *t++ = 2*num+2+ARGHEAD;
335 *t++ = 0;
336 FILLARG(t);
337 *t++ = 2*num+2;
338 while ( num > 1 ) {
339 *t++ = (UWORD)(*d); *t++ = (UWORD)(((ULONG)(*d))>>BITSINWORD); d++;
340 num -= 2;
341 }
342 if ( num == 1 ) { *t++ = (UWORD)(*d); }
343 *t++ = 1;
344 for ( i = 1; i < nnum; i++ ) *t++ = 0;
345 *t++ = 2*nnum+1; /* the sign is hidden in infloat->_mp_size */
346 }
347 fun[1] = t-fun;
348 return(fun[1]);
349}
350
351/*
352 #] PackFloat :
353 #[ UnpackFloat :
354
355 Takes the arguments of a function float_ and puts it inside an mpf_t.
356 For notation see commentary for PutInFloat.
357
358 We should make a new allocation for the limbs if the precision exceeds
359 the present precision of outfloat, or when outfloat has not been
360 initialized yet.
361
362 The return value is -1 if the contents of the FLOATFUN cannot be converted.
363 Otherwise the return value is the number of limbs.
364*/
365
366int UnpackFloat(mpf_t outfloat,WORD *fun)
367{
368 UWORD *t;
369 WORD *f;
370 int num, i;
371 mp_limb_t *d;
372/*
373 Very first step: check whether we can use float_:
374*/
375 GETIDENTITY
376 if ( AT.aux_ == 0 ) {
377 MLOCK(ErrorMessageLock);
378 MesPrint("Illegal attempt at using a float_ function without proper startup.");
379 MesPrint("Please use %#StartFloat <options> first.");
380 MUNLOCK(ErrorMessageLock);
381 Terminate(-1);
382 }
383/*
384 Check first the number and types of the arguments
385 There should be 4. -SNUMBER,-SNUMBER,-SNUMBER or a long number.
386 + the limbs, either -SNUMBER or Long number in the form of a Form rational.
387*/
388 if ( TestFloat(fun) == 0 ) goto Incorrect;
389 f = fun + FUNHEAD + 2;
390 if ( ABS(f[1]) > f[-1]+1 ) goto Incorrect;
391 if ( f[1] > outfloat->_mp_prec+1
392 || outfloat->_mp_d == 0 ) {
393 /*
394 We need to make a new allocation.
395 Unfortunately we cannot use Malloc1 because that is not
396 recognised by gmp and hence we cannot clear with mpf_clear.
397 Maybe we can do something about it by making our own
398 mpf_init and mpf_clear?
399 */
400 if ( outfloat->_mp_d != 0 ) free(outfloat->_mp_d);
401 outfloat->_mp_d = (mp_limb_t *)malloc((f[1]+1)*sizeof(mp_limb_t));
402 }
403 num = f[1];
404 outfloat->_mp_size = num;
405 if ( num < 0 ) { num = -num; }
406 f += 2;
407 if ( *f == -SNUMBER ) {
408 outfloat->_mp_exp = (mp_exp_t)(f[1]);
409 f += 2;
410 }
411 else {
412 f += ARGHEAD+6;
413 if ( f[-1] == -5 ) {
414 outfloat->_mp_exp =
415 -(mp_exp_t)((((ULONG)(f[-4]))<<BITSINWORD)+(UWORD)f[-5]);
416 }
417 else if ( f[-1] == 5 ) {
418 outfloat->_mp_exp =
419 (mp_exp_t)((((ULONG)(f[-4]))<<BITSINWORD)+(UWORD)f[-5]);
420 }
421 }
422/*
423 And now the limbs if needed
424*/
425 d = outfloat->_mp_d;
426 if ( outfloat->_mp_size == 0 ) {
427 for ( i = 0; i < outfloat->_mp_prec; i++ ) *d++ = 0;
428 return(0);
429 }
430 else if ( *f == -SNUMBER ) {
431 *d++ = (mp_limb_t)f[1];
432 for ( i = 0; i < outfloat->_mp_prec; i++ ) *d++ = 0;
433 return(0);
434 }
435 num = (*f-ARGHEAD-2)/2; /* 2*number of limbs in the argument */
436 t = (UWORD *)(f+ARGHEAD+1);
437 while ( num > 1 ) {
438 *d++ = (mp_limb_t)((((ULONG)(t[1]))<<BITSINWORD)+t[0]);
439 t += 2; num -= 2;
440 }
441 if ( num == 1 ) *d++ = (mp_limb_t)((UWORD)(*t));
442 for ( i = d-outfloat->_mp_d; i <= outfloat->_mp_prec; i++ ) *d++ = 0;
443 return(0);
444Incorrect:
445 return(-1);
446}
447
448/*
449 #] UnpackFloat :
450 #[ TestFloat :
451
452 Tells whether the function (with its arguments) is a legal float_.
453 We assume, as in the whole float library that one limb is 2 WORDs.
454*/
455
456int TestFloat(WORD *fun)
457{
458 WORD *fstop, *f, num, nnum, i;
459 fstop = fun+fun[1];
460 f = fun + FUNHEAD;
461 num = 0;
462/*
463 Count arguments
464*/
465 while ( f < fstop ) { num++; NEXTARG(f); }
466 if ( num != 4 ) return(0);
467 f = fun + FUNHEAD;
468 if ( *f != -SNUMBER ) return(0);
469 if ( f[1] < 0 ) return(0);
470 f += 2;
471 if ( *f != -SNUMBER ) return(0);
472 num = ABS(f[1]); /* number of limbs */
473 f += 2;
474 if ( *f == -SNUMBER ) { f += 2; }
475 else {
476 if ( *f != ARGHEAD+6 ) return(0);
477 if ( ABS(f[ARGHEAD+5]) != 5 ) return(0);
478 if ( f[ARGHEAD+3] != 1 ) return(0);
479 if ( f[ARGHEAD+4] != 0 ) return(0);
480 f += *f;
481 }
482 if ( num == 0 ) return(1);
483 if ( *f == -SNUMBER ) { if ( num != 1 ) return(0); }
484 else {
485 nnum = (ABS(f[*f-1])-1)/2;
486 if ( ( *f != 4*num+2+ARGHEAD ) && ( *f != 4*num+ARGHEAD ) ) return(0);
487 if ( ( nnum != 2*num ) && ( nnum != 2*num-1 ) ) return(0);
488 f += ARGHEAD+nnum+1;
489 if ( f[0] != 1 ) return(0);
490 for ( i = 1; i < nnum; i++ ) {
491 if ( f[i] != 0 ) return(0);
492 }
493 }
494 return(1);
495}
496
497/*
498 #] TestFloat :
499 #[ FormtoZ :
500
501 Converts a Form long integer to a GMP long integer.
502
503 typedef struct
504 {
505 int _mp_alloc; Number of *limbs* allocated and pointed
506 to by the _mp_d field.
507 int _mp_size; abs(_mp_size) is the number of limbs the
508 last field points to. If _mp_size is
509 negative this is a negative number.
510 mp_limb_t *_mp_d;Pointer to the limbs.
511 } __mpz_struct;
512 typedef __mpz_struct mpz_t[1];
513*/
514
515void FormtoZ(mpz_t z,UWORD *a,WORD na)
516{
517 int nlimbs, sgn = 1;
518 mp_limb_t *d;
519 UWORD *b = a;
520 WORD nb = na;
521
522 if ( nb == 0 ) {
523 z->_mp_size = 0;
524 z->_mp_d[0] = 0;
525 return;
526 }
527 if ( nb < 0 ) { sgn = -1; nb = -nb; }
528 nlimbs = (nb+1)/2;
529 if ( mpz_cmp_si(z,0L) <= 1 ) {
530 mpz_set_ui(z,10000000);
531 }
532 if ( z->_mp_alloc <= nlimbs ) {
533 mpz_t zz;
534 mpz_init(zz);
535 while ( z->_mp_alloc <= nlimbs ) {
536 mpz_mul(zz,z,z);
537 mpz_set(z,zz);
538 }
539 mpz_clear(zz);
540 }
541 z->_mp_size = sgn*nlimbs;
542 d = z->_mp_d;
543 while ( nb > 1 ) {
544 *d++ = (((mp_limb_t)(b[1]))<<BITSINWORD)+(mp_limb_t)(b[0]);
545 b += 2; nb -= 2;
546 }
547 if ( nb == 1 ) { *d = (mp_limb_t)(*b); }
548}
549
550/*
551 #] FormtoZ :
552 #[ ZtoForm :
553
554 Converts a GMP long integer to a Form long integer.
555 Mainly an exercise of going from little endian ULONGs.
556 to big endian UWORDs
557*/
558
559void ZtoForm(UWORD *a,WORD *na,mpz_t z)
560{
561 mp_limb_t *d = z->_mp_d;
562 int nlimbs = ABS(z->_mp_size), i;
563 UWORD j;
564 if ( nlimbs == 0 ) { *na = 0; return; }
565 *na = 0;
566 for ( i = 0; i < nlimbs-1; i++ ) {
567 *a++ = (UWORD)(*d);
568 *a++ = (UWORD)((*d++)>>BITSINWORD);
569 *na += 2;
570 }
571 *na += 1;
572 *a++ = (UWORD)(*d);
573 j = (UWORD)((*d)>>BITSINWORD);
574 if ( j != 0 ) { *a = j; *na += 1; }
575 if ( z->_mp_size < 0 ) *na = -*na;
576}
577
578/*
579 #] ZtoForm :
580 #[ FloatToInteger :
581
582 Converts a GMP float to a long Form integer.
583*/
584
585long FloatToInteger(UWORD *out, mpf_t floatin, long *bitsused)
586{
587 mpz_t z;
588 WORD nout, nx;
589 UWORD x;
590 mpz_init(z);
591 mpz_set_f(z,floatin);
592 ZtoForm(out,&nout,z);
593 mpz_clear(z);
594 x = out[nout-1]; nx = 0;
595 while ( x ) { nx++; x >>= 1; }
596 *bitsused = (nout-1)*BITSINWORD + nx;
597 return(nout);
598}
599
600/*
601 #] FloatToInteger :
602 #[ IntegerToFloat :
603
604 Converts a Form long integer to a gmp float of default size.
605 We assume that sizeof(unsigned long int) = 2*sizeof(UWORD).
606*/
607
608void IntegerToFloat(mpf_t result, UWORD *formlong, int longsize)
609{
610 mpz_t z;
611 mpz_init(z);
612 FormtoZ(z,formlong,longsize);
613 mpf_set_z(result,z);
614 mpz_clear(z);
615}
616
617/*
618 #] IntegerToFloat :
619 #[ RatToFloat :
620
621 Converts a Form rational to a gmp float of default size.
622*/
623
624void RatToFloat(mpf_t result, UWORD *formrat, int ratsize)
625{
626 GETIDENTITY
627 int nnum, nden;
628 UWORD *num, *den;
629 int sgn = 0;
630 if ( ratsize < 0 ) { ratsize = -ratsize; sgn = 1; }
631 nnum = nden = (ratsize-1)/2;
632 num = formrat; den = formrat+nnum;
633 while ( num[nnum-1] == 0 ) { nnum--; }
634 while ( den[nden-1] == 0 ) { nden--; }
635 IntegerToFloat(aux2,num,nnum);
636 IntegerToFloat(aux3,den,nden);
637 mpf_div(result,aux2,aux3);
638 if ( sgn > 0 ) mpf_neg(result,result);
639}
640
641/*
642 #] RatToFloat :
643 #[ FloatFunToRat :
644*/
645/* UNFINISHED_FEATURE_EXCL_START */
646WORD FloatFunToRat(PHEAD UWORD *ratout,WORD *in)
647{
648 WORD oldin = in[0], nratout;
649 in[0] = FLOATFUN;
650 UnpackFloat(aux4,in);
651 FloatToRat(ratout,&nratout,aux4);
652 in[0] = oldin;
653 return(nratout);
654}
655/* UNFINISHED_FEATURE_EXCL_STOP */
656/*
657 #] FloatFunToRat :
658 #[ FloatToRat :
659
660 Converts a gmp float to a Form rational.
661 The algorithm we use is 'repeated fractions' of the style
662 n0+1/(n1+1/(n2+1/(n3+.....)))
663 The moment we get an n that is very large we should have the proper fraction
664 Main problem: what if the sequence keeps going?
665 (there are always rounding errors)
666 We need a cutoff with an error condition.
667 Basically the product n0*n1*n2*... is an underlimit on the number of
668 digits in the answer. We can put a limit on this.
669 A return value of zero means that everything went fine.
670*/
671
672int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin)
673{
674 GETIDENTITY
675 WORD *out = AT.WorkPointer;
676 WORD s; /* the sign. */
677 UWORD *a, *b, *c, *d, *mc;
678 WORD na, nb, nc, nd, i;
679 int nout;
680 LONG oldpWorkPointer = AT.pWorkPointer;
681 long bitsused = 0, totalbitsused = 0, totalbits = AC.DefaultPrecision-AC.MaxWeight-1;
682 int retval = 0, startnul;
683 WantAddPointers(AC.DefaultPrecision); /* Horrible overkill */
684 AT.pWorkSpace[AT.pWorkPointer++] = out;
685 a = NumberMalloc("FloatToRat");
686 b = NumberMalloc("FloatToRat");
687
688 s = mpf_sgn(floatin);
689 if ( s < 0 ) mpf_neg(floatin,floatin);
690
691 Form_mpf_empty(aux1);
692 Form_mpf_empty(aux2);
693 Form_mpf_empty(aux3);
694
695 mpf_trunc(aux1,floatin); /* This should now be an integer */
696 mpf_sub(aux2,floatin,aux1); /* and this >= 0 */
697 if ( mpf_sgn(aux1) == 0 ) { *out++ = 0; startnul = 1; }
698 else {
699 nout = FloatToInteger((UWORD *)out,aux1,&totalbitsused);
700 out += nout;
701 startnul = 0;
702 }
703 AT.pWorkSpace[AT.pWorkPointer++] = out;
704 if ( mpf_sgn(aux2) ) {
705 for(;;) {
706 mpf_ui_div(aux3,1,aux2);
707 mpf_trunc(aux1,aux3);
708 mpf_sub(aux2,aux3,aux1);
709 if ( mpf_sgn(aux1) == 0 ) { *out++ = 0; }
710 else {
711 nout = FloatToInteger((UWORD *)out,aux1,&bitsused);
712 out += nout;
713 }
714 if ( bitsused > (totalbits-totalbitsused)/2 ) { break; }
715 if ( mpf_sgn(aux2) == 0 ) {
716 /*if ( startnul == 1 )*/ AT.pWorkSpace[AT.pWorkPointer++] = out;
717 break;
718 }
719 totalbitsused += bitsused;
720 AT.pWorkSpace[AT.pWorkPointer++] = out;
721 }
722 /*
723 For |floatin| << 1, we have startnul = 1 and hit the precision guard
724 already on the first continued-fraction step. The resulting float is
725 therefore close to the rational 0/1 and we can immediately return.
726 */
727 if ( startnul == 1 && AT.pWorkPointer == oldpWorkPointer + 2 ) {
728 *ratout++ = 0; *ratout++ = 1; *ratout = *nratout = 3;
729 goto ret;
730 }
731/*
732 At this point we have the function with the repeated fraction.
733 Now we should work out the fraction. Form code would be:
734 repeat id dum_(?a,x1?,x2?) = dum_(?a,x1+1/x2);
735 id dum_(x?) = x;
736 We have to work backwards. This is why we made a list of pointers
737 in AT.pWorkSpace
738
739 Now we need the long integers a and b.
740 Note that by construction there should never be a GCD!
741*/
742 out = (WORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
743 na = 1; a[0] = 1;
744 c = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
745 nc = nb = ((UWORD *)out)-c;
746 for ( i = 0; i < nb; i++ ) b[i] = c[i];
747 mc = c = NumberMalloc("FloatToRat");
748 while ( AT.pWorkPointer > oldpWorkPointer ) {
749 d = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
750 nd = (UWORD *)(AT.pWorkSpace[AT.pWorkPointer+1])-d; /* This is the x1 in the formula */
751 if ( nd == 1 && *d == 0 ) break;
752 c = a; a = b; b = c; nc = na; na = nb; nb = nc; /* 1/x2 */
753 MulLong(d,nd,a,na,mc,&nc);
754 AddLong(mc,nc,b,nb,b,&nb);
755 }
756 NumberFree(mc,"FloatToRat");
757 if ( startnul == 0 ) {
758 c = a; a = b; b = c; nc = na; na = nb; nb = nc;
759 }
760 }
761 else {
762 c = (UWORD *)(AT.pWorkSpace[oldpWorkPointer]);
763 na = (UWORD *)out - c;
764 for ( i = 0; i < na; i++ ) a[i] = c[i];
765 b[0] = 1; nb = 1;
766 }
767/*
768 Now we have the fraction in a/b. Create the rational and add the sign.
769*/
770 d = ratout;
771 if ( na == nb ) {
772 *nratout = (2*na+1)*s;
773 for ( i = 0; i < na; i++ ) *d++ = a[i];
774 for ( i = 0; i < nb; i++ ) *d++ = b[i];
775 }
776 else if ( na < nb ) {
777 *nratout = (2*nb+1)*s;
778 for ( i = 0; i < na; i++ ) *d++ = a[i];
779 for ( ; i < nb; i++ ) *d++ = 0;
780 for ( i = 0; i < nb; i++ ) *d++ = b[i];
781 }
782 else {
783 *nratout = (2*na+1)*s;
784 for ( i = 0; i < na; i++ ) *d++ = a[i];
785 for ( i = 0; i < nb; i++ ) *d++ = b[i];
786 for ( ; i < na; i++ ) *d++ = 0;
787 }
788 *d = (UWORD)(*nratout);
789 NumberFree(b,"FloatToRat");
790 NumberFree(a,"FloatToRat");
791 AT.pWorkPointer = oldpWorkPointer;
792/*
793 Just for check we go back to float
794*/
795 if ( s < 0 ) mpf_neg(floatin,floatin);
796/*
797 {
798 WORD n = *nratout;
799 RatToFloat(aux1,ratout,n);
800 mpf_sub(aux2,floatin,aux1);
801 gmp_printf("Diff is %.*Fe\n",40,aux2);
802 }
803*/
804ret:
805 return(retval);
806}
807
808/*
809 #] FloatToRat :
810 #[ ZeroTable :
811*/
812
813void ZeroTable(mpf_t *tab, int N)
814{
815 int i, j;
816 for ( i = 0; i < N; i++ ) {
817 for ( j = 0; j < tab[i]->_mp_prec; j++ ) tab[i]->_mp_d[j] = 0;
818 }
819}
820
821/*
822 #] ZeroTable :
823 #[ ReadFloat :
824
825 Used by the compiler. It reads a floating point number and
826 outputs it at AT.WorkPointer as if it were a float_ function
827 with its arguments.
828 The call enters with s[-1] == TFLOAT.
829*/
830
831SBYTE *ReadFloat(SBYTE *s)
832{
833 GETIDENTITY
834 SBYTE *ss, c;
835 ss = s;
836 while ( *ss > 0 ) ss++;
837 c = *ss; *ss = 0;
838 gmp_sscanf((char *)s,"%Ff",aux1);
839 if ( AT.WorkPointer > AT.WorkTop ) {
840 MLOCK(ErrorMessageLock);
841 MesWork();
842 MUNLOCK(ErrorMessageLock);
843 Terminate(-1);
844 }
845 PackFloat(AT.WorkPointer,aux1);
846 *ss = c;
847 return(ss);
848}
849
850/*
851 #] ReadFloat :
852 #[ CheckFloat :
853
854 For the tokenizer. Tests whether the input string can be a float.
855*/
856
857UBYTE *CheckFloat(UBYTE *ss, int *spec)
858{
859 GETIDENTITY
860 UBYTE *s = ss;
861 int gotdot = 0;
862 /* A single dot is not a valid float */
863 if ( *s == '.' && FG.cTable[s[-1]] != 1 && FG.cTable[s[1]] != 1 ) return(ss);
864 while ( FG.cTable[s[-1]] == 1 ) s--;
865 /* This cannot be a valid float */
866 if ( *s != '.' && FG.cTable[*s] != 1 ) return(ss);
867 *spec = 0;
868 while ( FG.cTable[*s] == 1 ) s++;
869 if ( *s == '.' ) {
870 gotdot = 1;
871 s++;
872 while ( FG.cTable[*s] == 1 ) s++;
873 }
874/*
875 Now we have had the mantissa part, which may be zero.
876 Check for an exponent.
877*/
878 if ( *s == 'e' || *s == 'E' ) {
879 s++;
880 if ( *s == '-' || *s == '+' ) s++;
881 if ( FG.cTable[*s] == 1 ) {
882 s++;
883 while ( FG.cTable[*s] == 1 ) s++;
884 }
885 else { return(ss); }
886 }
887 else if ( gotdot == 0 ) return(ss); /* No radix point and no exponent */
888 if ( AT.aux_ == 0 ) { /* no floating point system */
889 *spec = -1;
890 return(s);
891 }
892 return(s);
893}
894
895/*
896 #] CheckFloat :
897 #] Low Level :
898 #[ Float Routines :
899 #[ SetFloatPrecision :
900
901 Sets the default precision (in bits) of the floats and allocate
902 buffer space for an output string.
903 The buffer is used by PrintFloat (decimal output) and Strictrounding
904 (binary or decimal output), so it must accommodate the larger space
905 requirement:
906 exponent: up to 12 chars.
907 mantissa: prec + a little bit extra
908*/
909
910int SetFloatPrecision(WORD prec)
911{
912 if ( prec <= 0 ) {
913 MesPrint("&Illegal value for number of bits for floating point constants: %d",prec);
914 return(-1);
915 }
916 else {
917 AC.DefaultPrecision = prec;
918 if ( AO.floatspace != 0 ) M_free(AO.floatspace,"floatspace");
919 AO.floatsize = (prec+20)*sizeof(char);
920 AO.floatspace = (UBYTE *)Malloc1(AO.floatsize,"floatspace");
921 mpf_set_default_prec(prec);
922 return(0);
923 }
924}
925
926/*
927 #] SetFloatPrecision :
928 #[ PrintFloat :
929
930 Print the float_ function with its arguments as a floating point
931 number with numdigits digits.
932 If however we use rawfloat as a format option it prints it as a
933 regular Form function and it should never come here because the
934 print routines in sch.c should intercept it.
935 The buffer AO.floatspace is allocated when the precision of the
936 floats is set in the routine SetFloatPrecision.
937*/
938
939int PrintFloat(WORD *fun,int numdigits)
940{
941 GETIDENTITY
942 UBYTE *s1, *s2;
943 int n = 0;
944 int prec = (AC.DefaultPrecision-AC.MaxWeight-1)*log10(2.0);
945 if ( numdigits > prec || numdigits == 0 ) {
946 numdigits = prec;
947 }
948/*
949 GMP's gmp_snprintf always prints a non-zero number before the decimal point, so we
950 ask for one digit less.
951*/
952 if ( UnpackFloat(aux4,fun) == 0 )
953 n = gmp_snprintf((char *)(AO.floatspace),AO.floatsize,"%.*Fe",numdigits-1,aux4);
954 if ( n > 0 ) {
955 int n1, n2 = n;
956 s1 = AO.floatspace+n;
957 while ( s1 > AO.floatspace && s1[-1] != 'e'
958 && s1[-1] != 'E' && s1[-1] != '.' ) { s1--; n2--; }
959 if ( s1 > AO.floatspace && s1[-1] != '.' ) {
960 s1--; n2--;
961 s2 = s1; n1 = n2;
962 while ( s1[-1] == '0' ) { s1--; n1--; }
963 if ( s1[-1] == '.' ) { s1++; n1++; }
964 n -= (n2-n1);
965 while ( n1 < n ) { *s1++ = *s2++; n1++; }
966 *s1 = 0;
967 }
968 if ( AC.OutputMode == FORTRANMODE ) {
969 s1 = AO.floatspace+n;
970 while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) {
971 s1--;
972 }
973 if ( ( AO.DoubleFlag & 2 ) == 2 ) { *s1 = 'Q'; } /* Quadruple precision fortran */
974 else if ( ( AO.DoubleFlag & 1 ) == 1 ) { *s1 = 'D'; } /* Double precision fortran */
975 else { *s1 = 'E'; } /* Single precision fortran */
976 }
977 if ( AC.OutputMode == MATHEMATICAMODE ) {
978 s1 = AO.floatspace+n;
979 s2 = s1+2; *s2-- = 0;
980 while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) {
981 *s2-- = *s1--;
982 }
983 *s2-- = '^'; *s2 = '*'; /* Replace 'e' by '^*' */
984 n++;
985 }
986 }
987 return(n);
988}
989
990/*
991 #] PrintFloat :
992 #[ AddFloats :
993*/
994/* UNFINISHED_FEATURE_EXCL_START */
995int AddFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
996{
997 int retval = 0;
998 if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
999 mpf_add(aux1,aux1,aux2);
1000 PackFloat(fun3,aux1);
1001 }
1002 else { retval = -1; }
1003 return(retval);
1004}
1005/* UNFINISHED_FEATURE_EXCL_STOP */
1006/*
1007 #] AddFloats :
1008 #[ MulFloats :
1009*/
1010/* UNFINISHED_FEATURE_EXCL_START */
1011int MulFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
1012{
1013 int retval = 0;
1014 if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
1015 mpf_mul(aux1,aux1,aux2);
1016 PackFloat(fun3,aux1);
1017 }
1018 else { retval = -1; }
1019 return(retval);
1020}
1021/* UNFINISHED_FEATURE_EXCL_STOP */
1022/*
1023 #] MulFloats :
1024 #[ DivFloats :
1025*/
1026/* UNFINISHED_FEATURE_EXCL_START */
1027int DivFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
1028{
1029 int retval = 0;
1030 if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
1031 mpf_div(aux1,aux1,aux2);
1032 PackFloat(fun3,aux1);
1033 }
1034 else { retval = -1; }
1035 return(retval);
1036}
1037/* UNFINISHED_FEATURE_EXCL_STOP */
1038/*
1039 #] DivFloats :
1040 #[ AddRatToFloat :
1041
1042 Note: this can be optimized, because often the rat is rather simple.
1043*/
1044/* UNFINISHED_FEATURE_EXCL_START */
1045int AddRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat)
1046{
1047 int retval = 0;
1048 if ( UnpackFloat(aux2,infun) == 0 ) {
1049 RatToFloat(aux1,formrat,nrat);
1050 mpf_add(aux2,aux2,aux1);
1051 PackFloat(outfun,aux2);
1052 }
1053 else retval = -1;
1054 return(retval);
1055}
1056/* UNFINISHED_FEATURE_EXCL_STOP */
1057/*
1058 #] AddRatToFloat :
1059 #[ MulRatToFloat :
1060
1061 Note: this can be optimized, because often the rat is rather simple.
1062*/
1063/* UNFINISHED_FEATURE_EXCL_START */
1064int MulRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat)
1065{
1066 int retval = 0;
1067 if ( UnpackFloat(aux2,infun) == 0 ) {
1068 RatToFloat(aux1,formrat,nrat);
1069 mpf_mul(aux2,aux2,aux1);
1070 PackFloat(outfun,aux2);
1071 }
1072 else retval = -1;
1073 return(retval);
1074}
1075/* UNFINISHED_FEATURE_EXCL_STOP */
1076/*
1077 #] MulRatToFloat :
1078 #[ SetupMZVTables :
1079*/
1080
1081void SetupMZVTables(void)
1082{
1083/*
1084 Sets up a table of N+1 mpf_t floats with variable precision.
1085 It assumes that each next element needs one bit less.
1086 Initializes all of them.
1087 We take some extra space, to have one limb overflow everywhere.
1088 Because the depth of the MZV's can get close to the weight
1089 and each deeper sum goes one higher, we make the tablesize a bit bigger.
1090 This may not be needed if we fiddle with the sum boundaries.
1091*/
1092#ifdef WITHPTHREADS
1093 int i, Nw, id, totnum;
1094 size_t N;
1095 mpf_t *a;
1096 Nw = AC.DefaultPrecision;
1097 N = (size_t)Nw;
1098 totnum = AM.totalnumberofthreads;
1099 for ( id = 0; id < totnum; id++ ) {
1100 AB[id]->T.mpf_tab1 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab1");
1101 a = (mpf_t *)AB[id]->T.mpf_tab1;
1102 for ( i = 0; i <=Nw; i++ ) {
1103/*
1104 As explained in the comment above, we could make this variable precision
1105 using mpf_init2.
1106*/
1107 mpf_init(a[i]);
1108 }
1109 AB[id]->T.mpf_tab2 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab2");
1110 a = (mpf_t *)AB[id]->T.mpf_tab2;
1111 for ( i = 0; i <=Nw; i++ ) {
1112 mpf_init(a[i]);
1113 }
1114 }
1115#else
1116 int i, Nw;
1117 size_t N;
1118 Nw = AC.DefaultPrecision;
1119 N = (size_t)Nw;
1120 AT.mpf_tab1 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab1");
1121 for ( i = 0; i <= Nw; i++ ) {
1122/*
1123 As explained in the comment above, we could make this variable precision
1124 using mpf_init2.
1125*/
1126 mpf_init(mpftab1[i]);
1127 }
1128 AT.mpf_tab2 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab2");
1129 for ( i = 0; i <= Nw; i++ ) {
1130 mpf_init(mpftab2[i]);
1131 }
1132#endif
1133 AS.delta_1 = (void *)Malloc1(sizeof(mpf_t),"delta1");
1134 mpf_init(mpfdelta1);
1135 SimpleDelta(mpfdelta1,1); /* this can speed up things. delta1 = ln(2) */
1136}
1137
1138/*
1139 #] SetupMZVTables :
1140 #[ SetupMPFTables :
1141
1142 Allocates the aux variables
1143*/
1144
1145void SetupMPFTables(void)
1146{
1147#ifdef WITHPTHREADS
1148 int totnum = AM.totalnumberofthreads, id;
1149 mpf_t *a;
1150 totnum = totnum + GetNumberOfSortBots(totnum - 1);
1151 for ( id = 0; id < totnum; id++ ) {
1152/*
1153 We work here with a[0] etc because the aux1 etc contain B which
1154 in the current routine would be AB[0] only
1155*/
1156 AB[id]->T.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AB[id]->T.aux_");
1157 a = (mpf_t *)AB[id]->T.aux_;
1158 mpf_inits(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
1159 if ( AB[id]->T.indi1 ) M_free(AB[id]->T.indi1,"indi1");
1160 AB[id]->T.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
1161 AB[id]->T.indi2 = AB[id]->T.indi1 + AC.MaxWeight;
1162 }
1163#else
1164 AT.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AT.aux_");
1165 mpf_inits(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
1166 if ( AT.indi1 ) M_free(AT.indi1,"indi1");
1167 AT.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
1168 AT.indi2 = AT.indi1 + AC.MaxWeight;
1169#endif
1170}
1171
1172/*
1173 #] SetupMPFTables :
1174 #[ ClearMZVTables :
1175*/
1176
1177void ClearMZVTables(void)
1178{
1179#ifdef WITHPTHREADS
1180 int i, id, totnum;
1181 mpf_t *a;
1182 totnum = AM.totalnumberofthreads;
1183 for ( id = 0; id < totnum; id++ ) {
1184 if ( AB[id]->T.mpf_tab1 ) {
1185/*
1186 We work here with a[0] etc because the aux1, mpftab1 etc contain B
1187 which in the current routine would be AB[0] only
1188*/
1189 a = (mpf_t *)AB[id]->T.mpf_tab1;
1190 for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
1191 mpf_clear(a[i]);
1192 }
1193 M_free(AB[id]->T.mpf_tab1,"mpftab1");
1194 AB[id]->T.mpf_tab1 = 0;
1195 }
1196 if ( AB[id]->T.mpf_tab2 ) {
1197 a = (mpf_t *)AB[id]->T.mpf_tab2;
1198 for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
1199 mpf_clear(a[i]);
1200 }
1201 M_free(AB[id]->T.mpf_tab2,"mpftab2");
1202 AB[id]->T.mpf_tab2 = 0;
1203 }
1204 }
1205 totnum = totnum + GetNumberOfSortBots(totnum - 1);
1206 for ( id = 0; id < totnum; id++ ) {
1207 if ( AB[id]->T.aux_ ) {
1208 a = (mpf_t *)AB[id]->T.aux_;
1209 mpf_clears(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
1210 M_free(AB[id]->T.aux_,"AB[id]->T.aux_");
1211 AB[id]->T.aux_ = 0;
1212 }
1213 if ( AB[id]->T.indi1 ) { M_free(AB[id]->T.indi1,"indi1"); AB[id]->T.indi1 = 0; }
1214 }
1215#else
1216 int i;
1217 if ( AT.mpf_tab1 ) {
1218 for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
1219 mpf_clear(mpftab1[i]);
1220 }
1221 M_free(AT.mpf_tab1,"mpftab1");
1222 AT.mpf_tab1 = 0;
1223 }
1224 if ( AT.mpf_tab2 ) {
1225 for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
1226 mpf_clear(mpftab2[i]);
1227 }
1228 M_free(AT.mpf_tab2,"mpftab2");
1229 AT.mpf_tab2 = 0;
1230 }
1231 if ( AT.aux_ ) {
1232 mpf_clears(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
1233 M_free(AT.aux_,"AT.aux_");
1234 AT.aux_ = 0;
1235 }
1236 if ( AT.indi1 ) { M_free(AT.indi1,"indi1"); AT.indi1 = 0; }
1237#endif
1238 if ( AO.floatspace ) { M_free(AO.floatspace,"floatspace"); AO.floatspace = 0;
1239 AO.floatsize = 0; }
1240 if ( AS.delta_1 ) {
1241 mpf_clear(mpfdelta1);
1242 M_free(AS.delta_1,"delta1");
1243 AS.delta_1 = 0;
1244 }
1245}
1246
1247/*
1248 #] ClearMZVTables :
1249 #[ CoToFloat :
1250*/
1251
1252int CoToFloat(UBYTE *s)
1253{
1254 GETIDENTITY
1255 if ( AT.aux_ == 0 ) {
1256 MesPrint("&Illegal attempt to convert to float_ without activating floating point numbers.");
1257 MesPrint("&Forgotten %#startfloat instruction?");
1258 return(1);
1259 }
1260 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1261 if ( *s ) {
1262 MesPrint("&Illegal argument(s) in ToFloat statement: '%s'",s);
1263 return(1);
1264 }
1265 Add2Com(TYPETOFLOAT);
1266 return(0);
1267}
1268
1269/*
1270 #] CoToFloat :
1271 #[ CoToRat :
1272*/
1273
1274int CoToRat(UBYTE *s)
1275{
1276 GETIDENTITY
1277 if ( AT.aux_ == 0 ) {
1278 MesPrint("&Illegal attempt to convert from float_ without activating floating point numbers.");
1279 MesPrint("&Forgotten %#startfloat instruction?");
1280 return(1);
1281 }
1282 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1283 if ( *s ) {
1284 MesPrint("&Illegal argument(s) in ToRat statement: '%s'",s);
1285 return(1);
1286 }
1287 Add2Com(TYPETORAT);
1288 return(0);
1289}
1290
1291/*
1292 #] CoToRat :
1293 #[ CoStrictRounding :
1294
1295 Syntax: StrictRounding [precision][base]
1296 - precision: number of digits to round to (optional)
1297 - base: 'd' for decimal (base 10) or 'b' for binary (base 2)
1298
1299 If no arguments are provided, uses default precision with binary base.
1300*/
1301int CoStrictRounding(UBYTE *s)
1302{
1303 GETIDENTITY
1304 WORD x;
1305 int base;
1306 if ( AT.aux_ == 0 ) {
1307 MesPrint("&Illegal attempt for strict rounding without activating floating point numbers.");
1308 MesPrint("&Forgotten %#startfloat instruction?");
1309 return(1);
1310 }
1311 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1312 if ( *s == 0 ) {
1313 /* No subkey, which means round to default precision */
1314 x = AC.DefaultPrecision - AC.MaxWeight - 1;
1315 base = 2;
1316 }
1317 else if ( FG.cTable[*s] == 1 ) { /* number */
1318 ParseNumber(x,s)
1319 if ( tolower(*s) == 'd' ) { base = 10; s++; } /* decimal base */
1320 else if ( tolower(*s) == 'b' ){ base = 2; s++; } /* binary base */
1321 else goto IllPar; /* invalid base specification */
1322 }
1323 else {
1324 goto IllPar;
1325 }
1326 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1327
1328 /* Check for invalid arguments */
1329 if ( *s ) {
1330IllPar:
1331 MesPrint("&Illegal argument(s) in StrictRounding statement: '%s'",s);
1332 return(1);
1333 }
1334 Add4Com(TYPESTRICTROUNDING,x,base);
1335 return(0);
1336}
1337/*
1338 #] CoStrictRounding :
1339 #[ CoChop :
1340
1341 LHS notation of the chop statement:
1342 TYPECHOP, length, FLOATFUN, ...
1343 where FLOATFUN, ... represents the threshold of the chop statement in
1344 the notation of a float_ function with its arguments.
1345
1346*/
1347
1348int CoChop(UBYTE *s)
1349{
1350 GETIDENTITY
1351 UBYTE *ss, c;
1352 WORD *w, *OldWork;
1353 int spec, pow = 1;
1354 unsigned long x;
1355 if ( AT.aux_ == 0 ) {
1356 MesPrint("&Illegal attempt to chop a float_ without activating floating point numbers.");
1357 MesPrint("&Forgotten %#startfloat instruction?");
1358 return(1);
1359 }
1360 if ( *s == 0 ) {
1361 MesPrint("&Chop needs a number (float, rational or power) as an argument.");
1362 return(1);
1363 }
1364 /* Create TYPECHOP header */
1365 w = OldWork = AT.WorkPointer;
1366 *w++ = TYPECHOP;
1367 w++;
1368
1369 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1370
1371 /*
1372 The argument of chop can be
1373 1: a floating-point number
1374 2: an integer, rational number or power
1375 */
1376 if ( FG.cTable[*s] == 1 || *s == '.' ) {
1377 /* 1: Attempt to parse as floating-point number */
1378 ss = CheckFloat(s, &spec);
1379 if ( ss > s ) {
1380 /* CheckFloat found a valid float */
1381 AT.WorkPointer = w;
1382 /*
1383 Reads the floating point number and outputs it at AT.WorkPointer as if it were a float_
1384 function with its arguments.
1385 */
1386 ReadFloat((SBYTE *)s);
1387 s = ss;
1388 w += w[1];
1389 }
1390 else {
1391 /* 2: CheckFloat didn't find a float, we now try for rationals and powers */
1392 /* Parse the integer part (numerator for rationals) */
1393 if ( FG.cTable[*s] == 1 ) {
1394 ParseNumber(x,s)
1395 mpf_set_ui(aux1,x);
1396 }
1397 while ( *s == ' ' || *s == '\t' ) s++;
1398 /* Check for rational number or power*/
1399 if ( *s == '/' || *s == '^' ) {
1400 c = *s; s++;
1401 while ( *s == ' ' || *s == '\t' ) s++;
1402 if ( *s == '-' ) { s++; pow = -1; } /* negative power */
1403 /* Parse the denominator or power */
1404 if ( FG.cTable[*s] == 1 ) {
1405 ParseNumber(x,s)
1406 if ( c == '/' ) { /* rational */
1407 if ( x == 0 ) {
1408 MesPrint("&Division by zero in chop statement.");
1409 return(1);
1410 }
1411 /* Perform the division */
1412 mpf_div_ui(aux1, aux1,x);
1413 }
1414 else { /* Power */
1415 mpf_pow_ui(aux1,aux1,x);
1416 if ( pow == -1 ) {
1417 mpf_ui_div(aux1,(unsigned long) 1, aux1);
1418 }
1419 }
1420 }
1421 }
1422 /* Put aux1 in the notation of a float_ function */
1423 PackFloat(w, aux1);
1424 w += w[1];
1425 }
1426 }
1427 if ( *s ) {
1428 MesPrint("&Illegal argument(s) in Chop statement: '%s'.",s);
1429 return(1);
1430 }
1431 AT.WorkPointer = OldWork;
1432 AT.WorkPointer[1] = w - AT.WorkPointer; /* Set total length */
1433 AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
1434 return(0);
1435}
1436
1437/*
1438 #] CoChop :
1439 #[ ToFloat :
1440
1441 Converts the coefficient to floating point if it is still a rat.
1442*/
1443
1444int ToFloat(PHEAD WORD *term, WORD level)
1445{
1446 WORD *t, *tstop, nsize, nsign = 3;
1447 t = term+*term;
1448 nsize = ABS(t[-1]);
1449 tstop = t - nsize;
1450 if ( t[-1] < 0 ) { nsign = -nsign; }
1451 if ( nsize == 3 && t[-2] == 1 && t[-3] == 1 ) { /* Could be float */
1452 t = term + 1;
1453 while ( t < tstop ) {
1454 if ( ( *t == FLOATFUN ) && ( t+t[1] == tstop ) ) {
1455 return(Generator(BHEAD term,level));
1456 }
1457 t += t[1];
1458 }
1459 }
1460 RatToFloat(aux4,(UWORD *)tstop,nsize);
1461 PackFloat(tstop,aux4);
1462 tstop += tstop[1];
1463 *tstop++ = 1; *tstop++ = 1; *tstop++ = nsign;
1464 *term = tstop - term;
1465 AT.WorkPointer = tstop;
1466 return(Generator(BHEAD term,level));
1467}
1468
1469/*
1470 #] ToFloat :
1471 #[ ToRat :
1472
1473 Tries to convert the coefficient to rational if it is still a float.
1474*/
1475
1476int ToRat(PHEAD WORD *term, WORD level)
1477{
1478 WORD *tstop, *t, nsize, nsign, ncoef;
1479/*
1480 1: find the float which should be at the end.
1481*/
1482 tstop = term + *term; nsize = ABS(tstop[-1]);
1483 nsign = tstop[-1] < 0 ? -1: 1; tstop -= nsize;
1484 t = term+1;
1485 while ( t < tstop ) {
1486 if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1487 nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
1488 t += t[1];
1489 }
1490 if ( t < tstop ) {
1491/*
1492 Now t points at the float_ function and everything is correct.
1493 The result can go straight over the float_ function.
1494*/
1495 UnpackFloat(aux4,t);
1496 // If aux4 is zero, the term vanishes
1497 if ( mpf_sgn(aux4) == 0 ) return(0);
1498 if ( FloatToRat((UWORD *)t,&ncoef,aux4) == 0 ) {
1499 // Check if the resulting rational is zero
1500 if ( t[0] == 0 && t[1] == 1 && ncoef == 3 ) return(0);
1501 t += ABS(ncoef);
1502 t[-1] = ncoef*nsign;
1503 *term = t - term;
1504 }
1505 }
1506 return(Generator(BHEAD term,level));
1507}
1508
1509/*
1510 #] ToRat :
1511 #[ StrictRounding :
1512
1513 Rounds floating point numbers to a specified precision
1514 in a given base (decimal or binary).
1515*/
1516int StrictRounding(PHEAD WORD *term, WORD level, WORD prec, WORD base) {
1517 WORD *t,*tstop;
1518 int sign,size,maxprec = AC.DefaultPrecision-AC.MaxWeight-1;
1519 /* maxprec is in bits */
1520 if ( base == 2 && prec > maxprec ) {
1521 prec = maxprec;
1522 }
1523 if ( base == 10 && prec > (int)(maxprec*log10(2.0)) ) {
1524 prec = maxprec*log10(2.0);
1525 }
1526 /* Find the float which should be at the end. */
1527 tstop = term + *term; size = ABS(tstop[-1]);
1528 sign = tstop[-1] < 0 ? -1: 1; tstop -= size;
1529 t = term+1;
1530 while ( t < tstop ) {
1531 if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1532 size == 3 && tstop[0] == 1 && tstop[1] == 1) {
1533 break;
1534 }
1535 t += t[1];
1536 }
1537 if ( t < tstop ) {
1538/*
1539 Now t points at the float_ function and everything is correct.
1540 The result can go straight over the float_ function.
1541*/
1542 char *s;
1543 mp_exp_t exp;
1544 /* Extract the floating point value */
1545 UnpackFloat(aux4,t);
1546 /* Convert to string:
1547 - Format as MeN with M the mantissa and N the exponent
1548 - the generated string by mpf_get_str is the fraction/mantissa with
1549 an implicit radix point immediately to the left of the first digit.
1550 The applicable exponent is written in exp. */
1551 s = (char *)AO.floatspace;
1552 *s++ = '.';
1553 mpf_get_str(s,&exp, base, prec, aux4);
1554 while ( *s != 0 ) s++;
1555 *s++ = 'e';
1556 snprintf(s,AO.floatsize-(s-(char *)AO.floatspace),"%ld",exp);
1557 /* Negative base values are used to specify that the exponent is in decimal */
1558 mpf_set_str(aux4,(char *)AO.floatspace,-base);
1559 /* Pack the rounded floating point value back into the term */
1560 PackFloat(t,aux4);
1561 t+=t[1];
1562 *t++ = 1; *t++ = 1; *t++ = 3*sign;
1563 *term = t - term;
1564 }
1565 return(Generator(BHEAD term,level));
1566}
1567/*
1568 #] StrictRounding :
1569 #[ Chop :
1570
1571 Removes terms with a floating point number smaller than a given threshold.
1572
1573 Search for a FLOATFUN and compares its absolute value against the threshold
1574 specified in the chop statement. This threshold can be obtained from the
1575 LHS of the chop statement in the compiler buffer.
1576
1577 */
1578int Chop(PHEAD WORD *term, WORD level)
1579{
1580 WORD *tstop, *t, nsize, *threshold;
1581 CBUF *C = cbuf+AM.rbufnum;
1582 /* Find the float which should be at the end. */
1583 tstop = term + *term;
1584 nsize = ABS(tstop[-1]); tstop -= nsize;
1585 t = term+1;
1586 while ( t < tstop ) {
1587 if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1588 nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
1589 t += t[1];
1590 }
1591 if ( t < tstop ) {
1592 /* Get threshold value from compiler buffer */
1593 threshold = C->lhs[level];
1594 threshold += 2; /* Skip TYPECHOP header */
1595 UnpackFloat(aux5, threshold);
1596
1597 /* Extract float and compute its absolute value */
1598 UnpackFloat(aux4, t);
1599 mpf_abs(aux4, aux4);
1600
1601 /* Remove if < threshold */
1602 if ( mpf_cmp(aux4, aux5) < 0 ) return(0);
1603 }
1604 return(Generator(BHEAD term,level));
1605}
1606
1607/*
1608 #] Chop :
1609 #] Float Routines :
1610 #[ Sorting :
1611
1612 We need a method to see whether two terms need addition that could
1613 involve floating point numbers.
1614 1: if PolyWise is active, we do not need anything, because
1615 Poly(Rat)Fun and floating point are mutually exclusive.
1616 2: This means that there should be only interference in AddCoef.
1617 and the AddRat parts in MergePatches, MasterMerge, SortBotMerge
1618 and PF_GetLoser.
1619 The compare routine(s) should recognise the float_ and give off
1620 a code (SortFloatMode) inside the AT struct:
1621 0: no float_
1622 1: float_ in term1 only
1623 2: float_ in term2 only
1624 3: float_ in both terms
1625 Be careful: we have several compare routines, because various codes
1626 use their own routines and we just set a variable with its address.
1627 Currently we have Compare1, CompareSymbols and CompareHSymbols.
1628 Only Compare1 should be active for this. The others should make sure
1629 that the proper variable is always zero.
1630 Remember: the sign of the coefficient is in the last word of the term.
1631
1632 We need two routines:
1633 1: AddWithFloat for SplitMerge which sorts by pointer.
1634 2: MergeWithFloat for MergePatches etc which keeps terms as much
1635 as possible in their location.
1636 The routines start out the same, because AT.SortFloatMode, set in
1637 Compare1, tells more or less what should be done.
1638 The difference is in where we leave the result.
1639
1640 In the future we may want to add a feature that makes the result
1641 zero if the sum comes within a certain distance of the numerical
1642 accuracy, like for instance 5% of the number of bits.
1643
1644 #[ AddWithFloat :
1645*/
1646
1647int AddWithFloat(PHEAD WORD **ps1, WORD **ps2)
1648{
1649 GETBIDENTITY
1650 SORTING *S = AT.SS;
1651 WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3;
1652 WORD *s1,*s2,sign3,j,jj, *t1, *t2, i;
1653 s1 = *ps1;
1654 s2 = *ps2;
1655 coef1 = s1+*s1; size1 = coef1[-1]; coef1 -= ABS(coef1[-1]);
1656 coef2 = s2+*s2; size2 = coef2[-1]; coef2 -= ABS(coef2[-1]);
1657 if ( AT.SortFloatMode == 3 ) {
1658 fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1659 fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1660 UnpackFloat(aux1,fun1);
1661 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1662 UnpackFloat(aux2,fun2);
1663 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1664 }
1665 else if ( AT.SortFloatMode == 1 ) {
1666 fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1667 UnpackFloat(aux1,fun1);
1668 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1669 fun2 = coef2;
1670 RatToFloat(aux2,(UWORD *)coef2,size2);
1671 }
1672 else if ( AT.SortFloatMode == 2 ) {
1673 fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1674 fun1 = coef1;
1675 RatToFloat(aux1,(UWORD *)coef1,size1);
1676 UnpackFloat(aux2,fun2);
1677 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1678 }
1679 else {
1680/* INTERNAL_ERROR_EXCL_START */
1681 MLOCK(ErrorMessageLock);
1682 MesPrint("!>Illegal value %d for AT.SortFloatMode in AddWithFloat.",AT.SortFloatMode);
1683 MUNLOCK(ErrorMessageLock);
1684 Terminate(-1);
1685 return(0);
1686/* INTERNAL_ERROR_EXCL_STOP */
1687 }
1688 mpf_add(aux3,aux1,aux2);
1689 sign3 = mpf_sgn(aux3);
1690 if ( sign3 < 0 ) mpf_neg(aux3,aux3);
1691 fun3 = TermMalloc("AddWithFloat");
1692 PackFloat(fun3,aux3);
1693/*
1694 Now we have to calculate where the sumterm fits.
1695 If we are sloppy, we can be faster, but run the risk to need the
1696 extension space, even when it is not needed. At slightly lower speed
1697 (ie first creating the result in scribble space) we are better off.
1698 This is why we use TermMalloc.
1699
1700 The new term will have a rational coefficient of 1,1,+-3.
1701 The size will be (fun1 or fun2 - term) + fun3 +3;
1702*/
1703 if ( AT.SortFloatMode == 3 ) {
1704 if ( fun1[1] == fun3[1] ) {
1705Over1:
1706 i = fun3[1]; t1 = fun1; t2 = fun3; NCOPY(t1,t2,i);
1707 *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1708 *s1 = t1-s1; goto Finished;
1709 }
1710 else if ( fun2[1] == fun3[1] ) {
1711Over2:
1712 i = fun3[1]; t1 = fun2; t2 = fun3; NCOPY(t1,t2,i);
1713 *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1714 *s2 = t1-s2; *ps1 = s2; goto Finished;
1715 }
1716 else if ( fun1[1] >= fun3[1] ) goto Over1;
1717 else if ( fun2[1] >= fun3[1] ) goto Over2;
1718 }
1719 else if ( AT.SortFloatMode == 1 ) {
1720 if ( fun1[1] >= fun3[1] ) goto Over1;
1721 else if ( fun3[1]+3 <= ABS(size2) ) goto Over2;
1722 }
1723 else if ( AT.SortFloatMode == 2 ) {
1724 if ( fun2[1] >= fun3[1] ) goto Over2;
1725 else if ( fun3[1]+3 <= ABS(size1) ) goto Over1;
1726 }
1727/*
1728 Does not fit. Go to extension space.
1729*/
1730 jj = fun1-s1;
1731 j = jj+fun3[1]+3; /* space needed */
1732 if ( (S->sFill + j) >= S->sTop2 ) {
1733 GarbHand();
1734 s1 = *ps1; /* new position of the term after the garbage collection */
1735 fun1 = s1+jj;
1736 }
1737 t1 = S->sFill;
1738 for ( i = 0; i < jj; i++ ) *t1++ = s1[i];
1739 i = fun3[1]; s1 = fun3; NCOPY(t1,s1,i);
1740 *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1741 *ps1 = S->sFill;
1742 **ps1 = t1-*ps1;
1743 S->sFill = t1;
1744Finished:
1745 *ps2 = 0;
1746 TermFree(fun3,"AddWithFloat");
1747 AT.SortFloatMode = 0;
1748 if ( **ps1 > AM.MaxTer/((LONG)(sizeof(WORD))) ) {
1749 MLOCK(ErrorMessageLock);
1750 MesPrint("Term too complex after addition in sort. MaxTermSize = %10l",
1751 AM.MaxTer/sizeof(WORD));
1752 MUNLOCK(ErrorMessageLock);
1753 Terminate(-1);
1754 }
1755 if ( **ps1 > S->verbMaxTermSize ) S->verbMaxTermSize = **ps1;
1756 return(1);
1757}
1758
1759/*
1760 #] AddWithFloat :
1761 #[ MergeWithFloat :
1762
1763 Note that we always park the result on top of term1.
1764 This makes life easier, because the original AddRat in MergePatches
1765 does this as well.
1766*/
1767
1768int MergeWithFloat(PHEAD WORD **interm1, WORD **interm2)
1769{
1770 GETBIDENTITY
1771 WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3, *tt;
1772 WORD sign3,jj, *t1, *t2, i, *term1 = *interm1, *term2 = *interm2;
1773 int retval = 0;
1774 coef1 = term1+*term1; size1 = coef1[-1]; coef1 -= ABS(size1);
1775 coef2 = term2+*term2; size2 = coef2[-1]; coef2 -= ABS(size2);
1776 if ( AT.SortFloatMode == 3 ) {
1777 fun1 = term1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1778 fun2 = term2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1779 UnpackFloat(aux1,fun1);
1780 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1781 UnpackFloat(aux2,fun2);
1782 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1783 }
1784 else if ( AT.SortFloatMode == 1 ) {
1785 fun1 = term1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1786 UnpackFloat(aux1,fun1);
1787 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1788 fun2 = coef2;
1789 RatToFloat(aux2,(UWORD *)coef2,size2);
1790 }
1791 else if ( AT.SortFloatMode == 2 ) {
1792 fun2 = term2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1793 fun1 = coef1;
1794 RatToFloat(aux1,(UWORD *)coef1,size1);
1795 UnpackFloat(aux2,fun2);
1796 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1797 }
1798 else {
1799/* INTERNAL_ERROR_EXCL_START */
1800 MLOCK(ErrorMessageLock);
1801 MesPrint("!>Illegal value %d for AT.SortFloatMode in MergeWithFloat.",AT.SortFloatMode);
1802 MUNLOCK(ErrorMessageLock);
1803 Terminate(-1);
1804 return(0);
1805/* INTERNAL_ERROR_EXCL_STOP */
1806 }
1807 mpf_add(aux3,aux1,aux2);
1808 sign3 = mpf_sgn(aux3);
1809/*
1810 Now check whether we can park the result on top of one of the input terms.
1811*/
1812 if ( sign3 < 0 ) mpf_neg(aux3,aux3);
1813 fun3 = TermMalloc("MergeWithFloat");
1814 PackFloat(fun3,aux3);
1815 if ( AT.SortFloatMode == 3 ) {
1816 if ( fun1[1] + ABS(size1) == fun3[1] + 3 ) {
1817OnTopOf1: t1 = fun3; t2 = fun1;
1818 for ( i = 0; i < fun3[1]; i++ ) *t2++ = *t1++;
1819 *t2++ = 1; *t2++ = 1; *t2++ = sign3 < 0 ? -3: 3;
1820 retval = 1;
1821 }
1822 else if ( fun1[1] + ABS(size1) > fun3[1] + 3 ) {
1823Shift1: t2 = term1 + *term1; tt = t2;
1824 *--t2 = sign3 < 0 ? -3: 3; *--t2 = 1; *--t2 = 1;
1825 t1 = fun3 + fun3[1]; for ( i = 0; i < fun3[1]; i++ ) *--t2 = *--t1;
1826 t1 = fun1;
1827 while ( t1 > term1 ) *--t2 = *--t1;
1828 *t2 = tt-t2; term1 = t2;
1829 retval = 1;
1830 }
1831 else { /* Here we have to move term1 to the left to make room. */
1832 jj = fun3[1]-fun1[1]+3-ABS(size1); /* This is positive */
1833Over1: t2 = term1-jj; t1 = term1;
1834 while ( t1 < fun1 ) *t2++ = *t1++;
1835 term1 -= jj;
1836 *term1 += jj;
1837 for ( i = 0; i < fun3[1]; i++ ) *t2++ = fun3[i];
1838 *t2++ = 1; *t2++ = 1; *t2++ = sign3 < 0 ? -3: 3;
1839 retval = 1;
1840 }
1841 }
1842 else if ( AT.SortFloatMode == 1 ) {
1843 if ( fun1[1] + ABS(size1) == fun3[1] + 3 ) goto OnTopOf1;
1844 else if ( fun1[1] + ABS(size1) > fun3[1] + 3 ) goto Shift1;
1845 else {
1846 jj = fun3[1]-fun1[1]+3-ABS(size1); /* This is positive */
1847 goto Over1;
1848 }
1849 }
1850 else { /* Can only be 2, based on previous tests */
1851 if ( fun3[1] + 3 == ABS(size1) ) goto OnTopOf1;
1852 else if ( fun3[1] + 3 < ABS(size1) ) goto Shift1;
1853 else {
1854 jj = fun3[1]+3-ABS(size1); /* This is positive */
1855 goto Over1;
1856 }
1857 }
1858 *interm1 = term1;
1859 TermFree(fun3,"MergeWithFloat");
1860 AT.SortFloatMode = 0;
1861 return(retval);
1862}
1863
1864/*
1865 #] MergeWithFloat :
1866 #] Sorting :
1867 #[ MZV :
1868
1869 The functions here allow the arbitrary precision calculation
1870 of MZV's and Euler sums.
1871 They are called when the functions mzv_ and/or euler_ are used
1872 and the evaluate statement is applied.
1873 The output is in a float_ function.
1874 The expand statement tries to express the functions in terms of a basis.
1875 The bases are the 'standard basis for the euler sums and the
1876 pushdown bases from the datamine, unless otherwise specified.
1877
1878 #[ SimpleDelta :
1879*/
1880
1881void SimpleDelta(mpf_t sum, int m)
1882{
1883 long s = 1;
1884 long prec = AC.DefaultPrecision;
1885 unsigned long xprec = (unsigned long)prec, x;
1886 int j, jmax, n;
1887 mpf_t jm,jjm;
1888 mpf_init(jm); mpf_init(jjm);
1889 if ( m < 0 ) { s = -1; m = -m; }
1890
1891/*
1892 We will loop until 1/2^j/j^m is smaller than the default precision.
1893 Just running to prec is however overkill, specially when m is large.
1894 We try to estimate a better value.
1895 jmax = prec - ((log2(prec)-1)*m).
1896 Hence we need the leading bit of prec.
1897 We are still overshooting a bit.
1898*/
1899 n = 0; x = xprec;
1900 while ( x ) { x >>= 1; n++; }
1901/*
1902 We have now n = floor(log2(x))+1.
1903*/
1904 n--;
1905 jmax = (int)((int)xprec - (n-1)*m);
1906/*
1907 For small prec and large m, the estimate can be wrong and even be negative,
1908 so we increase jmax until jmax + m*log2(jmax) > prec
1909*/
1910 if ( jmax < 0 ) jmax = 1;
1911 do {
1912 n = 0;
1913 x = (unsigned long)jmax;
1914 while (x) { x >>= 1; n++; }
1915 n--; // floor(log2(jmax))
1916 jmax++;
1917 } while ( jmax + m * n <= prec );
1918 mpf_set_ui(sum,0);
1919 for ( j = 1; j <= jmax; j++ ) {
1920#ifdef WITHCUTOFF
1921 xprec--;
1922 mpf_set_prec_raw(jm,xprec);
1923 mpf_set_prec_raw(jjm,xprec);
1924#endif
1925 mpf_set_ui(jm,1L);
1926 mpf_div_ui(jjm,jm,(unsigned long)j);
1927 mpf_pow_ui(jm,jjm,(unsigned long)m);
1928 mpf_div_2exp(jjm,jm,(unsigned long)j);
1929 if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jjm);
1930 else mpf_add(sum,sum,jjm);
1931 }
1932 mpf_clear(jjm); mpf_clear(jm);
1933}
1934
1935/*
1936 #] SimpleDelta :
1937 #[ SimpleDeltaC :
1938*/
1939
1940void SimpleDeltaC(mpf_t sum, int m)
1941{
1942 long s = 1;
1943 long prec = AC.DefaultPrecision;
1944 unsigned long xprec = (unsigned long)prec, x;
1945 int j, jmax, n;
1946 mpf_t jm,jjm;
1947 mpf_init(jm); mpf_init(jjm);
1948 if ( m < 0 ) { s = -1; m = -m; }
1949/*
1950 We will loop until 1/2^j/j^m is smaller than the default precision.
1951 Just running to prec is however overkill, specially when m is large.
1952 We try to estimate a better value.
1953 jmax = prec - ((log2(prec)-1)*m).
1954 Hence we need the leading bit of prec.
1955 We are still overshooting a bit.
1956*/
1957 n = 0; x = xprec;
1958 while ( x ) { x >>= 1; n++; }
1959/*
1960 We have now n = floor(log2(x))+1.
1961*/
1962 n--;
1963 jmax = (int)((int)xprec - (n-1)*m);
1964/*
1965 For small prec and large m, the estimate can be wrong and even be negative,
1966 so we increase jmax until jmax + m*log2(jmax) > prec
1967*/
1968 if ( jmax < 0 ) jmax = 1;
1969 do {
1970 n = 0;
1971 x = (unsigned long)jmax;
1972 while (x) { x >>= 1; n++; }
1973 n--; // floor(log2(jmax))
1974 jmax++;
1975 } while ( jmax + m * n <= prec );
1976 if ( s < 0 ) jmax /= 2;
1977 mpf_set_si(sum,0L);
1978 for ( j = 1; j <= jmax; j++ ) {
1979#ifdef WITHCUTOFF
1980 xprec--;
1981 mpf_set_prec_raw(jm,xprec);
1982 mpf_set_prec_raw(jjm,xprec);
1983#endif
1984 mpf_set_ui(jm,1L);
1985 mpf_div_ui(jjm,jm,(unsigned long)j);
1986 mpf_pow_ui(jm,jjm,(unsigned long)m);
1987 if ( s == -1 ) mpf_div_2exp(jjm,jm,2*(unsigned long)j);
1988 else mpf_div_2exp(jjm,jm,(unsigned long)j);
1989 mpf_add(sum,sum,jjm);
1990 }
1991 mpf_clear(jjm); mpf_clear(jm);
1992}
1993
1994/*
1995 #] SimpleDeltaC :
1996 #[ SingleTable :
1997*/
1998
1999void SingleTable(mpf_t *tabl, int N, int m, int pow)
2000{
2001/*
2002 Creates a table T(1,...,N) with
2003 T(i) = sum_(j,i,N,[sign_(j)]/2^j/j^m)
2004 To make this table we have two options:
2005 1: run the sum backwards with the potential problem that the
2006 precision is difficult to manage.
2007 2: run the sum forwards. Take sum_(j,1,i-1,...) and later subtract.
2008 When doing Euler sums we may need also 1/4^j
2009 pow: 1 -> 1/2^j
2010 2 -> 1/4^j
2011*/
2012 GETIDENTITY
2013 long s = 1;
2014 int j;
2015#ifdef WITHCUTOFF
2016 long prec = mpf_get_default_prec();
2017#endif
2018 mpf_t jm,jjm;
2019 mpf_init(jm); mpf_init(jjm);
2020 if ( pow < 1 || pow > 2 ) {
2021/* INTERNAL_ERROR_EXCL_START */
2022 MLOCK(ErrorMessageLock);
2023 MesPrint("!>Wrong parameter pow in SingleTable: %d\n",pow);
2024 MUNLOCK(ErrorMessageLock);
2025 Terminate(-1);
2026/* INTERNAL_ERROR_EXCL_STOP */
2027 }
2028 if ( m < 0 ) { m = -m; s = -1; }
2029 mpf_set_si(auxsum,0L);
2030 for ( j = N; j > 0; j-- ) {
2031#ifdef WITHCUTOFF
2032 mpf_set_prec_raw(jm,prec-j);
2033 mpf_set_prec_raw(jjm,prec-j);
2034#endif
2035 mpf_set_ui(jm,1L);
2036 mpf_div_ui(jjm,jm,(unsigned long)j);
2037 mpf_pow_ui(jm,jjm,(unsigned long)m);
2038 mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
2039 if ( pow == 2 ) mpf_add(auxsum,auxsum,jjm);
2040 else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jjm);
2041 else mpf_add(auxsum,auxsum,jjm);
2042/*
2043 And now copy auxsum to tablelement j
2044*/
2045 mpf_set(tabl[j],auxsum);
2046 }
2047 mpf_clear(jjm); mpf_clear(jm);
2048}
2049
2050/*
2051 #] SingleTable :
2052 #[ DoubleTable :
2053*/
2054
2055void DoubleTable(mpf_t *tabout, mpf_t *tabin, int N, int m, int pow)
2056{
2057 GETIDENTITY
2058 long s = 1;
2059#ifdef WITHCUTOFF
2060 long prec = mpf_get_default_prec();
2061#endif
2062 int j;
2063 mpf_t jm,jjm;
2064 mpf_init(jm); mpf_init(jjm);
2065 if ( pow < -1 || pow > 2 ) {
2066/* INTERNAL_ERROR_EXCL_START */
2067 MLOCK(ErrorMessageLock);
2068 MesPrint("!>Wrong parameter pow in DoubleTable: %d\n",pow);
2069 MUNLOCK(ErrorMessageLock);
2070 Terminate(-1);
2071/* INTERNAL_ERROR_EXCL_STOP */
2072 }
2073 if ( m < 0 ) { m = -m; s = -1; }
2074 mpf_set_ui(auxsum,0L);
2075 for ( j = N; j > 0; j-- ) {
2076#ifdef WITHCUTOFF
2077 mpf_set_prec_raw(jm,prec-j);
2078 mpf_set_prec_raw(jjm,prec-j);
2079#endif
2080 mpf_set_ui(jm,1L);
2081 mpf_div_ui(jjm,jm,(unsigned long)j);
2082 mpf_pow_ui(jm,jjm,(unsigned long)m);
2083 if ( pow == -1 ) {
2084 mpf_mul_2exp(jjm,jm,(unsigned long)j);
2085 mpf_mul(jm,jjm,tabin[j+1]);
2086 }
2087 else if ( pow > 0 ) {
2088 mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
2089 mpf_mul(jm,jjm,tabin[j+1]);
2090 }
2091 else {
2092 mpf_mul(jm,jm,tabin[j+1]);
2093 }
2094 if ( pow == 2 ) mpf_add(auxsum,auxsum,jm);
2095 else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jm);
2096 else mpf_add(auxsum,auxsum,jm);
2097/*
2098 And now copy auxsum to tablelement j
2099*/
2100 mpf_set(tabout[j],auxsum);
2101 }
2102 mpf_clear(jjm); mpf_clear(jm);
2103}
2104
2105/*
2106 #] DoubleTable :
2107 #[ EndTable :
2108*/
2109
2110void EndTable(mpf_t sum, mpf_t *tabin, int N, int m, int pow)
2111{
2112 long s = 1;
2113#ifdef WITHCUTOFF
2114 long prec = mpf_get_default_prec();
2115#endif
2116 int j;
2117 mpf_t jm,jjm;
2118 mpf_init(jm); mpf_init(jjm);
2119 if ( pow < -1 || pow > 2 ) {
2120/* INTERNAL_ERROR_EXCL_START */
2121 MLOCK(ErrorMessageLock);
2122 MesPrint("!>Wrong parameter pow in EndTable: %d\n",pow);
2123 MUNLOCK(ErrorMessageLock);
2124 Terminate(-1);
2125/* INTERNAL_ERROR_EXCL_STOP */
2126 }
2127 if ( m < 0 ) { m = -m; s = -1; }
2128 mpf_set_si(sum,0L);
2129 for ( j = N; j > 0; j-- ) {
2130#ifdef WITHCUTOFF
2131 mpf_set_prec_raw(jm,prec-j);
2132 mpf_set_prec_raw(jjm,prec-j);
2133#endif
2134 mpf_set_ui(jm,1L);
2135 mpf_div_ui(jjm,jm,(unsigned long)j);
2136 mpf_pow_ui(jm,jjm,(unsigned long)m);
2137 if ( pow == -1 ) {
2138 mpf_mul_2exp(jjm,jm,(unsigned long)j);
2139 mpf_mul(jm,jjm,tabin[j+1]);
2140 }
2141 else if ( pow > 0 ) {
2142 mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
2143 mpf_mul(jm,jjm,tabin[j+1]);
2144 }
2145 else {
2146 mpf_mul(jm,jm,tabin[j+1]);
2147 }
2148 if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jm);
2149 else mpf_add(sum,sum,jm);
2150 }
2151 mpf_clear(jjm); mpf_clear(jm);
2152}
2153
2154/*
2155 #] EndTable :
2156 #[ deltaMZV :
2157*/
2158
2159void deltaMZV(mpf_t result, WORD *indexes, int depth)
2160{
2161 GETIDENTITY
2162/*
2163 Because all sums go roughly like 1/2^j we need about depth steps.
2164*/
2165/* MesPrint("deltaMZV(%a)",depth,indexes); */
2166 if ( depth == 1 ) {
2167 if ( indexes[0] == 1 ) {
2168 mpf_set(result,mpfdelta1);
2169 return;
2170 }
2171 SimpleDelta(result,indexes[0]);
2172 }
2173 else if ( depth == 2 ) {
2174 if ( indexes[0] == 1 && indexes[1] == 1 ) {
2175 mpf_pow_ui(result,mpfdelta1,2);
2176 mpf_div_2exp(result,result,1);
2177 }
2178 else {
2179 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
2180 EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,indexes[1],0);
2181 };
2182 }
2183 else if ( depth > 2 ) {
2184 mpf_t *mpftab3;
2185 int d;
2186/*
2187 Check first whether this is a power of delta1 = ln(2)
2188*/
2189 for ( d = 0; d < depth; d++ ) {
2190 if ( indexes[d] != 1 ) break;
2191 }
2192 if ( d == depth ) { /* divide by fac_(depth) */
2193 mpf_pow_ui(result,mpfdelta1,depth);
2194 for ( d = 2; d <= depth; d++ ) {
2195 mpf_div_ui(result,result,(unsigned long)d);
2196 }
2197 }
2198 else {
2199 d = depth-1;
2200 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
2201 d--; indexes++;
2202 for(;;) {
2203 DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,0);
2204 d--; indexes++;
2205 if ( d == 0 ) {
2206 EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,*indexes,0);
2207 break;
2208 }
2209 mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2210 AT.mpf_tab2 = (void *)mpftab3;
2211 }
2212 }
2213 }
2214 else if ( depth == 0 ) {
2215 mpf_set_ui(result,1L);
2216 }
2217}
2218
2219/*
2220 #] deltaMZV :
2221 #[ deltaEuler :
2222
2223 Regular Euler delta with - signs, but everywhere 1/2^j
2224*/
2225
2226void deltaEuler(mpf_t result, WORD *indexes, int depth)
2227{
2228 GETIDENTITY
2229 int m;
2230#ifdef DEBUG
2231 int i;
2232 printf(" deltaEuler(");
2233 for ( i = 0; i < depth; i++ ) {
2234 if ( i != 0 ) printf(",");
2235 printf("%d",indexes[i]);
2236 }
2237 printf(") = ");
2238#endif
2239 if ( depth == 1 ) {
2240 SimpleDelta(result,indexes[0]);
2241 }
2242 else if ( depth == 2 ) {
2243 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
2244 m = indexes[1]; if ( indexes[0] < 0 ) m = -m;
2245 EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,0);
2246 }
2247 else if ( depth > 2 ) {
2248 int d;
2249 mpf_t *mpftab3;
2250 d = depth-1;
2251 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
2252 d--; indexes++;
2253 m = *indexes; if ( indexes[-1] < 0 ) m = -m;
2254 for(;;) {
2255 DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,0);
2256 d--; indexes++;
2257 m = *indexes; if ( indexes[-1] < 0 ) m = -m;
2258 if ( d == 0 ) {
2259 EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,0);
2260 break;
2261 }
2262 mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2263 AT.mpf_tab2 = (void *)mpftab3;
2264 }
2265 }
2266 else if ( depth == 0 ) {
2267 mpf_set_ui(result,1L);
2268 }
2269#ifdef DEBUG
2270 gmp_printf("%.*Fe\n",40,result);
2271#endif
2272}
2273
2274/*
2275 #] deltaEuler :
2276 #[ deltaEulerC :
2277
2278 Conjugate Euler delta without - signs, but possibly 1/4^j
2279 When there is a - in the string we have 1/4.
2280*/
2281
2282void deltaEulerC(mpf_t result, WORD *indexes, int depth)
2283{
2284 GETIDENTITY
2285 int m;
2286#ifdef DEBUG
2287 int i;
2288 printf(" deltaEulerC(");
2289 for ( i = 0; i < depth; i++ ) {
2290 if ( i != 0 ) printf(",");
2291 printf("%d",indexes[i]);
2292 }
2293 printf(") = ");
2294#endif
2295 mpf_set_ui(result,0);
2296 if ( depth == 1 ) {
2297 if ( indexes[0] == 0 ) {
2298 MLOCK(ErrorMessageLock);
2299 MesPrint("Illegal index in depth=1 deltaEulerC: %d\n",indexes[0]);
2300 MUNLOCK(ErrorMessageLock);
2301 Terminate(-1);
2302 }
2303 if ( indexes[0] < 0 ) SimpleDeltaC(result,indexes[0]);
2304 else SimpleDelta(result,indexes[0]);
2305 }
2306 else if ( depth == 2 ) {
2307 int par;
2308 m = indexes[0];
2309 if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth,-m,2);
2310 else SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth, m,1);
2311 m = indexes[1];
2312 if ( m < 0 ) { m = -m; par = indexes[0] < 0 ? 0: 1; }
2313 else { par = indexes[0] < 0 ? -1: 0; }
2314 EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,par);
2315 }
2316 else if ( depth > 2 ) {
2317 int d, par;
2318 mpf_t *mpftab3;
2319 d = depth-1;
2320 m = indexes[0];
2321 ZeroTable(mpftab1,AC.DefaultPrecision+1);
2322 if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1,-m,2);
2323 else SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1, m,1);
2324 d--; indexes++; m = indexes[0];
2325 if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
2326 else { par = indexes[-1] < 0 ? -1: 0; }
2327 for(;;) {
2328 ZeroTable(mpftab2,AC.DefaultPrecision-AC.MaxWeight+d);
2329 DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,par);
2330 d--; indexes++; m = indexes[0];
2331 if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
2332 else { par = indexes[-1] < 0 ? -1: 0; }
2333 if ( d == 0 ) {
2334 mpf_set_ui(result,0);
2335 EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,par);
2336 break;
2337 }
2338 mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2339 AT.mpf_tab2 = (void *)mpftab3;
2340 }
2341 }
2342 else if ( depth == 0 ) {
2343 mpf_set_ui(result,1L);
2344 }
2345#ifdef DEBUG
2346 gmp_printf("%.*Fe\n",40,result);
2347#endif
2348}
2349
2350/*
2351 #] deltaEulerC :
2352 #[ CalculateMZVhalf :
2353
2354 This routine is mainly for support when large numbers of
2355 MZV's have to be calculated at the same time.
2356*/
2357
2358void CalculateMZVhalf(mpf_t result, WORD *indexes, int depth)
2359{
2360 int i;
2361 if ( depth < 0 ) {
2362 MLOCK(ErrorMessageLock);
2363 MesPrint("Illegal depth in CalculateMZVhalf: %d",depth);
2364 MUNLOCK(ErrorMessageLock);
2365 Terminate(-1);
2366 }
2367 for ( i = 0; i < depth; i++ ) {
2368 if ( indexes[i] <= 0 ) {
2369 MLOCK(ErrorMessageLock);
2370 MesPrint("Illegal index[%d] in CalculateMZVhalf: %d",i,indexes[i]);
2371 MUNLOCK(ErrorMessageLock);
2372 Terminate(-1);
2373 }
2374 }
2375 deltaMZV(result,indexes,depth);
2376}
2377
2378/*
2379 #] CalculateMZVhalf :
2380 #[ CalculateMZV :
2381*/
2382
2383void CalculateMZV(mpf_t result, WORD *indexes, int depth)
2384{
2385 GETIDENTITY
2386 int num1, num2 = 0, i, j = 0;
2387 if ( depth < 0 ) {
2388 MLOCK(ErrorMessageLock);
2389 MesPrint("Illegal depth in CalculateMZV: %d",depth);
2390 MUNLOCK(ErrorMessageLock);
2391 Terminate(-1);
2392 }
2393 if ( indexes[0] == 1 ) {
2394 MLOCK(ErrorMessageLock);
2395 MesPrint("Divergent MZV in CalculateMZV");
2396 MUNLOCK(ErrorMessageLock);
2397 Terminate(-1);
2398 }
2399/* MesPrint("calculateMZV(%a)",depth,indexes); */
2400 for ( i = 0; i < depth; i++ ) {
2401 if ( indexes[i] <= 0 ) {
2402 MLOCK(ErrorMessageLock);
2403 MesPrint("Illegal index[%d] in CalculateMZV: %d",i,indexes[i]);
2404 MUNLOCK(ErrorMessageLock);
2405 Terminate(-1);
2406 }
2407 AT.indi1[i] = indexes[i];
2408 }
2409 num1 = depth; i = 0;
2410 deltaMZV(result,indexes,depth);
2411 for(;;) {
2412 if ( AT.indi1[0] > 1 ) {
2413 AT.indi1[0] -= 1;
2414 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2415 AT.indi2[0] = 1; num2++;
2416 }
2417 else {
2418 AT.indi2[0] += 1;
2419 for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
2420 num1--;
2421 if ( num1 == 0 ) break;
2422 }
2423 deltaMZV(aux1,AT.indi1,num1);
2424 deltaMZV(aux2,AT.indi2,num2);
2425 mpf_mul(aux3,aux1,aux2);
2426 mpf_add(result,result,aux3);
2427 }
2428 deltaMZV(aux3,AT.indi2,num2);
2429 mpf_add(result,result,aux3);
2430}
2431
2432/*
2433 #] CalculateMZV :
2434 #[ CalculateEuler :
2435
2436 There is a problem of notation here.
2437 Basically there are two notations.
2438 1: Z(m1,m2,m3) = sum_(j3,1,inf,sign_(m3)/j3^abs_(m3)*
2439 sum_(j2,j3+1,inf,sign_(m2)/j2^abs_(m2)*
2440 sum_(j1,j2+1,inf,sign_(m1)/j1^abs_(m1))))
2441 See Broadhurst,1996
2442 2: L(m1,m2,m3) = sum_(j1,1,inf,sign_(m1)*
2443 sum_(j2,1,inf,sign_(m2)*
2444 sum_(j3,1,inf,sign_(m3)
2445 /j3^abs_(m3)
2446 /(j2+j3)^abs_(m2)
2447 /(j1+j2+j3)^abs_(m1) )))
2448 See Borwein, Bradley, Broadhurst and Lisonek, 1999
2449 The L corresponds with the H of the datamine up to sign_(m1*m2*m3)
2450 The algorithm follows 2, but the more common notation is 1.
2451 Hence we start with a conversion.
2452*/
2453
2454void CalculateEuler(mpf_t result, WORD *Zindexes, int depth)
2455{
2456 GETIDENTITY
2457 int s1, num1, num2, i, j;
2458
2459 WORD *indexes = AT.WorkPointer;
2460 for ( i = 0; i < depth; i++ ) indexes[i] = Zindexes[i];
2461 for ( i = 0; i < depth-1; i++ ) {
2462 if ( Zindexes[i] < 0 ) {
2463 for ( j = i+1; j < depth; j++ ) indexes[j] = -indexes[j];
2464 }
2465 }
2466
2467 if ( depth < 0 ) {
2468 MLOCK(ErrorMessageLock);
2469 MesPrint("Illegal depth in CalculateEuler: %d\n",depth);
2470 MUNLOCK(ErrorMessageLock);
2471 Terminate(-1);
2472 }
2473 if ( indexes[0] == 1 ) {
2474 MLOCK(ErrorMessageLock);
2475 MesPrint("Divergent Euler sum in CalculateEuler\n");
2476 MUNLOCK(ErrorMessageLock);
2477 Terminate(-1);
2478 }
2479 for ( i = 0, j = 0; i < depth; i++ ) {
2480 if ( indexes[i] == 0 ) {
2481 MLOCK(ErrorMessageLock);
2482 MesPrint("Illegal index[%d] in CalculateEuler: %d\n",i,indexes[i]);
2483 MUNLOCK(ErrorMessageLock);
2484 Terminate(-1);
2485 }
2486 if ( indexes[i] < 0 ) j = 1;
2487 AT.indi1[i] = indexes[i];
2488 }
2489 if ( j == 0 ) {
2490 CalculateMZV(result,indexes,depth);
2491 return;
2492 }
2493 num1 = depth; AT.indi2[0] = 0; num2 = 0;
2494 deltaEuler(result,AT.indi1,depth);
2495 s1 = 0;
2496 for(;;) {
2497 s1++;
2498 if ( AT.indi1[0] > 1 ) {
2499 AT.indi1[0] -= 1;
2500 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2501 AT.indi2[0] = 1; num2++;
2502 }
2503 else if ( AT.indi1[0] < -1 ) {
2504 AT.indi1[0] += 1;
2505 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2506 AT.indi2[0] = 1; num2++;
2507 }
2508 else if ( AT.indi1[0] == -1 ) {
2509 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2510 AT.indi2[0] = -1; num2++;
2511 for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
2512 num1--;
2513 }
2514 else {
2515 AT.indi2[0] = AT.indi2[0] < 0 ? AT.indi2[0]-1: AT.indi2[0]+1;
2516 for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
2517 num1--;
2518 }
2519 if ( num1 == 0 ) break;
2520 deltaEuler(aux1,AT.indi1,num1);
2521 deltaEulerC(aux2,AT.indi2,num2);
2522 mpf_mul(aux3,aux1,aux2);
2523 if ( (depth+num1+num2+s1)%2 == 0 ) mpf_add(result,result,aux3);
2524 else mpf_sub(result,result,aux3);
2525 }
2526 deltaEulerC(aux3,AT.indi2,num2);
2527 if ( (depth+num2+s1)%2 == 0 ) mpf_add(result,result,aux3);
2528 else mpf_sub(result,result,aux3);
2529}
2530
2531/*
2532 #] CalculateEuler :
2533 #[ ExpandMZV :
2534*/
2535/* UNFINISHED_FEATURE_EXCL_START */
2536int ExpandMZV(WORD *term, WORD level)
2537{
2538 DUMMYUSE(term);
2539 DUMMYUSE(level);
2540 return(0);
2541}
2542/* UNFINISHED_FEATURE_EXCL_STOP */
2543/*
2544 #] ExpandMZV :
2545 #[ ExpandEuler :
2546*/
2547/* UNFINISHED_FEATURE_EXCL_START */
2548int ExpandEuler(WORD *term, WORD level)
2549{
2550 DUMMYUSE(term);
2551 DUMMYUSE(level);
2552 return(0);
2553}
2554/* UNFINISHED_FEATURE_EXCL_STOP */
2555/*
2556 #] ExpandEuler :
2557 #[ EvaluateEuler :
2558
2559 There are various steps here:
2560 1: locate an Euler function.
2561 2: evaluate it into a float.
2562 3: convert the coefficient to a float and multiply.
2563 4: Put the new term together.
2564 5: Restart to see whether there are more Euler functions.
2565 The compiler should check that there is no conflict between
2566 the evaluate command and a potential polyfun or polyratfun.
2567 Yet, when reading in expressions there can be a conflict.
2568 Hence the Normalize routine should check as well.
2569
2570 par == MZV: MZV
2571 par == EULER: Euler
2572 par == MZVHALF: MZV sums in 1/2 rather than 1. -> deltaMZV.
2573 par == ALLMZVFUNCTIONS: all of the above.
2574*/
2575
2576int EvaluateEuler(PHEAD WORD *term, WORD level, WORD par)
2577{
2578 WORD *t, *tstop, *tt, *tnext, sumweight, depth, first = 1, *newterm, i;
2579 WORD *oldworkpointer = AT.WorkPointer, nsize, *indexes;
2580 int retval;
2581 tstop = term + *term; tstop -= ABS(tstop[-1]);
2582 if ( AT.WorkPointer < term+*term ) AT.WorkPointer = term + *term;
2583/*
2584 Step 1. We also need to verify that the argument we find is legal
2585*/
2586 t = term+1;
2587 while ( t < tstop ) {
2588 if ( ( *t == par ) || ( ( par == ALLMZVFUNCTIONS ) && (
2589 *t == MZV || *t == EULER || *t == MZVHALF ) ) ) {
2590 /* all arguments should be small integers */
2591 indexes = AT.WorkPointer;
2592 sumweight = 0; depth = 0;
2593 tnext = t + t[1]; tt = t + FUNHEAD;
2594 while ( tt < tnext ) {
2595 if ( *tt != -SNUMBER ) goto nextfun;
2596 if ( tt[1] == 0 ) goto nextfun;
2597 indexes[depth] = tt[1];
2598 sumweight += ABS(tt[1]); depth++;
2599 tt += 2;
2600 }
2601 /* euler sum without arguments, i.e. mzv_(), euler_() or mzvhalf_() */
2602 if ( depth == 0) goto nextfun;
2603 if ( sumweight > AC.MaxWeight ) {
2604 MLOCK(ErrorMessageLock);
2605 MesPrint("Error: Weight of Euler/MZV sum greater than %d.",AC.MaxWeight);
2606 MesPrint("Please increase the maximum weight in %#startfloat.");
2607 MUNLOCK(ErrorMessageLock);
2608 Terminate(-1);
2609 }
2610/*
2611 Step 2: evaluate:
2612*/
2613 AT.WorkPointer += depth;
2614 if ( first ) {
2615 if ( *t == MZV ) CalculateMZV(aux4,indexes,depth);
2616 else if ( *t == EULER ) CalculateEuler(aux4,indexes,depth);
2617 else if ( *t == MZVHALF ) CalculateMZVhalf(aux4,indexes,depth);
2618 first = 0;
2619 }
2620 else {
2621 if ( *t == MZV ) CalculateMZV(aux5,indexes,depth);
2622 else if ( *t == EULER ) CalculateEuler(aux5,indexes,depth);
2623 else if ( *t == MZVHALF ) CalculateMZVhalf(aux5,indexes,depth);
2624 mpf_mul(aux4,aux4,aux5);
2625 }
2626 *t = 0;
2627 }
2628nextfun:
2629 t += t[1];
2630 }
2631 if ( first == 1 ) return(Generator(BHEAD term,level));
2632/*
2633 Step 3:
2634 Now the regular coefficient, if it is not 1/1.
2635 We have two cases: size +- 3, or bigger.
2636*/
2637 nsize = term[*term-1];
2638 if ( nsize < 0 ) {
2639 mpf_neg(aux4,aux4);
2640 nsize = -nsize;
2641 }
2642 if ( nsize == 3 ) {
2643 if ( tstop[0] != 1 ) {
2644 mpf_mul_ui(aux4,aux4,(ULONG)((UWORD)tstop[0]));
2645 }
2646 if ( tstop[1] != 1 ) {
2647 mpf_div_ui(aux4,aux4,(ULONG)((UWORD)tstop[1]));
2648 }
2649 }
2650 else {
2651 RatToFloat(aux5,(UWORD *)tstop,nsize);
2652 mpf_mul(aux4,aux4,aux5);
2653 }
2654/*
2655 Now we have to locate possible other float_ functions.
2656*/
2657 t = term+1;
2658 while ( t < tstop ) {
2659 if ( *t == FLOATFUN ) {
2660 UnpackFloat(aux5,t);
2661 mpf_mul(aux4,aux4,aux5);
2662 }
2663 t += t[1];
2664 }
2665/*
2666 Now we should compose the new term in the WorkSpace.
2667*/
2668 t = term+1;
2669 newterm = AT.WorkPointer;
2670 tt = newterm+1;
2671 while ( t < tstop ) {
2672 if ( *t == 0 || *t == FLOATFUN ) t += t[1];
2673 else {
2674 i = t[1]; NCOPY(tt,t,i);
2675 }
2676 }
2677 PackFloat(tt,aux4);
2678 tt += tt[1];
2679 *tt++ = 1; *tt++ = 1; *tt++ = 3;
2680 *newterm = tt-newterm;
2681 AT.WorkPointer = tt;
2682 retval = Generator(BHEAD newterm,level);
2683 AT.WorkPointer = oldworkpointer;
2684 return(retval);
2685}
2686
2687/*
2688 #] EvaluateEuler :
2689 #] MZV :
2690 #[ Functions :
2691 #[ CoEvaluate :
2692
2693 Current subkeys: mzv_, euler_ and sqrt_.
2694*/
2695
2696int CoEvaluate(UBYTE *s)
2697{
2698 GETIDENTITY
2699 UBYTE *subkey, c;
2700 WORD numfun, type;
2701 int error = 0;
2702 if ( AT.aux_ == 0 ) {
2703 MesPrint("&Illegal attempt to evaluate a function without activating floating point numbers.");
2704 MesPrint("&Forgotten %#startfloat instruction?");
2705 return(1);
2706 }
2707 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
2708 if ( *s == 0 ) {
2709/*
2710 No subkey, which means all functions.
2711*/
2712 Add3Com(TYPEEVALUATE,ALLFUNCTIONS);
2713/*
2714 The MZV, EULER and MZVHALF are done separately
2715*/
2716 Add3Com(TYPEEVALUATE,ALLMZVFUNCTIONS);
2717 return(0);
2718 }
2719 while ( *s ) {
2720 subkey = s;
2721 while ( FG.cTable[*s] == 0 ) s++;
2722 if ( *s == '2' ) s++; /* cases li2_ and atan2_ */
2723 if ( *s == '_' ) s++;
2724 c = *s; *s = 0;
2725/*
2726 We still need provisions for pi_ and possibly other constants.
2727*/
2728 if ( ( ( type = GetName(AC.varnames,subkey,&numfun,NOAUTO) ) != CFUNCTION )
2729 || ( functions[numfun].spec != 0 ) ) {
2730
2731 if ( type == CSYMBOL ) {
2732 Add4Com(TYPEEVALUATE,SYMBOL,numfun);
2733 break;
2734 }
2735/*
2736 This cannot work.
2737*/
2738 MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
2739 return(1);
2740 }
2741 else {
2742 switch ( numfun+FUNCTION ) {
2743 case MZV:
2744 case EULER:
2745 case MZVHALF:
2746/*
2747 The following functions are treated in evaluate.c
2748*/
2749 case SQRTFUNCTION:
2750 case LNFUNCTION:
2751 case EXPFUNCTION:
2752 case SINFUNCTION:
2753 case COSFUNCTION:
2754 case TANFUNCTION:
2755 case ASINFUNCTION:
2756 case ACOSFUNCTION:
2757 case ATANFUNCTION:
2758 case ATAN2FUNCTION:
2759 case SINHFUNCTION:
2760 case COSHFUNCTION:
2761 case TANHFUNCTION:
2762 case ASINHFUNCTION:
2763 case ACOSHFUNCTION:
2764 case ATANHFUNCTION:
2765 case LI2FUNCTION:
2766 case LINFUNCTION:
2767 case AGMFUNCTION:
2768 case GAMMAFUN:
2769/*
2770 At a later stage we can add more functions from mpfr here
2771 mpfr_(number,arg(s))
2772*/
2773 Add3Com(TYPEEVALUATE,numfun+FUNCTION);
2774 break;
2775 default:
2776 MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
2777 error = 1;
2778 break;
2779 }
2780 }
2781 *s = c;
2782 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
2783 }
2784 return(error);
2785}
2786
2787/*
2788 #] CoEvaluate :
2789 #] Functions :
2790*/
int AddNtoL(int n, WORD *array)
Definition comtool.c:284
void GarbHand(void)
Definition sort.c:3405
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3272
WORD ** lhs
Definition structs.h:974