FORM v5.0.0-35-g6318119
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
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
196/*
197 #] Form_mpf_init :
198 #[ Form_mpf_clear :
199*/
200
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
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
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
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
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
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
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
1006/*
1007 #] AddFloats :
1008 #[ MulFloats :
1009*/
1010
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
1022/*
1023 #] MulFloats :
1024 #[ DivFloats :
1025*/
1026
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
1038/*
1039 #] DivFloats :
1040 #[ AddRatToFloat :
1041
1042 Note: this can be optimized, because often the rat is rather simple.
1043*/
1044
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
1057/*
1058 #] AddRatToFloat :
1059 #[ MulRatToFloat :
1060
1061 Note: this can be optimized, because often the rat is rather simple.
1062*/
1063
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
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 id, totnum;
1149 mpf_t *a;
1150#ifdef WITHSORTBOTS
1151 totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
1152#endif
1153 for ( id = 0; id < totnum; id++ ) {
1154/*
1155 We work here with a[0] etc because the aux1 etc contain B which
1156 in the current routine would be AB[0] only
1157*/
1158 AB[id]->T.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AB[id]->T.aux_");
1159 a = (mpf_t *)AB[id]->T.aux_;
1160 mpf_inits(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
1161 if ( AB[id]->T.indi1 ) M_free(AB[id]->T.indi1,"indi1");
1162 AB[id]->T.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
1163 AB[id]->T.indi2 = AB[id]->T.indi1 + AC.MaxWeight;
1164 }
1165#else
1166 AT.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AT.aux_");
1167 mpf_inits(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
1168 if ( AT.indi1 ) M_free(AT.indi1,"indi1");
1169 AT.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
1170 AT.indi2 = AT.indi1 + AC.MaxWeight;
1171#endif
1172}
1173
1174/*
1175 #] SetupMPFTables :
1176 #[ ClearMZVTables :
1177*/
1178
1179void ClearMZVTables(void)
1180{
1181#ifdef WITHPTHREADS
1182 int i, id, totnum;
1183 mpf_t *a;
1184 totnum = AM.totalnumberofthreads;
1185 for ( id = 0; id < totnum; id++ ) {
1186 if ( AB[id]->T.mpf_tab1 ) {
1187/*
1188 We work here with a[0] etc because the aux1, mpftab1 etc contain B
1189 which in the current routine would be AB[0] only
1190*/
1191 a = (mpf_t *)AB[id]->T.mpf_tab1;
1192 for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
1193 mpf_clear(a[i]);
1194 }
1195 M_free(AB[id]->T.mpf_tab1,"mpftab1");
1196 AB[id]->T.mpf_tab1 = 0;
1197 }
1198 if ( AB[id]->T.mpf_tab2 ) {
1199 a = (mpf_t *)AB[id]->T.mpf_tab2;
1200 for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
1201 mpf_clear(a[i]);
1202 }
1203 M_free(AB[id]->T.mpf_tab2,"mpftab2");
1204 AB[id]->T.mpf_tab2 = 0;
1205 }
1206 }
1207#ifdef WITHSORTBOTS
1208 totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
1209#endif
1210 for ( id = 0; id < totnum; id++ ) {
1211 if ( AB[id]->T.aux_ ) {
1212 a = (mpf_t *)AB[id]->T.aux_;
1213 mpf_clears(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
1214 M_free(AB[id]->T.aux_,"AB[id]->T.aux_");
1215 AB[id]->T.aux_ = 0;
1216 }
1217 if ( AB[id]->T.indi1 ) { M_free(AB[id]->T.indi1,"indi1"); AB[id]->T.indi1 = 0; }
1218 }
1219#else
1220 int i;
1221 if ( AT.mpf_tab1 ) {
1222 for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
1223 mpf_clear(mpftab1[i]);
1224 }
1225 M_free(AT.mpf_tab1,"mpftab1");
1226 AT.mpf_tab1 = 0;
1227 }
1228 if ( AT.mpf_tab2 ) {
1229 for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
1230 mpf_clear(mpftab2[i]);
1231 }
1232 M_free(AT.mpf_tab2,"mpftab2");
1233 AT.mpf_tab2 = 0;
1234 }
1235 if ( AT.aux_ ) {
1236 mpf_clears(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
1237 M_free(AT.aux_,"AT.aux_");
1238 AT.aux_ = 0;
1239 }
1240 if ( AT.indi1 ) { M_free(AT.indi1,"indi1"); AT.indi1 = 0; }
1241#endif
1242 if ( AO.floatspace ) { M_free(AO.floatspace,"floatspace"); AO.floatspace = 0;
1243 AO.floatsize = 0; }
1244 if ( AS.delta_1 ) {
1245 mpf_clear(mpfdelta1);
1246 M_free(AS.delta_1,"delta1");
1247 AS.delta_1 = 0;
1248 }
1249}
1250
1251/*
1252 #] ClearMZVTables :
1253 #[ CoToFloat :
1254*/
1255
1256int CoToFloat(UBYTE *s)
1257{
1258 GETIDENTITY
1259 if ( AT.aux_ == 0 ) {
1260 MesPrint("&Illegal attempt to convert to float_ without activating floating point numbers.");
1261 MesPrint("&Forgotten %#startfloat instruction?");
1262 return(1);
1263 }
1264 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1265 if ( *s ) {
1266 MesPrint("&Illegal argument(s) in ToFloat statement: '%s'",s);
1267 return(1);
1268 }
1269 Add2Com(TYPETOFLOAT);
1270 return(0);
1271}
1272
1273/*
1274 #] CoToFloat :
1275 #[ CoToRat :
1276*/
1277
1278int CoToRat(UBYTE *s)
1279{
1280 GETIDENTITY
1281 if ( AT.aux_ == 0 ) {
1282 MesPrint("&Illegal attempt to convert from float_ without activating floating point numbers.");
1283 MesPrint("&Forgotten %#startfloat instruction?");
1284 return(1);
1285 }
1286 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1287 if ( *s ) {
1288 MesPrint("&Illegal argument(s) in ToRat statement: '%s'",s);
1289 return(1);
1290 }
1291 Add2Com(TYPETORAT);
1292 return(0);
1293}
1294
1295/*
1296 #] CoToRat :
1297 #[ CoStrictRounding :
1298
1299 Syntax: StrictRounding [precision][base]
1300 - precision: number of digits to round to (optional)
1301 - base: 'd' for decimal (base 10) or 'b' for binary (base 2)
1302
1303 If no arguments are provided, uses default precision with binary base.
1304*/
1305int CoStrictRounding(UBYTE *s)
1306{
1307 GETIDENTITY
1308 WORD x;
1309 int base;
1310 if ( AT.aux_ == 0 ) {
1311 MesPrint("&Illegal attempt for strict rounding without activating floating point numbers.");
1312 MesPrint("&Forgotten %#startfloat instruction?");
1313 return(1);
1314 }
1315 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1316 if ( *s == 0 ) {
1317 /* No subkey, which means round to default precision */
1318 x = AC.DefaultPrecision - AC.MaxWeight - 1;
1319 base = 2;
1320 }
1321 else if ( FG.cTable[*s] == 1 ) { /* number */
1322 ParseNumber(x,s)
1323 if ( tolower(*s) == 'd' ) { base = 10; s++; } /* decimal base */
1324 else if ( tolower(*s) == 'b' ){ base = 2; s++; } /* binary base */
1325 else goto IllPar; /* invalid base specification */
1326 }
1327 else {
1328 goto IllPar;
1329 }
1330 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1331
1332 /* Check for invalid arguments */
1333 if ( *s ) {
1334IllPar:
1335 MesPrint("&Illegal argument(s) in StrictRounding statement: '%s'",s);
1336 return(1);
1337 }
1338 Add4Com(TYPESTRICTROUNDING,x,base);
1339 return(0);
1340}
1341/*
1342 #] CoStrictRounding :
1343 #[ CoChop :
1344
1345 LHS notation of the chop statement:
1346 TYPECHOP, length, FLOATFUN, ...
1347 where FLOATFUN, ... represents the threshold of the chop statement in
1348 the notation of a float_ function with its arguments.
1349
1350*/
1351
1352int CoChop(UBYTE *s)
1353{
1354 GETIDENTITY
1355 UBYTE *ss, c;
1356 WORD *w, *OldWork;
1357 int spec, pow = 1;
1358 unsigned long x;
1359 if ( AT.aux_ == 0 ) {
1360 MesPrint("&Illegal attempt to chop a float_ without activating floating point numbers.");
1361 MesPrint("&Forgotten %#startfloat instruction?");
1362 return(1);
1363 }
1364 if ( *s == 0 ) {
1365 MesPrint("&Chop needs a number (float, rational or power) as an argument.");
1366 return(1);
1367 }
1368 /* Create TYPECHOP header */
1369 w = OldWork = AT.WorkPointer;
1370 *w++ = TYPECHOP;
1371 w++;
1372
1373 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
1374
1375 /*
1376 The argument of chop can be
1377 1: a floating-point number
1378 2: an integer, rational number or power
1379 */
1380 if ( FG.cTable[*s] == 1 || *s == '.' ) {
1381 /* 1: Attempt to parse as floating-point number */
1382 ss = CheckFloat(s, &spec);
1383 if ( ss > s ) {
1384 /* CheckFloat found a valid float */
1385 AT.WorkPointer = w;
1386 /*
1387 Reads the floating point number and outputs it at AT.WorkPointer as if it were a float_
1388 function with its arguments.
1389 */
1390 ReadFloat((SBYTE *)s);
1391 s = ss;
1392 w += w[1];
1393 }
1394 else {
1395 /* 2: CheckFloat didn't find a float, we now try for rationals and powers */
1396 /* Parse the integer part (numerator for rationals) */
1397 if ( FG.cTable[*s] == 1 ) {
1398 ParseNumber(x,s)
1399 mpf_set_ui(aux1,x);
1400 }
1401 while ( *s == ' ' || *s == '\t' ) s++;
1402 /* Check for rational number or power*/
1403 if ( *s == '/' || *s == '^' ) {
1404 c = *s; s++;
1405 while ( *s == ' ' || *s == '\t' ) s++;
1406 if ( *s == '-' ) { s++; pow = -1; } /* negative power */
1407 /* Parse the denominator or power */
1408 if ( FG.cTable[*s] == 1 ) {
1409 ParseNumber(x,s)
1410 if ( c == '/' ) { /* rational */
1411 if ( x == 0 ) {
1412 MesPrint("&Division by zero in chop statement.");
1413 return(1);
1414 }
1415 /* Perform the division */
1416 mpf_div_ui(aux1, aux1,x);
1417 }
1418 else { /* Power */
1419 mpf_pow_ui(aux1,aux1,x);
1420 if ( pow == -1 ) {
1421 mpf_ui_div(aux1,(unsigned long) 1, aux1);
1422 }
1423 }
1424 }
1425 }
1426 /* Put aux1 in the notation of a float_ function */
1427 PackFloat(w, aux1);
1428 w += w[1];
1429 }
1430 }
1431 if ( *s ) {
1432 MesPrint("&Illegal argument(s) in Chop statement: '%s'.",s);
1433 return(1);
1434 }
1435 AT.WorkPointer = OldWork;
1436 AT.WorkPointer[1] = w - AT.WorkPointer; /* Set total length */
1437 AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
1438 return(0);
1439}
1440
1441/*
1442 #] CoChop :
1443 #[ ToFloat :
1444
1445 Converts the coefficient to floating point if it is still a rat.
1446*/
1447
1448int ToFloat(PHEAD WORD *term, WORD level)
1449{
1450 WORD *t, *tstop, nsize, nsign = 3;
1451 t = term+*term;
1452 nsize = ABS(t[-1]);
1453 tstop = t - nsize;
1454 if ( t[-1] < 0 ) { nsign = -nsign; }
1455 if ( nsize == 3 && t[-2] == 1 && t[-3] == 1 ) { /* Could be float */
1456 t = term + 1;
1457 while ( t < tstop ) {
1458 if ( ( *t == FLOATFUN ) && ( t+t[1] == tstop ) ) {
1459 return(Generator(BHEAD term,level));
1460 }
1461 t += t[1];
1462 }
1463 }
1464 RatToFloat(aux4,(UWORD *)tstop,nsize);
1465 PackFloat(tstop,aux4);
1466 tstop += tstop[1];
1467 *tstop++ = 1; *tstop++ = 1; *tstop++ = nsign;
1468 *term = tstop - term;
1469 AT.WorkPointer = tstop;
1470 return(Generator(BHEAD term,level));
1471}
1472
1473/*
1474 #] ToFloat :
1475 #[ ToRat :
1476
1477 Tries to convert the coefficient to rational if it is still a float.
1478*/
1479
1480int ToRat(PHEAD WORD *term, WORD level)
1481{
1482 WORD *tstop, *t, nsize, nsign, ncoef;
1483/*
1484 1: find the float which should be at the end.
1485*/
1486 tstop = term + *term; nsize = ABS(tstop[-1]);
1487 nsign = tstop[-1] < 0 ? -1: 1; tstop -= nsize;
1488 t = term+1;
1489 while ( t < tstop ) {
1490 if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1491 nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
1492 t += t[1];
1493 }
1494 if ( t < tstop ) {
1495/*
1496 Now t points at the float_ function and everything is correct.
1497 The result can go straight over the float_ function.
1498*/
1499 UnpackFloat(aux4,t);
1500 // If aux4 is zero, the term vanishes
1501 if ( mpf_sgn(aux4) == 0 ) return(0);
1502 if ( FloatToRat((UWORD *)t,&ncoef,aux4) == 0 ) {
1503 // Check if the resulting rational is zero
1504 if ( t[0] == 0 && t[1] == 1 && ncoef == 3 ) return(0);
1505 t += ABS(ncoef);
1506 t[-1] = ncoef*nsign;
1507 *term = t - term;
1508 }
1509 }
1510 return(Generator(BHEAD term,level));
1511}
1512
1513/*
1514 #] ToRat :
1515 #[ StrictRounding :
1516
1517 Rounds floating point numbers to a specified precision
1518 in a given base (decimal or binary).
1519*/
1520int StrictRounding(PHEAD WORD *term, WORD level, WORD prec, WORD base) {
1521 WORD *t,*tstop;
1522 int sign,size,maxprec = AC.DefaultPrecision-AC.MaxWeight-1;
1523 /* maxprec is in bits */
1524 if ( base == 2 && prec > maxprec ) {
1525 prec = maxprec;
1526 }
1527 if ( base == 10 && prec > (int)(maxprec*log10(2.0)) ) {
1528 prec = maxprec*log10(2.0);
1529 }
1530 /* Find the float which should be at the end. */
1531 tstop = term + *term; size = ABS(tstop[-1]);
1532 sign = tstop[-1] < 0 ? -1: 1; tstop -= size;
1533 t = term+1;
1534 while ( t < tstop ) {
1535 if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1536 size == 3 && tstop[0] == 1 && tstop[1] == 1) {
1537 break;
1538 }
1539 t += t[1];
1540 }
1541 if ( t < tstop ) {
1542/*
1543 Now t points at the float_ function and everything is correct.
1544 The result can go straight over the float_ function.
1545*/
1546 char *s;
1547 mp_exp_t exp;
1548 /* Extract the floating point value */
1549 UnpackFloat(aux4,t);
1550 /* Convert to string:
1551 - Format as MeN with M the mantissa and N the exponent
1552 - the generated string by mpf_get_str is the fraction/mantissa with
1553 an implicit radix point immediately to the left of the first digit.
1554 The applicable exponent is written in exp. */
1555 s = (char *)AO.floatspace;
1556 *s++ = '.';
1557 mpf_get_str(s,&exp, base, prec, aux4);
1558 while ( *s != 0 ) s++;
1559 *s++ = 'e';
1560 snprintf(s,AO.floatsize-(s-(char *)AO.floatspace),"%ld",exp);
1561 /* Negative base values are used to specify that the exponent is in decimal */
1562 mpf_set_str(aux4,(char *)AO.floatspace,-base);
1563 /* Pack the rounded floating point value back into the term */
1564 PackFloat(t,aux4);
1565 t+=t[1];
1566 *t++ = 1; *t++ = 1; *t++ = 3*sign;
1567 *term = t - term;
1568 }
1569 return(Generator(BHEAD term,level));
1570}
1571/*
1572 #] StrictRounding :
1573 #[ Chop :
1574
1575 Removes terms with a floating point number smaller than a given threshold.
1576
1577 Search for a FLOATFUN and compares its absolute value against the threshold
1578 specified in the chop statement. This threshold can be obtained from the
1579 LHS of the chop statement in the compiler buffer.
1580
1581 */
1582int Chop(PHEAD WORD *term, WORD level)
1583{
1584 WORD *tstop, *t, nsize, *threshold;
1585 CBUF *C = cbuf+AM.rbufnum;
1586 /* Find the float which should be at the end. */
1587 tstop = term + *term;
1588 nsize = ABS(tstop[-1]); tstop -= nsize;
1589 t = term+1;
1590 while ( t < tstop ) {
1591 if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
1592 nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
1593 t += t[1];
1594 }
1595 if ( t < tstop ) {
1596 /* Get threshold value from compiler buffer */
1597 threshold = C->lhs[level];
1598 threshold += 2; /* Skip TYPECHOP header */
1599 UnpackFloat(aux5, threshold);
1600
1601 /* Extract float and compute its absolute value */
1602 UnpackFloat(aux4, t);
1603 mpf_abs(aux4, aux4);
1604
1605 /* Remove if < threshold */
1606 if ( mpf_cmp(aux4, aux5) < 0 ) return(0);
1607 }
1608 return(Generator(BHEAD term,level));
1609}
1610
1611/*
1612 #] Chop :
1613 #] Float Routines :
1614 #[ Sorting :
1615
1616 We need a method to see whether two terms need addition that could
1617 involve floating point numbers.
1618 1: if PolyWise is active, we do not need anything, because
1619 Poly(Rat)Fun and floating point are mutually exclusive.
1620 2: This means that there should be only interference in AddCoef.
1621 and the AddRat parts in MergePatches, MasterMerge, SortBotMerge
1622 and PF_GetLoser.
1623 The compare routine(s) should recognise the float_ and give off
1624 a code (SortFloatMode) inside the AT struct:
1625 0: no float_
1626 1: float_ in term1 only
1627 2: float_ in term2 only
1628 3: float_ in both terms
1629 Be careful: we have several compare routines, because various codes
1630 use their own routines and we just set a variable with its address.
1631 Currently we have Compare1, CompareSymbols and CompareHSymbols.
1632 Only Compare1 should be active for this. The others should make sure
1633 that the proper variable is always zero.
1634 Remember: the sign of the coefficient is in the last word of the term.
1635
1636 We need two routines:
1637 1: AddWithFloat for SplitMerge which sorts by pointer.
1638 2: MergeWithFloat for MergePatches etc which keeps terms as much
1639 as possible in their location.
1640 The routines start out the same, because AT.SortFloatMode, set in
1641 Compare1, tells more or less what should be done.
1642 The difference is in where we leave the result.
1643
1644 In the future we may want to add a feature that makes the result
1645 zero if the sum comes within a certain distance of the numerical
1646 accuracy, like for instance 5% of the number of bits.
1647
1648 #[ AddWithFloat :
1649*/
1650
1651int AddWithFloat(PHEAD WORD **ps1, WORD **ps2)
1652{
1653 GETBIDENTITY
1654 SORTING *S = AT.SS;
1655 WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3;
1656 WORD *s1,*s2,sign3,j,jj, *t1, *t2, i;
1657 s1 = *ps1;
1658 s2 = *ps2;
1659 coef1 = s1+*s1; size1 = coef1[-1]; coef1 -= ABS(coef1[-1]);
1660 coef2 = s2+*s2; size2 = coef2[-1]; coef2 -= ABS(coef2[-1]);
1661 if ( AT.SortFloatMode == 3 ) {
1662 fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1663 fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1664 UnpackFloat(aux1,fun1);
1665 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1666 UnpackFloat(aux2,fun2);
1667 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1668 }
1669 else if ( AT.SortFloatMode == 1 ) {
1670 fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1671 UnpackFloat(aux1,fun1);
1672 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1673 fun2 = coef2;
1674 RatToFloat(aux2,(UWORD *)coef2,size2);
1675 }
1676 else if ( AT.SortFloatMode == 2 ) {
1677 fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1678 fun1 = coef1;
1679 RatToFloat(aux1,(UWORD *)coef1,size1);
1680 UnpackFloat(aux2,fun2);
1681 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1682 }
1683 else {
1684 MLOCK(ErrorMessageLock);
1685 MesPrint("Illegal value %d for AT.SortFloatMode in AddWithFloat.",AT.SortFloatMode);
1686 MUNLOCK(ErrorMessageLock);
1687 Terminate(-1);
1688 return(0);
1689 }
1690 mpf_add(aux3,aux1,aux2);
1691 sign3 = mpf_sgn(aux3);
1692 if ( sign3 < 0 ) mpf_neg(aux3,aux3);
1693 fun3 = TermMalloc("AddWithFloat");
1694 PackFloat(fun3,aux3);
1695/*
1696 Now we have to calculate where the sumterm fits.
1697 If we are sloppy, we can be faster, but run the risk to need the
1698 extension space, even when it is not needed. At slightly lower speed
1699 (ie first creating the result in scribble space) we are better off.
1700 This is why we use TermMalloc.
1701
1702 The new term will have a rational coefficient of 1,1,+-3.
1703 The size will be (fun1 or fun2 - term) + fun3 +3;
1704*/
1705 if ( AT.SortFloatMode == 3 ) {
1706 if ( fun1[1] == fun3[1] ) {
1707Over1:
1708 i = fun3[1]; t1 = fun1; t2 = fun3; NCOPY(t1,t2,i);
1709 *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1710 *s1 = t1-s1; goto Finished;
1711 }
1712 else if ( fun2[1] == fun3[1] ) {
1713Over2:
1714 i = fun3[1]; t1 = fun2; t2 = fun3; NCOPY(t1,t2,i);
1715 *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1716 *s2 = t1-s2; *ps1 = s2; goto Finished;
1717 }
1718 else if ( fun1[1] >= fun3[1] ) goto Over1;
1719 else if ( fun2[1] >= fun3[1] ) goto Over2;
1720 }
1721 else if ( AT.SortFloatMode == 1 ) {
1722 if ( fun1[1] >= fun3[1] ) goto Over1;
1723 else if ( fun3[1]+3 <= ABS(size2) ) goto Over2;
1724 }
1725 else if ( AT.SortFloatMode == 2 ) {
1726 if ( fun2[1] >= fun3[1] ) goto Over2;
1727 else if ( fun3[1]+3 <= ABS(size1) ) goto Over1;
1728 }
1729/*
1730 Does not fit. Go to extension space.
1731*/
1732 jj = fun1-s1;
1733 j = jj+fun3[1]+3; /* space needed */
1734 if ( (S->sFill + j) >= S->sTop2 ) {
1735 GarbHand();
1736 s1 = *ps1; /* new position of the term after the garbage collection */
1737 fun1 = s1+jj;
1738 }
1739 t1 = S->sFill;
1740 for ( i = 0; i < jj; i++ ) *t1++ = s1[i];
1741 i = fun3[1]; s1 = fun3; NCOPY(t1,s1,i);
1742 *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1743 *ps1 = S->sFill;
1744 **ps1 = t1-*ps1;
1745 S->sFill = t1;
1746Finished:
1747 *ps2 = 0;
1748 TermFree(fun3,"AddWithFloat");
1749 AT.SortFloatMode = 0;
1750 if ( **ps1 > AM.MaxTer/((LONG)(sizeof(WORD))) ) {
1751 MLOCK(ErrorMessageLock);
1752 MesPrint("Term too complex after addition in sort. MaxTermSize = %10l",
1753 AM.MaxTer/sizeof(WORD));
1754 MUNLOCK(ErrorMessageLock);
1755 Terminate(-1);
1756 }
1757 return(1);
1758}
1759
1760/*
1761 #] AddWithFloat :
1762 #[ MergeWithFloat :
1763
1764 Note that we always park the result on top of term1.
1765 This makes life easier, because the original AddRat in MergePatches
1766 does this as well.
1767*/
1768
1769int MergeWithFloat(PHEAD WORD **interm1, WORD **interm2)
1770{
1771 GETBIDENTITY
1772 WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3, *tt;
1773 WORD sign3,jj, *t1, *t2, i, *term1 = *interm1, *term2 = *interm2;
1774 int retval = 0;
1775 coef1 = term1+*term1; size1 = coef1[-1]; coef1 -= ABS(size1);
1776 coef2 = term2+*term2; size2 = coef2[-1]; coef2 -= ABS(size2);
1777 if ( AT.SortFloatMode == 3 ) {
1778 fun1 = term1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1779 fun2 = term2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1780 UnpackFloat(aux1,fun1);
1781 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1782 UnpackFloat(aux2,fun2);
1783 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1784 }
1785 else if ( AT.SortFloatMode == 1 ) {
1786 fun1 = term1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
1787 UnpackFloat(aux1,fun1);
1788 if ( size1 < 0 ) mpf_neg(aux1,aux1);
1789 fun2 = coef2;
1790 RatToFloat(aux2,(UWORD *)coef2,size2);
1791 }
1792 else if ( AT.SortFloatMode == 2 ) {
1793 fun2 = term2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
1794 fun1 = coef1;
1795 RatToFloat(aux1,(UWORD *)coef1,size1);
1796 UnpackFloat(aux2,fun2);
1797 if ( size2 < 0 ) mpf_neg(aux2,aux2);
1798 }
1799 else {
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 }
1806 mpf_add(aux3,aux1,aux2);
1807 sign3 = mpf_sgn(aux3);
1808/*
1809 Now check whether we can park the result on top of one of the input terms.
1810*/
1811 if ( sign3 < 0 ) mpf_neg(aux3,aux3);
1812 fun3 = TermMalloc("MergeWithFloat");
1813 PackFloat(fun3,aux3);
1814 if ( AT.SortFloatMode == 3 ) {
1815 if ( fun1[1] + ABS(size1) == fun3[1] + 3 ) {
1816OnTopOf1: t1 = fun3; t2 = fun1;
1817 for ( i = 0; i < fun3[1]; i++ ) *t2++ = *t1++;
1818 *t2++ = 1; *t2++ = 1; *t2++ = sign3 < 0 ? -3: 3;
1819 retval = 1;
1820 }
1821 else if ( fun1[1] + ABS(size1) > fun3[1] + 3 ) {
1822Shift1: t2 = term1 + *term1; tt = t2;
1823 *--t2 = sign3 < 0 ? -3: 3; *--t2 = 1; *--t2 = 1;
1824 t1 = fun3 + fun3[1]; for ( i = 0; i < fun3[1]; i++ ) *--t2 = *--t1;
1825 t1 = fun1;
1826 while ( t1 > term1 ) *--t2 = *--t1;
1827 *t2 = tt-t2; term1 = t2;
1828 retval = 1;
1829 }
1830 else { /* Here we have to move term1 to the left to make room. */
1831 jj = fun3[1]-fun1[1]+3-ABS(size1); /* This is positive */
1832Over1: t2 = term1-jj; t1 = term1;
1833 while ( t1 < fun1 ) *t2++ = *t1++;
1834 term1 -= jj;
1835 *term1 += jj;
1836 for ( i = 0; i < fun3[1]; i++ ) *t2++ = fun3[i];
1837 *t2++ = 1; *t2++ = 1; *t2++ = sign3 < 0 ? -3: 3;
1838 retval = 1;
1839 }
1840 }
1841 else if ( AT.SortFloatMode == 1 ) {
1842 if ( fun1[1] + ABS(size1) == fun3[1] + 3 ) goto OnTopOf1;
1843 else if ( fun1[1] + ABS(size1) > fun3[1] + 3 ) goto Shift1;
1844 else {
1845 jj = fun3[1]-fun1[1]+3-ABS(size1); /* This is positive */
1846 goto Over1;
1847 }
1848 }
1849 else { /* Can only be 2, based on previous tests */
1850 if ( fun3[1] + 3 == ABS(size1) ) goto OnTopOf1;
1851 else if ( fun3[1] + 3 < ABS(size1) ) goto Shift1;
1852 else {
1853 jj = fun3[1]+3-ABS(size1); /* This is positive */
1854 goto Over1;
1855 }
1856 }
1857 *interm1 = term1;
1858 TermFree(fun3,"MergeWithFloat");
1859 AT.SortFloatMode = 0;
1860 return(retval);
1861}
1862
1863/*
1864 #] MergeWithFloat :
1865 #] Sorting :
1866 #[ MZV :
1867
1868 The functions here allow the arbitrary precision calculation
1869 of MZV's and Euler sums.
1870 They are called when the functions mzv_ and/or euler_ are used
1871 and the evaluate statement is applied.
1872 The output is in a float_ function.
1873 The expand statement tries to express the functions in terms of a basis.
1874 The bases are the 'standard basis for the euler sums and the
1875 pushdown bases from the datamine, unless otherwise specified.
1876
1877 #[ SimpleDelta :
1878*/
1879
1880void SimpleDelta(mpf_t sum, int m)
1881{
1882 long s = 1;
1883 long prec = AC.DefaultPrecision;
1884 unsigned long xprec = (unsigned long)prec, x;
1885 int j, jmax, n;
1886 mpf_t jm,jjm;
1887 mpf_init(jm); mpf_init(jjm);
1888 if ( m < 0 ) { s = -1; m = -m; }
1889
1890/*
1891 We will loop until 1/2^j/j^m is smaller than the default precision.
1892 Just running to prec is however overkill, specially when m is large.
1893 We try to estimate a better value.
1894 jmax = prec - ((log2(prec)-1)*m).
1895 Hence we need the leading bit of prec.
1896 We are still overshooting a bit.
1897*/
1898 n = 0; x = xprec;
1899 while ( x ) { x >>= 1; n++; }
1900/*
1901 We have now n = floor(log2(x))+1.
1902*/
1903 n--;
1904 jmax = (int)((int)xprec - (n-1)*m);
1905/*
1906 For small prec and large m, the estimate can be wrong and even be negative,
1907 so we increase jmax until jmax + m*log2(jmax) > prec
1908*/
1909 if ( jmax < 0 ) jmax = 1;
1910 do {
1911 n = 0;
1912 x = (unsigned long)jmax;
1913 while (x) { x >>= 1; n++; }
1914 n--; // floor(log2(jmax))
1915 jmax++;
1916 } while ( jmax + m * n <= prec );
1917 mpf_set_ui(sum,0);
1918 for ( j = 1; j <= jmax; j++ ) {
1919#ifdef WITHCUTOFF
1920 xprec--;
1921 mpf_set_prec_raw(jm,xprec);
1922 mpf_set_prec_raw(jjm,xprec);
1923#endif
1924 mpf_set_ui(jm,1L);
1925 mpf_div_ui(jjm,jm,(unsigned long)j);
1926 mpf_pow_ui(jm,jjm,(unsigned long)m);
1927 mpf_div_2exp(jjm,jm,(unsigned long)j);
1928 if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jjm);
1929 else mpf_add(sum,sum,jjm);
1930 }
1931 mpf_clear(jjm); mpf_clear(jm);
1932}
1933
1934/*
1935 #] SimpleDelta :
1936 #[ SimpleDeltaC :
1937*/
1938
1939void SimpleDeltaC(mpf_t sum, int m)
1940{
1941 long s = 1;
1942 long prec = AC.DefaultPrecision;
1943 unsigned long xprec = (unsigned long)prec, x;
1944 int j, jmax, n;
1945 mpf_t jm,jjm;
1946 mpf_init(jm); mpf_init(jjm);
1947 if ( m < 0 ) { s = -1; m = -m; }
1948/*
1949 We will loop until 1/2^j/j^m is smaller than the default precision.
1950 Just running to prec is however overkill, specially when m is large.
1951 We try to estimate a better value.
1952 jmax = prec - ((log2(prec)-1)*m).
1953 Hence we need the leading bit of prec.
1954 We are still overshooting a bit.
1955*/
1956 n = 0; x = xprec;
1957 while ( x ) { x >>= 1; n++; }
1958/*
1959 We have now n = floor(log2(x))+1.
1960*/
1961 n--;
1962 jmax = (int)((int)xprec - (n-1)*m);
1963/*
1964 For small prec and large m, the estimate can be wrong and even be negative,
1965 so we increase jmax until jmax + m*log2(jmax) > prec
1966*/
1967 if ( jmax < 0 ) jmax = 1;
1968 do {
1969 n = 0;
1970 x = (unsigned long)jmax;
1971 while (x) { x >>= 1; n++; }
1972 n--; // floor(log2(jmax))
1973 jmax++;
1974 } while ( jmax + m * n <= prec );
1975 if ( s < 0 ) jmax /= 2;
1976 mpf_set_si(sum,0L);
1977 for ( j = 1; j <= jmax; j++ ) {
1978#ifdef WITHCUTOFF
1979 xprec--;
1980 mpf_set_prec_raw(jm,xprec);
1981 mpf_set_prec_raw(jjm,xprec);
1982#endif
1983 mpf_set_ui(jm,1L);
1984 mpf_div_ui(jjm,jm,(unsigned long)j);
1985 mpf_pow_ui(jm,jjm,(unsigned long)m);
1986 if ( s == -1 ) mpf_div_2exp(jjm,jm,2*(unsigned long)j);
1987 else mpf_div_2exp(jjm,jm,(unsigned long)j);
1988 mpf_add(sum,sum,jjm);
1989 }
1990 mpf_clear(jjm); mpf_clear(jm);
1991}
1992
1993/*
1994 #] SimpleDeltaC :
1995 #[ SingleTable :
1996*/
1997
1998void SingleTable(mpf_t *tabl, int N, int m, int pow)
1999{
2000/*
2001 Creates a table T(1,...,N) with
2002 T(i) = sum_(j,i,N,[sign_(j)]/2^j/j^m)
2003 To make this table we have two options:
2004 1: run the sum backwards with the potential problem that the
2005 precision is difficult to manage.
2006 2: run the sum forwards. Take sum_(j,1,i-1,...) and later subtract.
2007 When doing Euler sums we may need also 1/4^j
2008 pow: 1 -> 1/2^j
2009 2 -> 1/4^j
2010*/
2011 GETIDENTITY
2012 long s = 1;
2013 int j;
2014#ifdef WITHCUTOFF
2015 long prec = mpf_get_default_prec();
2016#endif
2017 mpf_t jm,jjm;
2018 mpf_init(jm); mpf_init(jjm);
2019 if ( pow < 1 || pow > 2 ) {
2020 MLOCK(ErrorMessageLock);
2021 MesPrint("Wrong parameter pow in SingleTable: %d\n",pow);
2022 MUNLOCK(ErrorMessageLock);
2023 Terminate(-1);
2024 }
2025 if ( m < 0 ) { m = -m; s = -1; }
2026 mpf_set_si(auxsum,0L);
2027 for ( j = N; j > 0; j-- ) {
2028#ifdef WITHCUTOFF
2029 mpf_set_prec_raw(jm,prec-j);
2030 mpf_set_prec_raw(jjm,prec-j);
2031#endif
2032 mpf_set_ui(jm,1L);
2033 mpf_div_ui(jjm,jm,(unsigned long)j);
2034 mpf_pow_ui(jm,jjm,(unsigned long)m);
2035 mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
2036 if ( pow == 2 ) mpf_add(auxsum,auxsum,jjm);
2037 else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jjm);
2038 else mpf_add(auxsum,auxsum,jjm);
2039/*
2040 And now copy auxsum to tablelement j
2041*/
2042 mpf_set(tabl[j],auxsum);
2043 }
2044 mpf_clear(jjm); mpf_clear(jm);
2045}
2046
2047/*
2048 #] SingleTable :
2049 #[ DoubleTable :
2050*/
2051
2052void DoubleTable(mpf_t *tabout, mpf_t *tabin, int N, int m, int pow)
2053{
2054 GETIDENTITY
2055 long s = 1;
2056#ifdef WITHCUTOFF
2057 long prec = mpf_get_default_prec();
2058#endif
2059 int j;
2060 mpf_t jm,jjm;
2061 mpf_init(jm); mpf_init(jjm);
2062 if ( pow < -1 || pow > 2 ) {
2063 MLOCK(ErrorMessageLock);
2064 MesPrint("Wrong parameter pow in DoubleTable: %d\n",pow);
2065 MUNLOCK(ErrorMessageLock);
2066 Terminate(-1);
2067 }
2068 if ( m < 0 ) { m = -m; s = -1; }
2069 mpf_set_ui(auxsum,0L);
2070 for ( j = N; j > 0; j-- ) {
2071#ifdef WITHCUTOFF
2072 mpf_set_prec_raw(jm,prec-j);
2073 mpf_set_prec_raw(jjm,prec-j);
2074#endif
2075 mpf_set_ui(jm,1L);
2076 mpf_div_ui(jjm,jm,(unsigned long)j);
2077 mpf_pow_ui(jm,jjm,(unsigned long)m);
2078 if ( pow == -1 ) {
2079 mpf_mul_2exp(jjm,jm,(unsigned long)j);
2080 mpf_mul(jm,jjm,tabin[j+1]);
2081 }
2082 else if ( pow > 0 ) {
2083 mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
2084 mpf_mul(jm,jjm,tabin[j+1]);
2085 }
2086 else {
2087 mpf_mul(jm,jm,tabin[j+1]);
2088 }
2089 if ( pow == 2 ) mpf_add(auxsum,auxsum,jm);
2090 else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jm);
2091 else mpf_add(auxsum,auxsum,jm);
2092/*
2093 And now copy auxsum to tablelement j
2094*/
2095 mpf_set(tabout[j],auxsum);
2096 }
2097 mpf_clear(jjm); mpf_clear(jm);
2098}
2099
2100/*
2101 #] DoubleTable :
2102 #[ EndTable :
2103*/
2104
2105void EndTable(mpf_t sum, mpf_t *tabin, int N, int m, int pow)
2106{
2107 long s = 1;
2108#ifdef WITHCUTOFF
2109 long prec = mpf_get_default_prec();
2110#endif
2111 int j;
2112 mpf_t jm,jjm;
2113 mpf_init(jm); mpf_init(jjm);
2114 if ( pow < -1 || pow > 2 ) {
2115 MLOCK(ErrorMessageLock);
2116 MesPrint("Wrong parameter pow in EndTable: %d\n",pow);
2117 MUNLOCK(ErrorMessageLock);
2118 Terminate(-1);
2119 }
2120 if ( m < 0 ) { m = -m; s = -1; }
2121 mpf_set_si(sum,0L);
2122 for ( j = N; j > 0; j-- ) {
2123#ifdef WITHCUTOFF
2124 mpf_set_prec_raw(jm,prec-j);
2125 mpf_set_prec_raw(jjm,prec-j);
2126#endif
2127 mpf_set_ui(jm,1L);
2128 mpf_div_ui(jjm,jm,(unsigned long)j);
2129 mpf_pow_ui(jm,jjm,(unsigned long)m);
2130 if ( pow == -1 ) {
2131 mpf_mul_2exp(jjm,jm,(unsigned long)j);
2132 mpf_mul(jm,jjm,tabin[j+1]);
2133 }
2134 else if ( pow > 0 ) {
2135 mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
2136 mpf_mul(jm,jjm,tabin[j+1]);
2137 }
2138 else {
2139 mpf_mul(jm,jm,tabin[j+1]);
2140 }
2141 if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jm);
2142 else mpf_add(sum,sum,jm);
2143 }
2144 mpf_clear(jjm); mpf_clear(jm);
2145}
2146
2147/*
2148 #] EndTable :
2149 #[ deltaMZV :
2150*/
2151
2152void deltaMZV(mpf_t result, WORD *indexes, int depth)
2153{
2154 GETIDENTITY
2155/*
2156 Because all sums go roughly like 1/2^j we need about depth steps.
2157*/
2158/* MesPrint("deltaMZV(%a)",depth,indexes); */
2159 if ( depth == 1 ) {
2160 if ( indexes[0] == 1 ) {
2161 mpf_set(result,mpfdelta1);
2162 return;
2163 }
2164 SimpleDelta(result,indexes[0]);
2165 }
2166 else if ( depth == 2 ) {
2167 if ( indexes[0] == 1 && indexes[1] == 1 ) {
2168 mpf_pow_ui(result,mpfdelta1,2);
2169 mpf_div_2exp(result,result,1);
2170 }
2171 else {
2172 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
2173 EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,indexes[1],0);
2174 };
2175 }
2176 else if ( depth > 2 ) {
2177 mpf_t *mpftab3;
2178 int d;
2179/*
2180 Check first whether this is a power of delta1 = ln(2)
2181*/
2182 for ( d = 0; d < depth; d++ ) {
2183 if ( indexes[d] != 1 ) break;
2184 }
2185 if ( d == depth ) { /* divide by fac_(depth) */
2186 mpf_pow_ui(result,mpfdelta1,depth);
2187 for ( d = 2; d <= depth; d++ ) {
2188 mpf_div_ui(result,result,(unsigned long)d);
2189 }
2190 }
2191 else {
2192 d = depth-1;
2193 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
2194 d--; indexes++;
2195 for(;;) {
2196 DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,0);
2197 d--; indexes++;
2198 if ( d == 0 ) {
2199 EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,*indexes,0);
2200 break;
2201 }
2202 mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2203 AT.mpf_tab2 = (void *)mpftab3;
2204 }
2205 }
2206 }
2207 else if ( depth == 0 ) {
2208 mpf_set_ui(result,1L);
2209 }
2210}
2211
2212/*
2213 #] deltaMZV :
2214 #[ deltaEuler :
2215
2216 Regular Euler delta with - signs, but everywhere 1/2^j
2217*/
2218
2219void deltaEuler(mpf_t result, WORD *indexes, int depth)
2220{
2221 GETIDENTITY
2222 int m;
2223#ifdef DEBUG
2224 int i;
2225 printf(" deltaEuler(");
2226 for ( i = 0; i < depth; i++ ) {
2227 if ( i != 0 ) printf(",");
2228 printf("%d",indexes[i]);
2229 }
2230 printf(") = ");
2231#endif
2232 if ( depth == 1 ) {
2233 SimpleDelta(result,indexes[0]);
2234 }
2235 else if ( depth == 2 ) {
2236 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
2237 m = indexes[1]; if ( indexes[0] < 0 ) m = -m;
2238 EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,0);
2239 }
2240 else if ( depth > 2 ) {
2241 int d;
2242 mpf_t *mpftab3;
2243 d = depth-1;
2244 SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
2245 d--; indexes++;
2246 m = *indexes; if ( indexes[-1] < 0 ) m = -m;
2247 for(;;) {
2248 DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,0);
2249 d--; indexes++;
2250 m = *indexes; if ( indexes[-1] < 0 ) m = -m;
2251 if ( d == 0 ) {
2252 EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,0);
2253 break;
2254 }
2255 mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2256 AT.mpf_tab2 = (void *)mpftab3;
2257 }
2258 }
2259 else if ( depth == 0 ) {
2260 mpf_set_ui(result,1L);
2261 }
2262#ifdef DEBUG
2263 gmp_printf("%.*Fe\n",40,result);
2264#endif
2265}
2266
2267/*
2268 #] deltaEuler :
2269 #[ deltaEulerC :
2270
2271 Conjugate Euler delta without - signs, but possibly 1/4^j
2272 When there is a - in the string we have 1/4.
2273*/
2274
2275void deltaEulerC(mpf_t result, WORD *indexes, int depth)
2276{
2277 GETIDENTITY
2278 int m;
2279#ifdef DEBUG
2280 int i;
2281 printf(" deltaEulerC(");
2282 for ( i = 0; i < depth; i++ ) {
2283 if ( i != 0 ) printf(",");
2284 printf("%d",indexes[i]);
2285 }
2286 printf(") = ");
2287#endif
2288 mpf_set_ui(result,0);
2289 if ( depth == 1 ) {
2290 if ( indexes[0] == 0 ) {
2291 MLOCK(ErrorMessageLock);
2292 MesPrint("Illegal index in depth=1 deltaEulerC: %d\n",indexes[0]);
2293 MUNLOCK(ErrorMessageLock);
2294 Terminate(-1);
2295 }
2296 if ( indexes[0] < 0 ) SimpleDeltaC(result,indexes[0]);
2297 else SimpleDelta(result,indexes[0]);
2298 }
2299 else if ( depth == 2 ) {
2300 int par;
2301 m = indexes[0];
2302 if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth,-m,2);
2303 else SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth, m,1);
2304 m = indexes[1];
2305 if ( m < 0 ) { m = -m; par = indexes[0] < 0 ? 0: 1; }
2306 else { par = indexes[0] < 0 ? -1: 0; }
2307 EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,par);
2308 }
2309 else if ( depth > 2 ) {
2310 int d, par;
2311 mpf_t *mpftab3;
2312 d = depth-1;
2313 m = indexes[0];
2314 ZeroTable(mpftab1,AC.DefaultPrecision+1);
2315 if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1,-m,2);
2316 else SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1, m,1);
2317 d--; indexes++; m = indexes[0];
2318 if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
2319 else { par = indexes[-1] < 0 ? -1: 0; }
2320 for(;;) {
2321 ZeroTable(mpftab2,AC.DefaultPrecision-AC.MaxWeight+d);
2322 DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,par);
2323 d--; indexes++; m = indexes[0];
2324 if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
2325 else { par = indexes[-1] < 0 ? -1: 0; }
2326 if ( d == 0 ) {
2327 mpf_set_ui(result,0);
2328 EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,par);
2329 break;
2330 }
2331 mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2332 AT.mpf_tab2 = (void *)mpftab3;
2333 }
2334 }
2335 else if ( depth == 0 ) {
2336 mpf_set_ui(result,1L);
2337 }
2338#ifdef DEBUG
2339 gmp_printf("%.*Fe\n",40,result);
2340#endif
2341}
2342
2343/*
2344 #] deltaEulerC :
2345 #[ CalculateMZVhalf :
2346
2347 This routine is mainly for support when large numbers of
2348 MZV's have to be calculated at the same time.
2349*/
2350
2351void CalculateMZVhalf(mpf_t result, WORD *indexes, int depth)
2352{
2353 int i;
2354 if ( depth < 0 ) {
2355 MLOCK(ErrorMessageLock);
2356 MesPrint("Illegal depth in CalculateMZVhalf: %d",depth);
2357 MUNLOCK(ErrorMessageLock);
2358 Terminate(-1);
2359 }
2360 for ( i = 0; i < depth; i++ ) {
2361 if ( indexes[i] <= 0 ) {
2362 MLOCK(ErrorMessageLock);
2363 MesPrint("Illegal index[%d] in CalculateMZVhalf: %d",i,indexes[i]);
2364 MUNLOCK(ErrorMessageLock);
2365 Terminate(-1);
2366 }
2367 }
2368 deltaMZV(result,indexes,depth);
2369}
2370
2371/*
2372 #] CalculateMZVhalf :
2373 #[ CalculateMZV :
2374*/
2375
2376void CalculateMZV(mpf_t result, WORD *indexes, int depth)
2377{
2378 GETIDENTITY
2379 int num1, num2 = 0, i, j = 0;
2380 if ( depth < 0 ) {
2381 MLOCK(ErrorMessageLock);
2382 MesPrint("Illegal depth in CalculateMZV: %d",depth);
2383 MUNLOCK(ErrorMessageLock);
2384 Terminate(-1);
2385 }
2386 if ( indexes[0] == 1 ) {
2387 MLOCK(ErrorMessageLock);
2388 MesPrint("Divergent MZV in CalculateMZV");
2389 MUNLOCK(ErrorMessageLock);
2390 Terminate(-1);
2391 }
2392/* MesPrint("calculateMZV(%a)",depth,indexes); */
2393 for ( i = 0; i < depth; i++ ) {
2394 if ( indexes[i] <= 0 ) {
2395 MLOCK(ErrorMessageLock);
2396 MesPrint("Illegal index[%d] in CalculateMZV: %d",i,indexes[i]);
2397 MUNLOCK(ErrorMessageLock);
2398 Terminate(-1);
2399 }
2400 AT.indi1[i] = indexes[i];
2401 }
2402 num1 = depth; i = 0;
2403 deltaMZV(result,indexes,depth);
2404 for(;;) {
2405 if ( AT.indi1[0] > 1 ) {
2406 AT.indi1[0] -= 1;
2407 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2408 AT.indi2[0] = 1; num2++;
2409 }
2410 else {
2411 AT.indi2[0] += 1;
2412 for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
2413 num1--;
2414 if ( num1 == 0 ) break;
2415 }
2416 deltaMZV(aux1,AT.indi1,num1);
2417 deltaMZV(aux2,AT.indi2,num2);
2418 mpf_mul(aux3,aux1,aux2);
2419 mpf_add(result,result,aux3);
2420 }
2421 deltaMZV(aux3,AT.indi2,num2);
2422 mpf_add(result,result,aux3);
2423}
2424
2425/*
2426 #] CalculateMZV :
2427 #[ CalculateEuler :
2428
2429 There is a problem of notation here.
2430 Basically there are two notations.
2431 1: Z(m1,m2,m3) = sum_(j3,1,inf,sign_(m3)/j3^abs_(m3)*
2432 sum_(j2,j3+1,inf,sign_(m2)/j2^abs_(m2)*
2433 sum_(j1,j2+1,inf,sign_(m1)/j1^abs_(m1))))
2434 See Broadhurst,1996
2435 2: L(m1,m2,m3) = sum_(j1,1,inf,sign_(m1)*
2436 sum_(j2,1,inf,sign_(m2)*
2437 sum_(j3,1,inf,sign_(m3)
2438 /j3^abs_(m3)
2439 /(j2+j3)^abs_(m2)
2440 /(j1+j2+j3)^abs_(m1) )))
2441 See Borwein, Bradley, Broadhurst and Lisonek, 1999
2442 The L corresponds with the H of the datamine up to sign_(m1*m2*m3)
2443 The algorithm follows 2, but the more common notation is 1.
2444 Hence we start with a conversion.
2445*/
2446
2447void CalculateEuler(mpf_t result, WORD *Zindexes, int depth)
2448{
2449 GETIDENTITY
2450 int s1, num1, num2, i, j;
2451
2452 WORD *indexes = AT.WorkPointer;
2453 for ( i = 0; i < depth; i++ ) indexes[i] = Zindexes[i];
2454 for ( i = 0; i < depth-1; i++ ) {
2455 if ( Zindexes[i] < 0 ) {
2456 for ( j = i+1; j < depth; j++ ) indexes[j] = -indexes[j];
2457 }
2458 }
2459
2460 if ( depth < 0 ) {
2461 MLOCK(ErrorMessageLock);
2462 MesPrint("Illegal depth in CalculateEuler: %d\n",depth);
2463 MUNLOCK(ErrorMessageLock);
2464 Terminate(-1);
2465 }
2466 if ( indexes[0] == 1 ) {
2467 MLOCK(ErrorMessageLock);
2468 MesPrint("Divergent Euler sum in CalculateEuler\n");
2469 MUNLOCK(ErrorMessageLock);
2470 Terminate(-1);
2471 }
2472 for ( i = 0, j = 0; i < depth; i++ ) {
2473 if ( indexes[i] == 0 ) {
2474 MLOCK(ErrorMessageLock);
2475 MesPrint("Illegal index[%d] in CalculateEuler: %d\n",i,indexes[i]);
2476 MUNLOCK(ErrorMessageLock);
2477 Terminate(-1);
2478 }
2479 if ( indexes[i] < 0 ) j = 1;
2480 AT.indi1[i] = indexes[i];
2481 }
2482 if ( j == 0 ) {
2483 CalculateMZV(result,indexes,depth);
2484 return;
2485 }
2486 num1 = depth; AT.indi2[0] = 0; num2 = 0;
2487 deltaEuler(result,AT.indi1,depth);
2488 s1 = 0;
2489 for(;;) {
2490 s1++;
2491 if ( AT.indi1[0] > 1 ) {
2492 AT.indi1[0] -= 1;
2493 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2494 AT.indi2[0] = 1; num2++;
2495 }
2496 else if ( AT.indi1[0] < -1 ) {
2497 AT.indi1[0] += 1;
2498 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2499 AT.indi2[0] = 1; num2++;
2500 }
2501 else if ( AT.indi1[0] == -1 ) {
2502 for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
2503 AT.indi2[0] = -1; num2++;
2504 for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
2505 num1--;
2506 }
2507 else {
2508 AT.indi2[0] = AT.indi2[0] < 0 ? AT.indi2[0]-1: AT.indi2[0]+1;
2509 for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
2510 num1--;
2511 }
2512 if ( num1 == 0 ) break;
2513 deltaEuler(aux1,AT.indi1,num1);
2514 deltaEulerC(aux2,AT.indi2,num2);
2515 mpf_mul(aux3,aux1,aux2);
2516 if ( (depth+num1+num2+s1)%2 == 0 ) mpf_add(result,result,aux3);
2517 else mpf_sub(result,result,aux3);
2518 }
2519 deltaEulerC(aux3,AT.indi2,num2);
2520 if ( (depth+num2+s1)%2 == 0 ) mpf_add(result,result,aux3);
2521 else mpf_sub(result,result,aux3);
2522}
2523
2524/*
2525 #] CalculateEuler :
2526 #[ ExpandMZV :
2527*/
2528
2529int ExpandMZV(WORD *term, WORD level)
2530{
2531 DUMMYUSE(term);
2532 DUMMYUSE(level);
2533 return(0);
2534}
2535
2536/*
2537 #] ExpandMZV :
2538 #[ ExpandEuler :
2539*/
2540
2541int ExpandEuler(WORD *term, WORD level)
2542{
2543 DUMMYUSE(term);
2544 DUMMYUSE(level);
2545 return(0);
2546}
2547
2548/*
2549 #] ExpandEuler :
2550 #[ EvaluateEuler :
2551
2552 There are various steps here:
2553 1: locate an Euler function.
2554 2: evaluate it into a float.
2555 3: convert the coefficient to a float and multiply.
2556 4: Put the new term together.
2557 5: Restart to see whether there are more Euler functions.
2558 The compiler should check that there is no conflict between
2559 the evaluate command and a potential polyfun or polyratfun.
2560 Yet, when reading in expressions there can be a conflict.
2561 Hence the Normalize routine should check as well.
2562
2563 par == MZV: MZV
2564 par == EULER: Euler
2565 par == MZVHALF: MZV sums in 1/2 rather than 1. -> deltaMZV.
2566 par == ALLMZVFUNCTIONS: all of the above.
2567*/
2568
2569int EvaluateEuler(PHEAD WORD *term, WORD level, WORD par)
2570{
2571 WORD *t, *tstop, *tt, *tnext, sumweight, depth, first = 1, *newterm, i;
2572 WORD *oldworkpointer = AT.WorkPointer, nsize, *indexes;
2573 int retval;
2574 tstop = term + *term; tstop -= ABS(tstop[-1]);
2575 if ( AT.WorkPointer < term+*term ) AT.WorkPointer = term + *term;
2576/*
2577 Step 1. We also need to verify that the argument we find is legal
2578*/
2579 t = term+1;
2580 while ( t < tstop ) {
2581 if ( ( *t == par ) || ( ( par == ALLMZVFUNCTIONS ) && (
2582 *t == MZV || *t == EULER || *t == MZVHALF ) ) ) {
2583 /* all arguments should be small integers */
2584 indexes = AT.WorkPointer;
2585 sumweight = 0; depth = 0;
2586 tnext = t + t[1]; tt = t + FUNHEAD;
2587 while ( tt < tnext ) {
2588 if ( *tt != -SNUMBER ) goto nextfun;
2589 if ( tt[1] == 0 ) goto nextfun;
2590 indexes[depth] = tt[1];
2591 sumweight += ABS(tt[1]); depth++;
2592 tt += 2;
2593 }
2594 /* euler sum without arguments, i.e. mzv_(), euler_() or mzvhalf_() */
2595 if ( depth == 0) goto nextfun;
2596 if ( sumweight > AC.MaxWeight ) {
2597 MLOCK(ErrorMessageLock);
2598 MesPrint("Error: Weight of Euler/MZV sum greater than %d.",AC.MaxWeight);
2599 MesPrint("Please increase the maximum weight in %#startfloat.");
2600 MUNLOCK(ErrorMessageLock);
2601 Terminate(-1);
2602 }
2603/*
2604 Step 2: evaluate:
2605*/
2606 AT.WorkPointer += depth;
2607 if ( first ) {
2608 if ( *t == MZV ) CalculateMZV(aux4,indexes,depth);
2609 else if ( *t == EULER ) CalculateEuler(aux4,indexes,depth);
2610 else if ( *t == MZVHALF ) CalculateMZVhalf(aux4,indexes,depth);
2611 first = 0;
2612 }
2613 else {
2614 if ( *t == MZV ) CalculateMZV(aux5,indexes,depth);
2615 else if ( *t == EULER ) CalculateEuler(aux5,indexes,depth);
2616 else if ( *t == MZVHALF ) CalculateMZVhalf(aux5,indexes,depth);
2617 mpf_mul(aux4,aux4,aux5);
2618 }
2619 *t = 0;
2620 }
2621nextfun:
2622 t += t[1];
2623 }
2624 if ( first == 1 ) return(Generator(BHEAD term,level));
2625/*
2626 Step 3:
2627 Now the regular coefficient, if it is not 1/1.
2628 We have two cases: size +- 3, or bigger.
2629*/
2630 nsize = term[*term-1];
2631 if ( nsize < 0 ) {
2632 mpf_neg(aux4,aux4);
2633 nsize = -nsize;
2634 }
2635 if ( nsize == 3 ) {
2636 if ( tstop[0] != 1 ) {
2637 mpf_mul_ui(aux4,aux4,(ULONG)((UWORD)tstop[0]));
2638 }
2639 if ( tstop[1] != 1 ) {
2640 mpf_div_ui(aux4,aux4,(ULONG)((UWORD)tstop[1]));
2641 }
2642 }
2643 else {
2644 RatToFloat(aux5,(UWORD *)tstop,nsize);
2645 mpf_mul(aux4,aux4,aux5);
2646 }
2647/*
2648 Now we have to locate possible other float_ functions.
2649*/
2650 t = term+1;
2651 while ( t < tstop ) {
2652 if ( *t == FLOATFUN ) {
2653 UnpackFloat(aux5,t);
2654 mpf_mul(aux4,aux4,aux5);
2655 }
2656 t += t[1];
2657 }
2658/*
2659 Now we should compose the new term in the WorkSpace.
2660*/
2661 t = term+1;
2662 newterm = AT.WorkPointer;
2663 tt = newterm+1;
2664 while ( t < tstop ) {
2665 if ( *t == 0 || *t == FLOATFUN ) t += t[1];
2666 else {
2667 i = t[1]; NCOPY(tt,t,i);
2668 }
2669 }
2670 PackFloat(tt,aux4);
2671 tt += tt[1];
2672 *tt++ = 1; *tt++ = 1; *tt++ = 3;
2673 *newterm = tt-newterm;
2674 AT.WorkPointer = tt;
2675 retval = Generator(BHEAD newterm,level);
2676 AT.WorkPointer = oldworkpointer;
2677 return(retval);
2678}
2679
2680/*
2681 #] EvaluateEuler :
2682 #] MZV :
2683 #[ Functions :
2684 #[ CoEvaluate :
2685
2686 Current subkeys: mzv_, euler_ and sqrt_.
2687*/
2688
2689int CoEvaluate(UBYTE *s)
2690{
2691 GETIDENTITY
2692 UBYTE *subkey, c;
2693 WORD numfun, type;
2694 int error = 0;
2695 if ( AT.aux_ == 0 ) {
2696 MesPrint("&Illegal attempt to evaluate a function without activating floating point numbers.");
2697 MesPrint("&Forgotten %#startfloat instruction?");
2698 return(1);
2699 }
2700 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
2701 if ( *s == 0 ) {
2702/*
2703 No subkey, which means all functions.
2704*/
2705 Add3Com(TYPEEVALUATE,ALLFUNCTIONS);
2706/*
2707 The MZV, EULER and MZVHALF are done separately
2708*/
2709 Add3Com(TYPEEVALUATE,ALLMZVFUNCTIONS);
2710 return(0);
2711 }
2712 while ( *s ) {
2713 subkey = s;
2714 while ( FG.cTable[*s] == 0 ) s++;
2715 if ( *s == '2' ) s++; /* cases li2_ and atan2_ */
2716 if ( *s == '_' ) s++;
2717 c = *s; *s = 0;
2718/*
2719 We still need provisions for pi_ and possibly other constants.
2720*/
2721 if ( ( ( type = GetName(AC.varnames,subkey,&numfun,NOAUTO) ) != CFUNCTION )
2722 || ( functions[numfun].spec != 0 ) ) {
2723
2724 if ( type == CSYMBOL ) {
2725 Add4Com(TYPEEVALUATE,SYMBOL,numfun);
2726 break;
2727 }
2728/*
2729 This cannot work.
2730*/
2731 MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
2732 return(1);
2733 }
2734 else {
2735 switch ( numfun+FUNCTION ) {
2736 case MZV:
2737 case EULER:
2738 case MZVHALF:
2739/*
2740 The following functions are treated in evaluate.c
2741*/
2742 case SQRTFUNCTION:
2743 case LNFUNCTION:
2744 case EXPFUNCTION:
2745 case SINFUNCTION:
2746 case COSFUNCTION:
2747 case TANFUNCTION:
2748 case ASINFUNCTION:
2749 case ACOSFUNCTION:
2750 case ATANFUNCTION:
2751 case ATAN2FUNCTION:
2752 case SINHFUNCTION:
2753 case COSHFUNCTION:
2754 case TANHFUNCTION:
2755 case ASINHFUNCTION:
2756 case ACOSHFUNCTION:
2757 case ATANHFUNCTION:
2758 case LI2FUNCTION:
2759 case LINFUNCTION:
2760 case AGMFUNCTION:
2761 case GAMMAFUN:
2762/*
2763 At a later stage we can add more functions from mpfr here
2764 mpfr_(number,arg(s))
2765*/
2766 Add3Com(TYPEEVALUATE,numfun+FUNCTION);
2767 break;
2768 default:
2769 MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
2770 error = 1;
2771 break;
2772 }
2773 }
2774 *s = c;
2775 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
2776 }
2777 return(error);
2778}
2779
2780/*
2781 #] CoEvaluate :
2782 #] Functions :
2783*/
int AddNtoL(int n, WORD *array)
Definition comtool.c:288
void GarbHand(void)
Definition sort.c:3346
int Generator(PHEAD WORD *, WORD)
Definition proces.c:3249
WORD ** lhs
Definition structs.h:974