• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tueda / form / 21438602085

27 Jan 2026 09:10AM UTC coverage: 58.031% (+0.2%) from 57.877%
21438602085

push

github

jodavies
docs: get ready for the next release.

0 of 1 new or added line in 1 file covered. (0.0%)

2616 existing lines in 13 files now uncovered.

47983 of 82685 relevant lines covered (58.03%)

5397615.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.48
/sources/float.c
1
/** @file float.c
2
 * 
3
 *  This file contains numerical routines that deal with floating point numbers.
4
 *        We use the GMP for arbitrary precision floating point arithmetic.
5
 *        The functions of the type sin, cos, ln, sqrt etc are handled by the
6
 *        mpfr library. The reason that for MZV's and the general notation we use
7
 *        the GMP (mpf_) is because the contents of the structs have been frozen
8
 *        and can be used for storage in a Form function float_. With mpfr_ this
9
 *        is not safely possible. All mpfr_ related code is in the file evaluate.c.
10
 */
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

50
void Form_mpf_init(mpf_t t);
51
void Form_mpf_clear(mpf_t t);
52
void Form_mpf_set_prec_raw(mpf_t t,ULONG newprec);
53
void FormtoZ(mpz_t z,UWORD *a,WORD na);
54
void ZtoForm(UWORD *a,WORD *na,mpz_t z);
55
long FloatToInteger(UWORD *out, mpf_t floatin, long *bitsused);
56
void IntegerToFloat(mpf_t result, UWORD *formlong, int longsize);
57
int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin);
58
int AddFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2);
59
int MulFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2);
60
int DivFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2);
61
int AddRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat);
62
int MulRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat);
63
void SimpleDelta(mpf_t sum, int m);
64
void SimpleDeltaC(mpf_t sum, int m);
65
void SingleTable(mpf_t *tabl, int N, int m, int pow);
66
void DoubleTable(mpf_t *tabout, mpf_t *tabin, int N, int m, int pow);
67
void EndTable(mpf_t sum, mpf_t *tabin, int N, int m, int pow);
68
void deltaMZV(mpf_t, WORD *, int);
69
void deltaEuler(mpf_t, WORD *, int);
70
void deltaEulerC(mpf_t, WORD *, int);
71
void CalculateMZVhalf(mpf_t, WORD *, int);
72
void CalculateMZV(mpf_t, WORD *, int);
73
void CalculateEuler(mpf_t, WORD *, int);
74
int ExpandMZV(WORD *term, WORD level);
75
int ExpandEuler(WORD *term, WORD level);
76
int PackFloat(WORD *,mpf_t);
77
int UnpackFloat(mpf_t, WORD *);
78
void 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

177
void 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

201
void 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

214
void Form_mpf_empty(mpf_t t)
720✔
215
{
216
        int i;
720✔
217
        for ( i = 0; i < t->_mp_prec; i++ ) t->_mp_d[i] = 0;
2,340✔
218
        t->_mp_size = 0;
720✔
219
        t->_mp_exp = 0;
720✔
220
}
720✔
221

222
/*
223
                 #] Form_mpf_empty : 
224
                 #[ Form_mpf_set_prec_raw :
225
*/
226

227
void 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

271
int PackFloat(WORD *fun,mpf_t infloat)
12,120✔
272
{
273
        WORD *t, nlimbs, num, nnum;
12,120✔
274
        mp_limb_t *d = infloat->_mp_d; /* Pointer to the limbs.  */
12,120✔
275
        int i;
12,120✔
276
        long e = infloat->_mp_exp;
12,120✔
277
        t = fun;
12,120✔
278
        *t++ = FLOATFUN;
12,120✔
279
        t++;
12,120✔
280
        FILLFUN(t);
12,120✔
281
        *t++ = -SNUMBER;
12,120✔
282
        *t++ = infloat->_mp_prec;
12,120✔
283
        *t++ = -SNUMBER;
12,120✔
284
        *t++ = infloat->_mp_size;
12,120✔
285
/*
286
        Now the exponent which is a signed long
287
*/
288
        if ( e < 0 ) {
12,120✔
289
                e = -e;
354✔
290
                if ( ( e >> (BITSINWORD-1) ) == 0 ) {
354✔
291
                        *t++ = -SNUMBER; *t++ = -e;
192✔
292
                }
293
                else {
294
                        *t++ = ARGHEAD+6; *t++ = 0; FILLARG(t);
162✔
295
                        *t++ = 6;
162✔
296
                        *t++ = (UWORD)e;
162✔
297
                        *t++ = (UWORD)(e >> BITSINWORD);
162✔
298
                        *t++ = 1; *t++ = 0; *t++ = -5;
162✔
299
                }
300
        }
301
        else {
302
                if ( ( e >> (BITSINWORD-1) ) == 0 ) {
11,766✔
303
                        *t++ = -SNUMBER; *t++ = e;
11,604✔
304
                }
305
                else {
306
                        *t++ = ARGHEAD+6; *t++ = 0; FILLARG(t);
162✔
307
                        *t++ = 6;
162✔
308
                        *t++ = (UWORD)e;
162✔
309
                        *t++ = (UWORD)(e >> BITSINWORD);
162✔
310
                        *t++ = 1; *t++ = 0; *t++ = 5;
162✔
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;
12,120✔
318
        if ( nlimbs == 0 ) {
12,120✔
319
                *t++ = -SNUMBER;
1,242✔
320
                *t++ = 0;
1,242✔
321
        }
322
        else if ( nlimbs == 1 && (ULONG)(*d) < ((ULONG)1)<<(BITSINWORD-1) ) {
10,878✔
323
                *t++ = -SNUMBER;
1,872✔
324
                *t++ = (UWORD)(*d);
1,872✔
325
        }
326
        else {
327
          if ( d[nlimbs-1] < ((ULONG)1)<<BITSINWORD ) {
9,006✔
328
                num = 2*nlimbs-1; /* number of UWORDS needed */
6,774✔
329
          }
330
          else {
331
                num = 2*nlimbs;   /* number of UWORDS needed */
2,232✔
332
          }
333
          nnum = num;
9,006✔
334
          *t++ = 2*num+2+ARGHEAD;
9,006✔
335
          *t++ = 0;
9,006✔
336
          FILLARG(t);
9,006✔
337
          *t++ = 2*num+2;
9,006✔
338
          while ( num > 1 ) {
30,174✔
339
                *t++ = (UWORD)(*d); *t++ = (UWORD)(((ULONG)(*d))>>BITSINWORD); d++;
21,168✔
340
                num -= 2;
21,168✔
341
          }
342
          if ( num == 1 ) { *t++ = (UWORD)(*d); }
9,006✔
343
          *t++ = 1;
9,006✔
344
          for ( i = 1; i < nnum; i++ ) *t++ = 0;
49,110✔
345
          *t++ = 2*nnum+1; /* the sign is hidden in infloat->_mp_size */
9,006✔
346
        }
347
        fun[1] = t-fun;
12,120✔
348
        return(fun[1]);
12,120✔
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

366
int UnpackFloat(mpf_t outfloat,WORD *fun)
18,450✔
367
{
368
        UWORD *t;
18,450✔
369
        WORD *f;
18,450✔
370
        int num, i;
18,450✔
371
        mp_limb_t *d;
18,450✔
372
/*
373
        Very first step: check whether we can use float_:
374
*/
375
        GETIDENTITY
12,300✔
376
        if ( AT.aux_ == 0 ) {
18,450✔
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;
18,450✔
389
        f = fun + FUNHEAD + 2;
18,450✔
390
        if ( ABS(f[1]) > f[-1]+1 ) goto Incorrect;
18,450✔
391
        if ( f[1] > outfloat->_mp_prec+1
18,450✔
392
          || outfloat->_mp_d == 0 ) {
18,450✔
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];
18,450✔
404
        outfloat->_mp_size = num;
18,450✔
405
        if ( num < 0 ) { num = -num; }
18,450✔
406
        f += 2;
18,450✔
407
        if ( *f == -SNUMBER ) {
18,450✔
408
                outfloat->_mp_exp = (mp_exp_t)(f[1]);
18,126✔
409
                f += 2;
18,126✔
410
        }
411
        else {
412
                f += ARGHEAD+6;
324✔
413
                if ( f[-1] == -5 ) {
324✔
414
                        outfloat->_mp_exp =
162✔
415
                                -(mp_exp_t)((((ULONG)(f[-4]))<<BITSINWORD)+(UWORD)f[-5]);
162✔
416
                }
417
                else if ( f[-1] == 5 ) {
162✔
418
                        outfloat->_mp_exp =
162✔
419
                                 (mp_exp_t)((((ULONG)(f[-4]))<<BITSINWORD)+(UWORD)f[-5]);
162✔
420
                }
421
        }
422
/*
423
        And now the limbs if needed
424
*/
425
        d = outfloat->_mp_d;
18,450✔
426
        if ( outfloat->_mp_size == 0 ) {
18,450✔
427
                for ( i = 0; i < outfloat->_mp_prec; i++ ) *d++ = 0;
3,726✔
428
                return(0);
429
        }
430
        else if ( *f == -SNUMBER ) {
17,208✔
431
                *d++ = (mp_limb_t)f[1];
1,944✔
432
                for ( i = 0; i < outfloat->_mp_prec; i++ ) *d++ = 0;
5,832✔
433
                return(0);
434
        }
435
        num = (*f-ARGHEAD-2)/2; /* 2*number of limbs in the argument */
15,264✔
436
        t = (UWORD *)(f+ARGHEAD+1);
15,264✔
437
        while ( num > 1 ) {
48,954✔
438
                *d++ = (mp_limb_t)((((ULONG)(t[1]))<<BITSINWORD)+t[0]);
33,690✔
439
                t += 2; num -= 2;
33,690✔
440
        }
441
        if ( num == 1 ) *d++ = (mp_limb_t)((UWORD)(*t));
15,264✔
442
        for ( i = d-outfloat->_mp_d; i <= outfloat->_mp_prec; i++ ) *d++ = 0;
19,896✔
443
        return(0);
444
Incorrect:
18,450✔
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

456
int TestFloat(WORD *fun)
40,740✔
457
{
458
        WORD *fstop, *f, num, nnum, i;
40,740✔
459
        fstop = fun+fun[1];
40,740✔
460
        f = fun + FUNHEAD;
40,740✔
461
        num = 0;
40,740✔
462
/*
463
        Count arguments
464
*/
465
        while ( f < fstop ) { num++; NEXTARG(f); }
203,664✔
466
        if ( num != 4 ) return(0);
40,740✔
467
        f = fun + FUNHEAD;
40,728✔
468
        if ( *f != -SNUMBER ) return(0);
40,728✔
469
        if ( f[1] < 0 ) return(0);
40,716✔
470
        f += 2;
40,716✔
471
        if ( *f != -SNUMBER ) return(0);
40,716✔
472
        num = ABS(f[1]); /* number of limbs */
40,716✔
473
        f += 2;
40,716✔
474
        if ( *f == -SNUMBER ) { f += 2; }
40,716✔
475
        else {
476
                if ( *f != ARGHEAD+6 ) return(0);
648✔
477
                if ( ABS(f[ARGHEAD+5]) != 5 ) return(0);
648✔
478
                if ( f[ARGHEAD+3] != 1 ) return(0);
648✔
479
                if ( f[ARGHEAD+4] != 0 ) return(0);
648✔
480
                f += *f;
648✔
481
        }
482
        if ( num == 0 ) return(1);
40,716✔
483
        if ( *f == -SNUMBER ) { if ( num != 1 ) return(0); }
38,412✔
484
        else {
485
                nnum = (ABS(f[*f-1])-1)/2;
34,566✔
486
                if ( ( *f != 4*num+2+ARGHEAD ) && ( *f != 4*num+ARGHEAD ) ) return(0);
34,566✔
487
                if ( ( nnum != 2*num ) && ( nnum != 2*num-1 ) ) return(0);
34,566✔
488
                f += ARGHEAD+nnum+1;
34,566✔
489
                if ( f[0] != 1 ) return(0);
34,566✔
490
                for ( i = 1; i < nnum; i++ ) {
185,004✔
491
                        if ( f[i] != 0 ) return(0);
150,438✔
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

515
void FormtoZ(mpz_t z,UWORD *a,WORD na)
9,708✔
516
{
517
        int nlimbs, sgn = 1;
9,708✔
518
        mp_limb_t *d;
9,708✔
519
        UWORD *b = a;
9,708✔
520
        WORD nb = na;
9,708✔
521

522
        if ( nb == 0 ) {
9,708✔
523
                z->_mp_size = 0;
×
524
                z->_mp_d[0] = 0;
×
525
                return;
×
526
        }
527
        if ( nb < 0 ) { sgn = -1; nb = -nb; }
9,708✔
528
        nlimbs = (nb+1)/2;
9,708✔
529
        if ( mpz_cmp_si(z,0L) <= 1 ) {
9,708✔
530
                mpz_set_ui(z,10000000);
9,708✔
531
        }
532
        if ( z->_mp_alloc <= nlimbs ) {
9,708✔
533
                mpz_t zz;
9,708✔
534
                mpz_init(zz);
9,708✔
535
                while ( z->_mp_alloc <= nlimbs ) {
29,202✔
536
                        mpz_mul(zz,z,z);
19,494✔
537
                        mpz_set(z,zz);
19,494✔
538
                }
539
                mpz_clear(zz);
9,708✔
540
        }
541
        z->_mp_size = sgn*nlimbs;
9,708✔
542
        d = z->_mp_d;
9,708✔
543
        while ( nb > 1 ) {
10,284✔
544
                *d++ = (((mp_limb_t)(b[1]))<<BITSINWORD)+(mp_limb_t)(b[0]);
576✔
545
                b += 2; nb -= 2;
576✔
546
        }
547
        if ( nb == 1 ) { *d = (mp_limb_t)(*b); }
9,708✔
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

559
void ZtoForm(UWORD *a,WORD *na,mpz_t z)
1,434✔
560
{
561
        mp_limb_t *d = z->_mp_d;
1,434✔
562
        int nlimbs = ABS(z->_mp_size), i;
1,434✔
563
        UWORD j;
1,434✔
564
        if ( nlimbs == 0 ) { *na = 0; return; }
1,434✔
565
        *na = 0;
1,434✔
566
        for ( i = 0; i < nlimbs-1; i++ ) {
1,488✔
567
                *a++ = (UWORD)(*d);
54✔
568
                *a++ = (UWORD)((*d++)>>BITSINWORD);
54✔
569
                *na += 2;
54✔
570
        }
571
        *na += 1;
1,434✔
572
        *a++ = (UWORD)(*d);
1,434✔
573
        j = (UWORD)((*d)>>BITSINWORD);
1,434✔
574
        if ( j != 0 ) { *a = j; *na += 1; }
1,434✔
575
        if ( z->_mp_size < 0 ) *na = -*na;
1,434✔
576
}
577

578
/*
579
                 #] ZtoForm : 
580
                 #[ FloatToInteger :
581

582
                Converts a GMP float to a long Form integer.
583
*/
584

585
long FloatToInteger(UWORD *out, mpf_t floatin, long *bitsused)
1,434✔
586
{
587
        mpz_t z;
1,434✔
588
        WORD nout, nx;
1,434✔
589
        UWORD x;
1,434✔
590
        mpz_init(z);
1,434✔
591
        mpz_set_f(z,floatin);
1,434✔
592
        ZtoForm(out,&nout,z);
1,434✔
593
        mpz_clear(z);
1,434✔
594
        x = out[nout-1]; nx = 0;
1,434✔
595
        while ( x ) { nx++; x >>= 1; }
9,012✔
596
        *bitsused = (nout-1)*BITSINWORD + nx;
1,434✔
597
        return(nout);
1,434✔
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

608
void IntegerToFloat(mpf_t result, UWORD *formlong, int longsize)
9,456✔
609
{
610
        mpz_t z;
9,456✔
611
        mpz_init(z);
9,456✔
612
        FormtoZ(z,formlong,longsize);
9,456✔
613
        mpf_set_z(result,z);
9,456✔
614
        mpz_clear(z);
9,456✔
615
}
9,456✔
616

617
/*
618
                 #] IntegerToFloat : 
619
                 #[ RatToFloat :
620

621
                Converts a Form rational to a gmp float of default size.
622
*/
623

624
void RatToFloat(mpf_t result, UWORD *formrat, int ratsize)
4,728✔
625
{
626
        GETIDENTITY
3,152✔
627
        int nnum, nden;
4,728✔
628
        UWORD *num, *den;
4,728✔
629
        int sgn = 0;
4,728✔
630
        if ( ratsize < 0 ) { ratsize = -ratsize; sgn = 1; }
4,728✔
631
        nnum = nden = (ratsize-1)/2;
4,728✔
632
        num = formrat; den = formrat+nnum;
4,728✔
633
        while ( num[nnum-1] == 0 ) { nnum--; }
5,610✔
634
        while ( den[nden-1] == 0 ) { nden--; }
4,818✔
635
        IntegerToFloat(aux2,num,nnum);
4,728✔
636
        IntegerToFloat(aux3,den,nden);
4,728✔
637
        mpf_div(result,aux2,aux3);
4,728✔
638
        if ( sgn > 0 ) mpf_neg(result,result);
4,728✔
639
}
4,728✔
640

641
/*
642
                 #] RatToFloat : 
643
                 #[ FloatFunToRat :
644
*/
645

646
WORD 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

672
int FloatToRat(UWORD *ratout, WORD *nratout, mpf_t floatin)
240✔
673
{
674
        GETIDENTITY
160✔
675
        WORD *out = AT.WorkPointer;
240✔
676
        WORD s; /* the sign. */
240✔
677
        UWORD *a, *b, *c, *d, *mc;
240✔
678
        WORD na, nb, nc, nd, i;
240✔
679
        int nout;
240✔
680
        LONG oldpWorkPointer = AT.pWorkPointer;
240✔
681
        long bitsused = 0, totalbitsused = 0, totalbits = AC.DefaultPrecision-AC.MaxWeight-1;
240✔
682
        int retval = 0, startnul;
240✔
683
        WantAddPointers(AC.DefaultPrecision);  /* Horrible overkill */
284✔
684
        AT.pWorkSpace[AT.pWorkPointer++] = out;
240✔
685
        a = NumberMalloc("FloatToRat");
240✔
686
        b = NumberMalloc("FloatToRat");
240✔
687

688
        s = mpf_sgn(floatin);
240✔
689
        if ( s < 0 ) mpf_neg(floatin,floatin);
240✔
690

691
        Form_mpf_empty(aux1);
240✔
692
        Form_mpf_empty(aux2);
240✔
693
        Form_mpf_empty(aux3);
240✔
694

695
        mpf_trunc(aux1,floatin);     /* This should now be an integer */
240✔
696
        mpf_sub(aux2,floatin,aux1);  /* and this >= 0 */
240✔
697
        if ( mpf_sgn(aux1) == 0 ) { *out++ = 0; startnul = 1; }
240✔
698
        else {
699
                nout = FloatToInteger((UWORD *)out,aux1,&totalbitsused);
114✔
700
                out += nout;
114✔
701
                startnul = 0;
114✔
702
        }
703
        AT.pWorkSpace[AT.pWorkPointer++] = out;
240✔
704
        if ( mpf_sgn(aux2) ) {
240✔
705
          for(;;) {
2,412✔
706
                mpf_ui_div(aux3,1,aux2);
1,320✔
707
                mpf_trunc(aux1,aux3);
1,320✔
708
                mpf_sub(aux2,aux3,aux1);
1,320✔
709
                if ( mpf_sgn(aux1) == 0 ) { *out++ = 0; }
1,320✔
710
                else {
711
                        nout = FloatToInteger((UWORD *)out,aux1,&bitsused);
1,320✔
712
                        out += nout;
1,320✔
713
                }
714
                if ( bitsused > (totalbits-totalbitsused)/2 ) { break; }
1,320✔
715
                if ( mpf_sgn(aux2) == 0 ) {
1,098✔
716
                        /*if ( startnul == 1 )*/ AT.pWorkSpace[AT.pWorkPointer++] = out;
6✔
717
                        break;
6✔
718
                }
719
                totalbitsused += bitsused;
1,092✔
720
                AT.pWorkSpace[AT.pWorkPointer++] = out;
1,092✔
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 ) {
228✔
728
                *ratout++ = 0; *ratout++ = 1; *ratout = *nratout = 3;
6✔
729
                goto ret;
6✔
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]);
222✔
743
          na = 1; a[0] = 1;
222✔
744
          c = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
222✔
745
          nc = nb = ((UWORD *)out)-c;
222✔
746
          for ( i = 0; i < nb; i++ ) b[i] = c[i];
450✔
747
          mc = c = NumberMalloc("FloatToRat");
222✔
748
          while ( AT.pWorkPointer > oldpWorkPointer ) {
1,200✔
749
                d = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
1,098✔
750
                nd = (UWORD *)(AT.pWorkSpace[AT.pWorkPointer+1])-d; /* This is the x1 in the formula */
1,098✔
751
                if ( nd == 1 && *d == 0 ) break;
1,098✔
752
                c = a; a = b; b = c; nc = na; na = nb; nb = nc; /* 1/x2 */
978✔
753
                MulLong(d,nd,a,na,mc,&nc);
978✔
754
                AddLong(mc,nc,b,nb,b,&nb);
978✔
755
          }
756
          NumberFree(mc,"FloatToRat");
222✔
757
          if ( startnul == 0 ) {
222✔
758
                c = a; a = b; b = c; nc = na; na = nb; nb = nc;
102✔
759
          }
760
        }
761
        else {
762
                c = (UWORD *)(AT.pWorkSpace[oldpWorkPointer]);
12✔
763
                na = (UWORD *)out - c;
12✔
764
                for ( i = 0; i < na; i++ ) a[i] = c[i];
36✔
765
                b[0] = 1; nb = 1;
12✔
766
        }
767
/*
768
        Now we have the fraction in a/b. Create the rational and add the sign.
769
*/
770
        d = ratout;
234✔
771
        if ( na == nb ) {
234✔
772
                *nratout = (2*na+1)*s;
222✔
773
                for ( i = 0; i < na; i++ ) *d++ = a[i];
468✔
774
                for ( i = 0; i < nb; i++ ) *d++ = b[i];
468✔
775
        }
776
        else if ( na < nb ) {
12✔
777
                *nratout = (2*nb+1)*s;
6✔
778
                for ( i = 0; i < na; i++ ) *d++ = a[i];
12✔
779
                for ( ; i < nb; i++ ) *d++ = 0;
12✔
780
                for ( i = 0; i < nb; i++ ) *d++ = b[i];
18✔
781
        }
782
        else {
783
                *nratout = (2*na+1)*s;
6✔
784
                for ( i = 0; i < na; i++ ) *d++ = a[i];
24✔
785
                for ( i = 0; i < nb; i++ ) *d++ = b[i];
12✔
786
                for ( ; i < na; i++ ) *d++ = 0;
18✔
787
        }
788
        *d = (UWORD)(*nratout);
234✔
789
        NumberFree(b,"FloatToRat");
234✔
790
        NumberFree(a,"FloatToRat");
234✔
791
        AT.pWorkPointer = oldpWorkPointer;
234✔
792
/*
793
        Just for check we go back to float
794
*/
795
        if ( s < 0 ) mpf_neg(floatin,floatin);
234✔
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
*/
804
ret:
234✔
805
        return(retval);
240✔
806
}
807

808
/*
809
                 #] FloatToRat : 
810
                 #[ ZeroTable :
811
*/
812
        
813
void ZeroTable(mpf_t *tab, int N)
552✔
814
{
815
        int i, j;
552✔
816
        for ( i = 0; i < N; i++ ) {
43,536✔
817
                for ( j = 0; j < tab[i]->_mp_prec; j++ ) tab[i]->_mp_d[j] = 0;
171,936✔
818
        }
819
}
552✔
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

831
SBYTE *ReadFloat(SBYTE *s)
1,572✔
832
{
833
        GETIDENTITY
1,048✔
834
        SBYTE *ss, c;
1,572✔
835
        ss = s;
1,572✔
836
        while ( *ss > 0 ) ss++;
17,280✔
837
        c = *ss; *ss = 0;
1,572✔
838
        gmp_sscanf((char *)s,"%Ff",aux1);
1,572✔
839
        if ( AT.WorkPointer > AT.WorkTop ) {
1,572✔
UNCOV
840
                MLOCK(ErrorMessageLock);
×
UNCOV
841
                MesWork();
×
842
                MUNLOCK(ErrorMessageLock);
843
                Terminate(-1);
1,572✔
844
        }
845
        PackFloat(AT.WorkPointer,aux1);
1,572✔
846
        *ss = c;
1,572✔
847
        return(ss);
1,572✔
848
}
849

850
/*
851
                 #] ReadFloat : 
852
                 #[ CheckFloat :
853

854
        For the tokenizer. Tests whether the input string can be a float.
855
*/
856

857
UBYTE *CheckFloat(UBYTE *ss, int *spec)
13,688,792✔
858
{
859
        GETIDENTITY
9,125,864✔
860
        UBYTE *s = ss;
13,688,792✔
861
        int gotdot = 0;
13,688,792✔
862
        /* A single dot is not a valid float */
863
        if ( *s == '.' && FG.cTable[s[-1]] != 1 && FG.cTable[s[1]] != 1 ) return(ss);
13,688,792✔
864
        while ( FG.cTable[s[-1]] == 1 ) s--;
35,779,912✔
865
        /* This cannot be a valid float */
866
        if ( *s != '.' && FG.cTable[*s] != 1 ) return(ss);
13,688,792✔
867
        *spec = 0;
13,688,792✔
868
        while ( FG.cTable[*s] == 1 ) s++;
36,173,008✔
869
        if ( *s == '.' ) {
13,688,792✔
870
                gotdot = 1;
1,554✔
871
                s++;
1,554✔
872
                while ( FG.cTable[*s] == 1 ) s++;
5,106✔
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' ) {
13,688,792✔
879
                s++;
876✔
880
                if ( *s == '-' || *s == '+' ) s++;
876✔
881
                if ( FG.cTable[*s] == 1 ) {
876✔
882
                        s++;
876✔
883
                        while ( FG.cTable[*s] == 1 ) s++;
7,662✔
884
                }
885
                else { return(ss); }
886
        }
887
        else if ( gotdot == 0 ) return(ss); /* No radix point and no exponent */
13,687,916✔
888
        if ( AT.aux_ == 0 ) { /* no floating point system */
1,578✔
889
                *spec = -1;
6✔
890
                return(s);
6✔
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

910
int SetFloatPrecision(WORD prec)
528✔
911
{
912
        if ( prec <= 0 ) {
528✔
UNCOV
913
                MesPrint("&Illegal value for number of bits for floating point constants: %d",prec);
×
UNCOV
914
                return(-1);
×
915
        }
916
        else {
917
                AC.DefaultPrecision = prec;
528✔
918
                if ( AO.floatspace != 0 ) M_free(AO.floatspace,"floatspace");
528✔
919
                AO.floatsize = (prec+20)*sizeof(char);
528✔
920
                AO.floatspace = (UBYTE *)Malloc1(AO.floatsize,"floatspace");
528✔
921
                mpf_set_default_prec(prec);
528✔
922
                return(0);
528✔
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

939
int PrintFloat(WORD *fun,int numdigits)
4,914✔
940
{
941
        GETIDENTITY
3,276✔
942
        UBYTE *s1, *s2;
4,914✔
943
        int n = 0;
4,914✔
944
        int prec = (AC.DefaultPrecision-AC.MaxWeight-1)*log10(2.0);
4,914✔
945
        if ( numdigits > prec || numdigits == 0 ) {
4,914✔
946
                numdigits = prec;
4,626✔
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 )
4,914✔
953
                n = gmp_snprintf((char *)(AO.floatspace),AO.floatsize,"%.*Fe",numdigits-1,aux4);
4,914✔
954
        if ( n > 0 ) {
4,914✔
955
                int n1, n2 = n;
4,914✔
956
                s1 = AO.floatspace+n;
4,914✔
957
                while ( s1 > AO.floatspace && s1[-1] != 'e'
30,576✔
958
                 && s1[-1] != 'E' && s1[-1] != '.' ) { s1--; n2--; }
25,662✔
959
                if ( s1 > AO.floatspace && s1[-1] != '.' ) {
4,914✔
960
                        s1--; n2--;
4,914✔
961
                        s2 = s1; n1 = n2;
4,914✔
962
                        while ( s1[-1] == '0' ) { s1--; n1--; }
32,574✔
963
                        if ( s1[-1] == '.' ) { s1++; n1++; }
4,914✔
964
                        n -= (n2-n1);
4,914✔
965
                        while ( n1 < n ) { *s1++ = *s2++; n1++; }
30,576✔
966
                        *s1 = 0;
4,914✔
967
                }
968
                if ( AC.OutputMode == FORTRANMODE ) {
4,914✔
969
                        s1 = AO.floatspace+n;
720✔
970
                        while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) { 
3,600✔
971
                                s1--; 
2,880✔
972
                        }
973
                        if ( ( AO.DoubleFlag & 2 ) == 2 ) { *s1 = 'Q'; } /* Quadruple precision fortran */
720✔
974
                        else if ( ( AO.DoubleFlag & 1 ) == 1 ) { *s1 = 'D'; } /* Double precision fortran */
576✔
975
                        else { *s1 = 'E'; } /* Single precision fortran */
432✔
976
                }
977
                if ( AC.OutputMode == MATHEMATICAMODE ) {
4,914✔
978
                        s1 = AO.floatspace+n;
144✔
979
                        s2 = s1+2; *s2-- = 0;
144✔
980
                        while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) { 
720✔
981
                                *s2-- = *s1--; 
576✔
982
                        }
983
                        *s2-- = '^'; *s2 = '*'; /* Replace 'e' by '^*' */
144✔
984
                        n++;
144✔
985
                }
986
        }
987
        return(n);
4,914✔
988
}
989

990
/*
991
                 #] PrintFloat : 
992
                 #[ AddFloats :
993
*/
994

995
int AddFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
×
996
{
UNCOV
997
        int retval = 0;
×
998
        if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
×
UNCOV
999
                mpf_add(aux1,aux1,aux2);
×
UNCOV
1000
                PackFloat(fun3,aux1);
×
1001
        }
1002
        else { retval = -1; }
UNCOV
1003
        return(retval);
×
1004
}
1005

1006
/*
1007
                 #] AddFloats : 
1008
                 #[ MulFloats :
1009
*/
1010

1011
int MulFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
×
1012
{
UNCOV
1013
        int retval = 0;
×
1014
        if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
×
UNCOV
1015
                mpf_mul(aux1,aux1,aux2);
×
UNCOV
1016
                PackFloat(fun3,aux1);
×
1017
        }
1018
        else { retval = -1; }
UNCOV
1019
        return(retval);
×
1020
}
1021

1022
/*
1023
                 #] MulFloats : 
1024
                 #[ DivFloats :
1025
*/
1026

1027
int DivFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
×
1028
{
UNCOV
1029
        int retval = 0;
×
1030
        if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
×
UNCOV
1031
                mpf_div(aux1,aux1,aux2);
×
UNCOV
1032
                PackFloat(fun3,aux1);
×
1033
        }
1034
        else { retval = -1; }
UNCOV
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

1045
int AddRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat)
×
1046
{
UNCOV
1047
        int retval = 0;
×
UNCOV
1048
        if ( UnpackFloat(aux2,infun) == 0 ) {
×
1049
                RatToFloat(aux1,formrat,nrat);
×
UNCOV
1050
                mpf_add(aux2,aux2,aux1);
×
UNCOV
1051
                PackFloat(outfun,aux2);
×
1052
        }
1053
        else retval = -1;
UNCOV
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

1064
int MulRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat)
×
1065
{
UNCOV
1066
        int retval = 0;
×
UNCOV
1067
        if ( UnpackFloat(aux2,infun) == 0 ) {
×
1068
                RatToFloat(aux1,formrat,nrat);
×
UNCOV
1069
                mpf_mul(aux2,aux2,aux1);
×
UNCOV
1070
                PackFloat(outfun,aux2);
×
1071
        }
1072
        else retval = -1;
UNCOV
1073
        return(retval);
×
1074
}
1075

1076
/*
1077
                 #] MulRatToFloat : 
1078
                 #[ SetupMZVTables :
1079
*/
1080

1081
void SetupMZVTables(void)
246✔
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;
164✔
1094
        size_t N;
164✔
1095
        mpf_t *a;
164✔
1096
        Nw = AC.DefaultPrecision;
164✔
1097
        N = (size_t)Nw;
164✔
1098
        totnum = AM.totalnumberofthreads;
164✔
1099
    for ( id = 0; id < totnum; id++ ) {
820✔
1100
                AB[id]->T.mpf_tab1 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab1");
656✔
1101
                a = (mpf_t *)AB[id]->T.mpf_tab1;
656✔
1102
                for ( i = 0; i <=Nw; i++ ) {
43,680✔
1103
/*
1104
        As explained in the comment above, we could make this variable precision
1105
        using mpf_init2.
1106
*/
1107
                        mpf_init(a[i]);
43,024✔
1108
                }
1109
                AB[id]->T.mpf_tab2 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab2");
656✔
1110
                a = (mpf_t *)AB[id]->T.mpf_tab2;
656✔
1111
                for ( i = 0; i <=Nw; i++ ) {
43,680✔
1112
                        mpf_init(a[i]);
43,024✔
1113
                }
1114
        }
1115
#else
1116
        int i, Nw;
82✔
1117
        size_t N;
82✔
1118
        Nw = AC.DefaultPrecision;
82✔
1119
        N = (size_t)Nw;
82✔
1120
        AT.mpf_tab1 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab1");
82✔
1121
        for ( i = 0; i <= Nw; i++ ) {
5,460✔
1122
/*
1123
        As explained in the comment above, we could make this variable precision
1124
        using mpf_init2.
1125
*/
1126
                mpf_init(mpftab1[i]);
5,378✔
1127
        }
1128
        AT.mpf_tab2 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab2");
82✔
1129
        for ( i = 0; i <= Nw; i++ ) {
5,460✔
1130
                mpf_init(mpftab2[i]);
5,378✔
1131
        }
1132
#endif
1133
        AS.delta_1 = (void *)Malloc1(sizeof(mpf_t),"delta1");
246✔
1134
        mpf_init(mpfdelta1);
246✔
1135
        SimpleDelta(mpfdelta1,1); /* this can speed up things. delta1 = ln(2) */
246✔
1136
}
246✔
1137

1138
/*
1139
                 #] SetupMZVTables : 
1140
                 #[ SetupMPFTables :
1141
        
1142
                Allocates the aux variables
1143
*/
1144

1145
void SetupMPFTables(void)
528✔
1146
{
1147
#ifdef WITHPTHREADS
1148
        int id, totnum;
352✔
1149
        mpf_t *a;
352✔
1150
#ifdef WITHSORTBOTS
1151
        totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
352✔
1152
#endif
1153
    for ( id = 0; id < totnum; id++ ) {
2,112✔
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_");
1,760✔
1159
                a = (mpf_t *)AB[id]->T.aux_;
1,760✔
1160
                mpf_inits(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
1,760✔
1161
                if ( AB[id]->T.indi1 ) M_free(AB[id]->T.indi1,"indi1");
1,760✔
1162
                AB[id]->T.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
1,760✔
1163
                AB[id]->T.indi2 = AB[id]->T.indi1 + AC.MaxWeight;
1,760✔
1164
        }
1165
#else
1166
        AT.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AT.aux_");
176✔
1167
        mpf_inits(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
176✔
1168
        if ( AT.indi1 ) M_free(AT.indi1,"indi1");
176✔
1169
        AT.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
176✔
1170
        AT.indi2 = AT.indi1 + AC.MaxWeight;
176✔
1171
#endif
1172
}
528✔
1173

1174
/*
1175
                 #] SetupMPFTables : 
1176
                 #[ ClearMZVTables :
1177
*/
1178

1179
void ClearMZVTables(void)
258✔
1180
{
1181
#ifdef WITHPTHREADS
1182
        int i, id, totnum;
172✔
1183
        mpf_t *a;
172✔
1184
        totnum = AM.totalnumberofthreads;
172✔
1185
    for ( id = 0; id < totnum; id++ ) {
860✔
1186
                if ( AB[id]->T.mpf_tab1 ) { 
688✔
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;
39,344✔
1192
                        for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
39,344✔
1193
                                mpf_clear(a[i]);
38,784✔
1194
                        }
1195
                        M_free(AB[id]->T.mpf_tab1,"mpftab1"); 
560✔
1196
                        AB[id]->T.mpf_tab1 = 0; 
560✔
1197
                }
1198
                if ( AB[id]->T.mpf_tab2 ) { 
688✔
1199
                        a = (mpf_t *)AB[id]->T.mpf_tab2;
39,344✔
1200
                        for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
39,344✔
1201
                                mpf_clear(a[i]);
38,784✔
1202
                        }
1203
                        M_free(AB[id]->T.mpf_tab2,"mpftab2"); 
560✔
1204
                        AB[id]->T.mpf_tab2 = 0; 
560✔
1205
                }
1206
        }
1207
#ifdef WITHSORTBOTS
1208
        totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
172✔
1209
#endif
1210
    for ( id = 0; id < totnum; id++ ) {
1,032✔
1211
                if ( AB[id]->T.aux_ ) { 
860✔
1212
                        a = (mpf_t *)AB[id]->T.aux_;
860✔
1213
                        mpf_clears(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
860✔
1214
                        M_free(AB[id]->T.aux_,"AB[id]->T.aux_");
860✔
1215
                        AB[id]->T.aux_ = 0; 
860✔
1216
                }
1217
                if ( AB[id]->T.indi1 ) { M_free(AB[id]->T.indi1,"indi1"); AB[id]->T.indi1 = 0; }
860✔
1218
        }
1219
#else
1220
        int i;
86✔
1221
        if ( AT.mpf_tab1 ) { 
86✔
1222
                for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
4,918✔
1223
                        mpf_clear(mpftab1[i]);
4,848✔
1224
                }
1225
                M_free(AT.mpf_tab1,"mpftab1"); 
70✔
1226
                AT.mpf_tab1 = 0; 
70✔
1227
        }
1228
        if ( AT.mpf_tab2 ) { 
86✔
1229
                for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
4,918✔
1230
                        mpf_clear(mpftab2[i]);
4,848✔
1231
                }
1232
                M_free(AT.mpf_tab2,"mpftab2"); 
70✔
1233
                AT.mpf_tab2 = 0; 
70✔
1234
        }
1235
        if ( AT.aux_ ) { 
86✔
1236
                mpf_clears(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
86✔
1237
                M_free(AT.aux_,"AT.aux_"); 
86✔
1238
                AT.aux_ = 0; 
86✔
1239
        }
1240
        if ( AT.indi1 ) { M_free(AT.indi1,"indi1"); AT.indi1 = 0; }
86✔
1241
#endif
1242
        if ( AO.floatspace ) { M_free(AO.floatspace,"floatspace"); AO.floatspace = 0;
258✔
1243
                AO.floatsize = 0; }
258✔
1244
        if ( AS.delta_1 ) { 
258✔
1245
                mpf_clear(mpfdelta1);
210✔
1246
                M_free(AS.delta_1,"delta1"); 
210✔
1247
                AS.delta_1 = 0; 
210✔
1248
        }
1249
}
258✔
1250

1251
/*
1252
                 #] ClearMZVTables : 
1253
                 #[ CoToFloat :
1254
*/
1255

1256
int CoToFloat(UBYTE *s)
48✔
1257
{
1258
        GETIDENTITY
32✔
1259
        if ( AT.aux_ == 0 ) {
48✔
1260
                MesPrint("&Illegal attempt to convert to float_ without activating floating point numbers.");
6✔
1261
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
1262
                return(1);
6✔
1263
        }
1264
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
42✔
1265
        if ( *s ) {
42✔
1266
                MesPrint("&Illegal argument(s) in ToFloat statement: '%s'",s);
6✔
1267
                return(1);
6✔
1268
        }
1269
        Add2Com(TYPETOFLOAT);
36✔
1270
        return(0);
36✔
1271
}
1272

1273
/*
1274
                 #] CoToFloat : 
1275
                 #[ CoToRat :
1276
*/
1277

1278
int CoToRat(UBYTE *s)
30✔
1279
{
1280
        GETIDENTITY
20✔
1281
        if ( AT.aux_ == 0 ) {
30✔
1282
                MesPrint("&Illegal attempt to convert from float_ without activating floating point numbers.");
6✔
1283
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
1284
                return(1);
6✔
1285
        }
1286
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
24✔
1287
        if ( *s ) {
24✔
1288
                MesPrint("&Illegal argument(s) in ToRat statement: '%s'",s);
6✔
1289
                return(1);
6✔
1290
        }
1291
        Add2Com(TYPETORAT);
18✔
1292
        return(0);
18✔
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
*/
1305
int CoStrictRounding(UBYTE *s)
42✔
1306
{
1307
        GETIDENTITY
28✔
1308
        WORD x;
42✔
1309
        int base;
42✔
1310
        if ( AT.aux_ == 0 ) {
42✔
1311
                MesPrint("&Illegal attempt for strict rounding without activating floating point numbers.");
6✔
1312
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
1313
                return(1);
6✔
1314
        }
1315
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
36✔
1316
        if ( *s == 0 ) {
36✔
1317
                /* No subkey, which means round to default precision */
1318
                x = AC.DefaultPrecision - AC.MaxWeight - 1;
6✔
1319
                base = 2;
6✔
1320
        }
1321
        else if ( FG.cTable[*s] == 1 ) { /* number */
30✔
1322
                ParseNumber(x,s)
48✔
1323
                if ( tolower(*s) == 'd' ) { base = 10; s++; }      /* decimal base */
24✔
1324
                else if ( tolower(*s) == 'b' ){ base = 2; s++; }  /* binary base */
18✔
1325
                else goto IllPar;  /* invalid base specification */
12✔
1326
        }
1327
        else {
1328
                goto IllPar;
6✔
1329
        }
1330
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
18✔
1331
        
1332
        /* Check for invalid arguments */
1333
        if ( *s ) {
18✔
UNCOV
1334
IllPar:
×
1335
                MesPrint("&Illegal argument(s) in StrictRounding statement: '%s'",s);
18✔
1336
                return(1);
18✔
1337
        }
1338
        Add4Com(TYPESTRICTROUNDING,x,base);
18✔
1339
        return(0);
18✔
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

1352
int CoChop(UBYTE *s)
54✔
1353
{
1354
        GETIDENTITY
36✔
1355
        UBYTE *ss, c;
54✔
1356
        WORD *w, *OldWork;
54✔
1357
        int spec, pow = 1;
54✔
1358
        unsigned long x;
54✔
1359
        if ( AT.aux_ == 0 ) {
54✔
1360
                MesPrint("&Illegal attempt to chop a float_ without activating floating point numbers.");
6✔
1361
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
1362
                return(1);
6✔
1363
        }
1364
        if ( *s == 0 ) {
48✔
1365
                MesPrint("&Chop needs a number (float, rational or power) as an argument.");
6✔
1366
                return(1);
6✔
1367
        }
1368
        /* Create TYPECHOP header */
1369
        w = OldWork = AT.WorkPointer;
42✔
1370
        *w++ = TYPECHOP; 
42✔
1371
        w++;
42✔
1372

1373
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
42✔
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 == '.' ) { 
42✔
1381
                /* 1: Attempt to parse as floating-point number */
1382
                ss = CheckFloat(s, &spec);
42✔
1383
                if ( ss > s ) {
42✔
1384
                        /* CheckFloat found a valid float */
1385
                        AT.WorkPointer = w;
12✔
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); 
12✔
1391
                        s = ss;
12✔
1392
                        w += w[1];
12✔
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 ) {
30✔
1398
                                ParseNumber(x,s)
72✔
1399
                                mpf_set_ui(aux1,x);
30✔
1400
                        }
1401
                        while ( *s == ' ' || *s == '\t' ) s++;
30✔
1402
                        /* Check for rational number or power*/
1403
                        if ( *s == '/' || *s == '^' ) {
30✔
1404
                                c = *s; s++; 
24✔
1405
                                while ( *s == ' ' || *s == '\t' ) s++;
24✔
1406
                                if ( *s == '-' ) { s++; pow = -1; } /* negative power */
24✔
1407
                                /* Parse the denominator or power */
1408
                                if ( FG.cTable[*s] == 1 ) {
24✔
1409
                                        ParseNumber(x,s)
72✔
1410
                                        if ( c == '/' ) { /* rational */
24✔
1411
                                                if ( x == 0 ) {
12✔
1412
                                                        MesPrint("&Division by zero in chop statement.");
6✔
1413
                                                        return(1);
6✔
1414
                                                }
1415
                                                /* Perform the division */
1416
                                                mpf_div_ui(aux1, aux1,x);
6✔
1417
                                        }
1418
                                        else { /* Power */
1419
                                                mpf_pow_ui(aux1,aux1,x);
12✔
1420
                                                if ( pow == -1 ) {
12✔
1421
                                                        mpf_ui_div(aux1,(unsigned long) 1, aux1);
6✔
1422
                                                }
1423
                                        }
1424
                                }
1425
                        }
1426
                        /* Put aux1 in the notation of a float_ function */
1427
                        PackFloat(w, aux1);
24✔
1428
                        w += w[1];
24✔
1429
                }
1430
        }
1431
        if ( *s ) {
36✔
1432
                MesPrint("&Illegal argument(s) in Chop statement: '%s'.",s);
6✔
1433
                return(1);
6✔
1434
        }
1435
        AT.WorkPointer = OldWork;
30✔
1436
        AT.WorkPointer[1] = w - AT.WorkPointer;  /* Set total length */
30✔
1437
        AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
30✔
1438
        return(0);
30✔
1439
}
1440

1441
/*
1442
                 #] CoChop : 
1443
                 #[ ToFloat :
1444

1445
                Converts the coefficient to floating point if it is still a rat.
1446
*/
1447

1448
int ToFloat(PHEAD WORD *term, WORD level)
612✔
1449
{
1450
        WORD *t, *tstop, nsize, nsign = 3;
612✔
1451
        t = term+*term;
612✔
1452
        nsize = ABS(t[-1]);
612✔
1453
        tstop = t - nsize;
612✔
1454
        if ( t[-1] < 0 ) { nsign = -nsign; }
612✔
1455
        if ( nsize == 3 && t[-2] == 1 && t[-3] == 1 ) { /* Could be float */
612✔
1456
                t = term + 1;
246✔
1457
                while ( t < tstop ) {
480✔
1458
                        if ( ( *t == FLOATFUN ) && ( t+t[1] == tstop ) ) {
336✔
1459
                                return(Generator(BHEAD term,level));
102✔
1460
                        }
1461
                        t += t[1];
234✔
1462
                }
1463
        }
1464
        RatToFloat(aux4,(UWORD *)tstop,nsize);
510✔
1465
        PackFloat(tstop,aux4);
510✔
1466
        tstop += tstop[1];
510✔
1467
        *tstop++ = 1; *tstop++ = 1; *tstop++ = nsign;
510✔
1468
        *term = tstop - term;
510✔
1469
        AT.WorkPointer = tstop;
510✔
1470
        return(Generator(BHEAD term,level));
510✔
1471
}
1472

1473
/*
1474
                 #] ToFloat : 
1475
                 #[ ToRat :
1476

1477
                Tries to convert the coefficient to rational if it is still a float.
1478
*/
1479

1480
int ToRat(PHEAD WORD *term, WORD level)
468✔
1481
{
1482
        WORD *tstop, *t, nsize, nsign, ncoef;
468✔
1483
/*
1484
        1: find the float which should be at the end.
1485
*/
1486
        tstop = term + *term; nsize = ABS(tstop[-1]);
468✔
1487
        nsign = tstop[-1] < 0 ? -1: 1; tstop -= nsize;
468✔
1488
        t = term+1;
468✔
1489
        while ( t < tstop ) {
918✔
1490
                if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
696✔
1491
                nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
246✔
1492
                t += t[1];
450✔
1493
        }
1494
        if ( t < tstop ) {
468✔
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);
246✔
1500
                // If aux4 is zero, the term vanishes
1501
                if ( mpf_sgn(aux4) == 0 ) return(0);
246✔
1502
                if ( FloatToRat((UWORD *)t,&ncoef,aux4) == 0 ) {
240✔
1503
                        // Check if the resulting rational is zero
1504
                        if ( t[0] == 0 && t[1] == 1 && ncoef == 3 ) return(0);
240✔
1505
                        t += ABS(ncoef);
234✔
1506
                        t[-1] = ncoef*nsign;
234✔
1507
                        *term = t - term;
234✔
1508
                }
1509
        }
1510
        return(Generator(BHEAD term,level));
456✔
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
*/
1520
int StrictRounding(PHEAD WORD *term, WORD level, WORD prec, WORD base) {
36✔
1521
        WORD *t,*tstop;
36✔
1522
        int sign,size,maxprec = AC.DefaultPrecision-AC.MaxWeight-1;
36✔
1523
        /* maxprec is in bits */
1524
        if ( base == 2 && prec > maxprec ) {
36✔
1525
                prec = maxprec;
1526
        }
1527
        if ( base == 10 && prec > (int)(maxprec*log10(2.0)) ) {
36✔
UNCOV
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]);
36✔
1532
        sign = tstop[-1] < 0 ? -1: 1; tstop -= size;
36✔
1533
        t = term+1;
36✔
1534
        while ( t < tstop ) {
48✔
1535
                if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
36✔
1536
                size == 3 && tstop[0] == 1 && tstop[1] == 1) {
24✔
1537
                        break;
1538
                }
1539
                t += t[1];
12✔
1540
        }
1541
        if ( t < tstop ) {
36✔
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;
24✔
1547
                mp_exp_t exp;
24✔
1548
                /* Extract the floating point value */
1549
                UnpackFloat(aux4,t);
24✔
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;
24✔
1556
                *s++ = '.';
24✔
1557
                mpf_get_str(s,&exp, base, prec, aux4);
24✔
1558
                while ( *s != 0 ) s++;
90✔
1559
                *s++ = 'e';
24✔
1560
                snprintf(s,AO.floatsize-(s-(char *)AO.floatspace),"%ld",exp);
24✔
1561
                /* Negative base values are used to specify that the exponent is in decimal */
1562
                mpf_set_str(aux4,(char *)AO.floatspace,-base);
24✔
1563
                /* Pack the rounded floating point value back into the term */
1564
                PackFloat(t,aux4);
24✔
1565
                t+=t[1];
24✔
1566
                *t++ = 1; *t++ = 1; *t++ = 3*sign;
24✔
1567
                *term = t - term;
24✔
1568
        }
1569
        return(Generator(BHEAD term,level));
36✔
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
 */
1582
int Chop(PHEAD WORD *term, WORD level)
150✔
1583
{
1584
        WORD *tstop, *t, nsize, *threshold; 
150✔
1585
        CBUF *C = cbuf+AM.rbufnum;
150✔
1586
        /* Find the float which should be at the end. */
1587
        tstop = term + *term; 
150✔
1588
        nsize = ABS(tstop[-1]); tstop -= nsize;
150✔
1589
        t = term+1;
150✔
1590
        while ( t < tstop ) {
300✔
1591
                if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
270✔
1592
                nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
120✔
1593
                t += t[1];
150✔
1594
        }
1595
        if ( t < tstop ) {
150✔
1596
                /* Get threshold value from compiler buffer */
1597
                threshold = C->lhs[level];
120✔
1598
                threshold += 2;  /* Skip TYPECHOP header */
120✔
1599
                UnpackFloat(aux5, threshold); 
120✔
1600
                
1601
                /* Extract float and compute its absolute value */
1602
                UnpackFloat(aux4, t);
120✔
1603
                mpf_abs(aux4, aux4);
120✔
1604
                
1605
                /* Remove if < threshold */
1606
                if ( mpf_cmp(aux4, aux5) < 0 ) return(0);
120✔
1607
        }
1608
        return(Generator(BHEAD term,level));
66✔
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

1651
int AddWithFloat(PHEAD WORD **ps1, WORD **ps2)
2,712✔
1652
{
1653
        GETBIDENTITY
1654
        SORTING *S = AT.SS;
2,712✔
1655
        WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3;
2,712✔
1656
        WORD *s1,*s2,sign3,j,jj, *t1, *t2, i;
2,712✔
1657
        s1 = *ps1;
2,712✔
1658
        s2 = *ps2;
2,712✔
1659
        coef1 = s1+*s1; size1 = coef1[-1]; coef1 -= ABS(coef1[-1]);
2,712✔
1660
        coef2 = s2+*s2; size2 = coef2[-1]; coef2 -= ABS(coef2[-1]);
2,712✔
1661
        if ( AT.SortFloatMode == 3 ) {
2,712✔
1662
                fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
4,098✔
1663
                fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
4,098✔
1664
                UnpackFloat(aux1,fun1);
2,118✔
1665
                if ( size1 < 0 ) mpf_neg(aux1,aux1);
2,118✔
1666
                UnpackFloat(aux2,fun2);
2,118✔
1667
                if ( size2 < 0 ) mpf_neg(aux2,aux2);
2,118✔
1668
        }
1669
        else if ( AT.SortFloatMode == 1 ) {
594✔
1670
                fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
306✔
1671
                UnpackFloat(aux1,fun1);
156✔
1672
                if ( size1 < 0 ) mpf_neg(aux1,aux1);
156✔
1673
                fun2 = coef2;
156✔
1674
                RatToFloat(aux2,(UWORD *)coef2,size2);
156✔
1675
        }
1676
        else if ( AT.SortFloatMode == 2 ) {
438✔
1677
                fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
876✔
1678
                fun1 = coef1;
438✔
1679
                RatToFloat(aux1,(UWORD *)coef1,size1);
438✔
1680
                UnpackFloat(aux2,fun2);
438✔
1681
                if ( size2 < 0 ) mpf_neg(aux2,aux2);
438✔
1682
        }
1683
        else {
UNCOV
1684
                MLOCK(ErrorMessageLock);
×
UNCOV
1685
                MesPrint("Illegal value %d for AT.SortFloatMode in AddWithFloat.",AT.SortFloatMode);
×
UNCOV
1686
                MUNLOCK(ErrorMessageLock);
×
UNCOV
1687
                Terminate(-1);
×
1688
                return(0);
1689
        }
1690
        mpf_add(aux3,aux1,aux2);
2,712✔
1691
        sign3 = mpf_sgn(aux3);
2,712✔
1692
        if ( sign3 < 0 ) mpf_neg(aux3,aux3);
2,712✔
1693
        fun3 = TermMalloc("AddWithFloat");
2,712✔
1694
        PackFloat(fun3,aux3);
2,712✔
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 ) {
2,712✔
1706
                if ( fun1[1] == fun3[1]  ) {
2,118✔
1707
Over1:
738✔
1708
                        i = fun3[1]; t1 = fun1; t2 = fun3; NCOPY(t1,t2,i);
35,052✔
1709
                        *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
2,016✔
1710
                        *s1 = t1-s1; goto Finished;
2,016✔
1711
                }
1712
                else if ( fun2[1] == fun3[1]  ) {
1,380✔
1713
Over2:
240✔
1714
                        i = fun3[1]; t1 = fun2; t2 = fun3; NCOPY(t1,t2,i);
11,220✔
1715
                        *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
672✔
1716
                        *s2 = t1-s2; *ps1 = s2; goto Finished;
672✔
1717
                }
1718
                else if ( fun1[1] >= fun3[1]  ) goto Over1;
1,140✔
1719
                else if ( fun2[1] >= fun3[1]  ) goto Over2;
12✔
1720
        }
1721
        else if ( AT.SortFloatMode == 1 ) {
594✔
1722
                if ( fun1[1] >= fun3[1]  ) goto Over1;
156✔
1723
                else if ( fun3[1]+3 <= ABS(size2) ) goto Over2;
6✔
1724
        }
1725
        else if ( AT.SortFloatMode == 2 ) {
438✔
1726
                if ( fun2[1] >= fun3[1]  ) goto Over2;
438✔
1727
                else if ( fun3[1]+3 <= ABS(size1) ) goto Over1;
12✔
1728
        }
1729
/*
1730
        Does not fit. Go to extension space.
1731
*/
1732
        jj = fun1-s1;
24✔
1733
        j = jj+fun3[1]+3; /* space needed */
24✔
1734
        if ( (S->sFill + j) >= S->sTop2 ) {
24✔
UNCOV
1735
                GarbHand();
×
UNCOV
1736
                s1 = *ps1; /* new position of the term after the garbage collection */
×
UNCOV
1737
                fun1 = s1+jj;
×
1738
        }
1739
        t1 = S->sFill;
24✔
1740
        for ( i = 0; i < jj; i++ ) *t1++ = s1[i];
120✔
1741
        i = fun3[1]; s1 = fun3; NCOPY(t1,s1,i);
744✔
1742
        *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
24✔
1743
        *ps1 = S->sFill;
24✔
1744
        **ps1 = t1-*ps1;
24✔
1745
        S->sFill = t1;
24✔
1746
Finished:
2,712✔
1747
        *ps2 = 0;
2,712✔
1748
        TermFree(fun3,"AddWithFloat");
2,712✔
1749
        AT.SortFloatMode = 0;
2,712✔
1750
        if ( **ps1 > AM.MaxTer/((LONG)(sizeof(WORD))) ) {
2,712✔
UNCOV
1751
                MLOCK(ErrorMessageLock);
×
UNCOV
1752
                MesPrint("Term too complex after addition in sort. MaxTermSize = %10l",
×
UNCOV
1753
                AM.MaxTer/sizeof(WORD));
×
UNCOV
1754
                MUNLOCK(ErrorMessageLock);
×
UNCOV
1755
                Terminate(-1);
×
1756
        }
1757
        return(1);
2,712✔
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

1769
int MergeWithFloat(PHEAD WORD **interm1, WORD **interm2)
2,208✔
1770
{
1771
        GETBIDENTITY
1772
        WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3, *tt;
2,208✔
1773
        WORD sign3,jj, *t1, *t2, i, *term1 = *interm1, *term2 = *interm2;
2,208✔
1774
        int retval = 0;
2,208✔
1775
        coef1 = term1+*term1; size1 = coef1[-1]; coef1 -= ABS(size1);
2,208✔
1776
        coef2 = term2+*term2; size2 = coef2[-1]; coef2 -= ABS(size2);
2,208✔
1777
        if ( AT.SortFloatMode == 3 ) {
2,208✔
1778
                fun1 = term1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
3,156✔
1779
                fun2 = term2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
3,156✔
1780
                UnpackFloat(aux1,fun1);
1,578✔
1781
                if ( size1 < 0 ) mpf_neg(aux1,aux1);
1,578✔
1782
                UnpackFloat(aux2,fun2);
1,578✔
1783
                if ( size2 < 0 ) mpf_neg(aux2,aux2);
1,578✔
1784
        }
1785
        else if ( AT.SortFloatMode == 1 ) {
630✔
1786
                fun1 = term1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
624✔
1787
                UnpackFloat(aux1,fun1);
312✔
1788
                if ( size1 < 0 ) mpf_neg(aux1,aux1);
312✔
1789
                fun2 = coef2;
312✔
1790
                RatToFloat(aux2,(UWORD *)coef2,size2);
312✔
1791
        }
1792
        else if ( AT.SortFloatMode == 2 ) {
318✔
1793
                fun2 = term2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
636✔
1794
                fun1 = coef1;
318✔
1795
                RatToFloat(aux1,(UWORD *)coef1,size1);
318✔
1796
                UnpackFloat(aux2,fun2);
318✔
1797
                if ( size2 < 0 ) mpf_neg(aux2,aux2);
318✔
1798
        }
1799
        else {
UNCOV
1800
                MLOCK(ErrorMessageLock);
×
UNCOV
1801
                MesPrint("Illegal value %d for AT.SortFloatMode in MergeWithFloat.",AT.SortFloatMode);
×
UNCOV
1802
                MUNLOCK(ErrorMessageLock);
×
UNCOV
1803
                Terminate(-1);
×
1804
                return(0);
1805
        }
1806
        mpf_add(aux3,aux1,aux2);
2,208✔
1807
        sign3 = mpf_sgn(aux3);
2,208✔
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);
2,208✔
1812
        fun3 = TermMalloc("MergeWithFloat");
2,208✔
1813
        PackFloat(fun3,aux3);
2,208✔
1814
        if ( AT.SortFloatMode == 3 ) {
2,208✔
1815
                if ( fun1[1] + ABS(size1) == fun3[1] + 3 ) {
1,578✔
1816
OnTopOf1:        t1 = fun3; t2 = fun1;
570✔
1817
                        for ( i = 0; i < fun3[1]; i++ ) *t2++ = *t1++;
7,512✔
1818
                        *t2++ = 1; *t2++ = 1; *t2++ = sign3 < 0 ? -3: 3;
588✔
1819
                        retval = 1;
588✔
1820
                }
1821
                else if ( fun1[1] + ABS(size1) > fun3[1] + 3 ) {
1,008✔
1822
Shift1:                t2 = term1 + *term1; tt = t2;
966✔
1823
                        *--t2 = sign3 < 0 ? -3: 3; *--t2 = 1; *--t2 = 1;
1,254✔
1824
                        t1 = fun3 + fun3[1]; for ( i = 0; i < fun3[1]; i++ ) *--t2 = *--t1;
19,080✔
1825
                        t1 = fun1;
1826
                        while ( t1 > term1 ) *--t2 = *--t1;
10,752✔
1827
                        *t2 = tt-t2; term1 = t2;
1,254✔
1828
                        retval = 1;
1,254✔
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 */
42✔
1832
Over1:                t2 = term1-jj; t1 = term1;
366✔
1833
                        while ( t1 < fun1 ) *t2++ = *t1++;
3,012✔
1834
                        term1 -= jj;
366✔
1835
                        *term1 += jj;
366✔
1836
                        for ( i = 0; i < fun3[1]; i++ ) *t2++ = fun3[i];
5,568✔
1837
                        *t2++ = 1; *t2++ = 1;  *t2++ = sign3 < 0 ? -3: 3;
366✔
1838
                        retval = 1;
366✔
1839
                }
1840
        }
1841
        else if ( AT.SortFloatMode == 1 ) {
630✔
1842
                if ( fun1[1] + ABS(size1) == fun3[1] + 3 ) goto OnTopOf1;
312✔
1843
                else if ( fun1[1] + ABS(size1) > fun3[1] + 3 ) goto Shift1;
294✔
1844
                else {
1845
                        jj = fun3[1]-fun1[1]+3-ABS(size1); /* This is positive */
12✔
1846
                        goto Over1;
12✔
1847
                }
1848
        }
1849
        else { /* Can only be 2, based on previous tests */
1850
                if ( fun3[1] + 3 == ABS(size1) ) goto OnTopOf1;
318✔
1851
                else if ( fun3[1] + 3 < ABS(size1) ) goto Shift1;
318✔
1852
                else {
1853
                        jj = fun3[1]+3-ABS(size1); /* This is positive */
312✔
1854
                        goto Over1;
312✔
1855
                }
1856
        }
1857
        *interm1 = term1;
2,208✔
1858
        TermFree(fun3,"MergeWithFloat");
2,208✔
1859
        AT.SortFloatMode = 0;
2,208✔
1860
        return(retval);
2,208✔
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

1880
void SimpleDelta(mpf_t sum, int m)
2,940✔
1881
{
1882
        long s = 1;
2,940✔
1883
        long prec = AC.DefaultPrecision;
2,940✔
1884
        unsigned long xprec = (unsigned long)prec, x;
2,940✔
1885
        int j, jmax, n;
2,940✔
1886
        mpf_t jm,jjm;
2,940✔
1887
        mpf_init(jm); mpf_init(jjm);
2,940✔
1888
        if ( m < 0 ) { s = -1; m = -m; }
2,940✔
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;
2,940✔
1899
        while ( x ) { x >>= 1; n++; }
27,252✔
1900
/* 
1901
        We have now n = floor(log2(x))+1. 
1902
*/
1903
        n--;
2,940✔
1904
        jmax = (int)((int)xprec - (n-1)*m);
2,940✔
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;
2,940✔
1910
        do {
2,940✔
1911
                n = 0;
2,940✔
1912
                x = (unsigned long)jmax;
2,940✔
1913
                while (x) { x >>= 1; n++; }
25,560✔
1914
                n--; // floor(log2(jmax))
2,940✔
1915
                jmax++; 
2,940✔
1916
        } while ( jmax + m * n <= prec );
2,940✔
1917
        mpf_set_ui(sum,0);
2,940✔
1918
        for ( j = 1; j <= jmax; j++ ) {
796,236✔
1919
#ifdef WITHCUTOFF
1920
                xprec--;
790,356✔
1921
                mpf_set_prec_raw(jm,xprec);
790,356✔
1922
                mpf_set_prec_raw(jjm,xprec);
790,356✔
1923
#endif
1924
                mpf_set_ui(jm,1L);
790,356✔
1925
                mpf_div_ui(jjm,jm,(unsigned long)j);
790,356✔
1926
                mpf_pow_ui(jm,jjm,(unsigned long)m);
790,356✔
1927
                mpf_div_2exp(jjm,jm,(unsigned long)j);
790,356✔
1928
                if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jjm);
790,356✔
1929
                else                       mpf_add(sum,sum,jjm);
781,608✔
1930
        }
1931
        mpf_clear(jjm); mpf_clear(jm);
2,940✔
1932
}
2,940✔
1933

1934
/*
1935
                 #] SimpleDelta : 
1936
                 #[ SimpleDeltaC :
1937
*/
1938

1939
void SimpleDeltaC(mpf_t sum, int m)
240✔
1940
{
1941
        long s = 1;
240✔
1942
        long prec = AC.DefaultPrecision;
240✔
1943
        unsigned long xprec = (unsigned long)prec, x;
240✔
1944
        int j, jmax, n;
240✔
1945
        mpf_t jm,jjm;
240✔
1946
        mpf_init(jm); mpf_init(jjm);
240✔
1947
        if ( m < 0 ) { s = -1; m = -m; }
240✔
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;
240✔
1957
        while ( x ) { x >>= 1; n++; }
1,920✔
1958
/* 
1959
        We have now n = floor(log2(x))+1. 
1960
*/
1961
        n--;
240✔
1962
        jmax = (int)((int)xprec - (n-1)*m);
240✔
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;
240✔
1968
        do {
240✔
1969
                n = 0;
240✔
1970
                x = (unsigned long)jmax;
240✔
1971
                while (x) { x >>= 1; n++; }
1,908✔
1972
                n--; // floor(log2(jmax))
240✔
1973
                jmax++; 
240✔
1974
        } while ( jmax + m * n <= prec );
240✔
1975
        if ( s < 0 ) jmax /= 2;
240✔
1976
        mpf_set_si(sum,0L);
240✔
1977
        for ( j = 1; j <= jmax; j++ ) {
9,084✔
1978
#ifdef WITHCUTOFF
1979
                xprec--;
8,604✔
1980
                mpf_set_prec_raw(jm,xprec);
8,604✔
1981
                mpf_set_prec_raw(jjm,xprec);
8,604✔
1982
#endif
1983
                mpf_set_ui(jm,1L);
8,604✔
1984
                mpf_div_ui(jjm,jm,(unsigned long)j);
8,604✔
1985
                mpf_pow_ui(jm,jjm,(unsigned long)m);
8,604✔
1986
                if ( s == -1 ) mpf_div_2exp(jjm,jm,2*(unsigned long)j);
8,604✔
UNCOV
1987
                else           mpf_div_2exp(jjm,jm,(unsigned long)j);
×
1988
                mpf_add(sum,sum,jjm);
8,604✔
1989
        }
1990
        mpf_clear(jjm); mpf_clear(jm);
240✔
1991
}
240✔
1992

1993
/*
1994
                 #] SimpleDeltaC : 
1995
                 #[ SingleTable :
1996
*/
1997

1998
void SingleTable(mpf_t *tabl, int N, int m, int pow)
3,606✔
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
2,404✔
2012
        long s = 1;
3,606✔
2013
        int j;
3,606✔
2014
#ifdef WITHCUTOFF
2015
        long prec = mpf_get_default_prec();
3,606✔
2016
#endif
2017
        mpf_t jm,jjm;
3,606✔
2018
        mpf_init(jm); mpf_init(jjm);
3,606✔
2019
        if ( pow < 1 || pow > 2 ) {
3,606✔
UNCOV
2020
                MLOCK(ErrorMessageLock);
×
UNCOV
2021
                MesPrint("Wrong parameter pow in SingleTable: %d\n",pow);
×
UNCOV
2022
                MUNLOCK(ErrorMessageLock);
×
UNCOV
2023
                Terminate(-1);
×
2024
        }
2025
        if ( m < 0 ) { m = -m; s = -1; }
3,606✔
2026
        mpf_set_si(auxsum,0L);
3,606✔
2027
        for ( j = N; j > 0; j-- ) {
779,850✔
2028
#ifdef WITHCUTOFF
2029
                mpf_set_prec_raw(jm,prec-j);
772,638✔
2030
                mpf_set_prec_raw(jjm,prec-j);
772,638✔
2031
#endif
2032
                mpf_set_ui(jm,1L);
772,638✔
2033
                mpf_div_ui(jjm,jm,(unsigned long)j);
772,638✔
2034
                mpf_pow_ui(jm,jjm,(unsigned long)m);
772,638✔
2035
                mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
772,638✔
2036
                if ( pow == 2 ) mpf_add(auxsum,auxsum,jjm);
772,638✔
2037
                else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jjm);
740,982✔
2038
                else                       mpf_add(auxsum,auxsum,jjm);
725,286✔
2039
/*
2040
                And now copy auxsum to tablelement j
2041
*/
2042
                mpf_set(tabl[j],auxsum);
772,638✔
2043
        }
2044
        mpf_clear(jjm); mpf_clear(jm);
3,606✔
2045
}
3,606✔
2046

2047
/*
2048
                 #] SingleTable : 
2049
                 #[ DoubleTable :
2050
*/
2051

2052
void DoubleTable(mpf_t *tabout, mpf_t *tabin, int N, int m, int pow)
4,674✔
2053
{
2054
        GETIDENTITY
3,116✔
2055
        long s = 1;
4,674✔
2056
#ifdef WITHCUTOFF
2057
        long prec = mpf_get_default_prec();
4,674✔
2058
#endif
2059
        int j;
4,674✔
2060
        mpf_t jm,jjm;
4,674✔
2061
        mpf_init(jm); mpf_init(jjm);
4,674✔
2062
        if ( pow < -1 || pow > 2 ) {
4,674✔
UNCOV
2063
                MLOCK(ErrorMessageLock);
×
UNCOV
2064
                MesPrint("Wrong parameter pow in DoubleTable: %d\n",pow);
×
UNCOV
2065
                MUNLOCK(ErrorMessageLock);
×
UNCOV
2066
                Terminate(-1);
×
2067
        }
2068
        if ( m < 0 ) { m = -m; s = -1; }
4,674✔
2069
        mpf_set_ui(auxsum,0L);
4,674✔
2070
        for ( j = N; j > 0; j-- ) {
1,709,796✔
2071
#ifdef WITHCUTOFF
2072
                mpf_set_prec_raw(jm,prec-j);
1,700,448✔
2073
                mpf_set_prec_raw(jjm,prec-j);
1,700,448✔
2074
#endif
2075
                mpf_set_ui(jm,1L);
1,700,448✔
2076
                mpf_div_ui(jjm,jm,(unsigned long)j);
1,700,448✔
2077
                mpf_pow_ui(jm,jjm,(unsigned long)m);
1,700,448✔
2078
                if ( pow == -1 ) {
1,700,448✔
2079
                        mpf_mul_2exp(jjm,jm,(unsigned long)j);
8,232✔
2080
                        mpf_mul(jm,jjm,tabin[j+1]);
8,232✔
2081
                }
2082
                else if ( pow > 0 ) {
1,692,216✔
2083
                        mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
3,648✔
2084
                        mpf_mul(jm,jjm,tabin[j+1]);
3,648✔
2085
                }
2086
                else {
2087
                        mpf_mul(jm,jm,tabin[j+1]);
1,688,568✔
2088
                }
2089
                if ( pow == 2 ) mpf_add(auxsum,auxsum,jm);
1,700,448✔
2090
                else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jm);
1,700,448✔
2091
                else                       mpf_add(auxsum,auxsum,jm);
1,694,496✔
2092
/*
2093
                And now copy auxsum to tablelement j
2094
*/
2095
                mpf_set(tabout[j],auxsum);
1,700,448✔
2096
        }
2097
        mpf_clear(jjm); mpf_clear(jm);
4,674✔
2098
}
4,674✔
2099

2100
/*
2101
                 #] DoubleTable : 
2102
                 #[ EndTable :
2103
*/
2104

2105
void EndTable(mpf_t sum, mpf_t *tabin, int N, int m, int pow)
3,606✔
2106
{
2107
        long s = 1;
3,606✔
2108
#ifdef WITHCUTOFF
2109
        long prec = mpf_get_default_prec();
3,606✔
2110
#endif
2111
        int j;
3,606✔
2112
        mpf_t jm,jjm;
3,606✔
2113
        mpf_init(jm); mpf_init(jjm);
3,606✔
2114
        if ( pow < -1 || pow > 2 ) {
3,606✔
UNCOV
2115
                MLOCK(ErrorMessageLock);
×
UNCOV
2116
                MesPrint("Wrong parameter pow in EndTable: %d\n",pow);
×
UNCOV
2117
                MUNLOCK(ErrorMessageLock);
×
UNCOV
2118
                Terminate(-1);
×
2119
        }
2120
        if ( m < 0 ) { m = -m; s = -1; }
3,606✔
2121
        mpf_set_si(sum,0L);
3,606✔
2122
        for ( j = N; j > 0; j-- ) {
770,970✔
2123
#ifdef WITHCUTOFF
2124
                mpf_set_prec_raw(jm,prec-j);
763,758✔
2125
                mpf_set_prec_raw(jjm,prec-j);
763,758✔
2126
#endif
2127
                mpf_set_ui(jm,1L);
763,758✔
2128
                mpf_div_ui(jjm,jm,(unsigned long)j);
763,758✔
2129
                mpf_pow_ui(jm,jjm,(unsigned long)m);
763,758✔
2130
                if ( pow == -1 ) {
763,758✔
2131
                        mpf_mul_2exp(jjm,jm,(unsigned long)j);
13,050✔
2132
                        mpf_mul(jm,jjm,tabin[j+1]);
13,050✔
2133
                }
2134
                else if ( pow > 0 ) {
750,708✔
2135
                        mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
11,700✔
2136
                        mpf_mul(jm,jjm,tabin[j+1]);
11,700✔
2137
                }
2138
                else {
2139
                        mpf_mul(jm,jm,tabin[j+1]);
739,008✔
2140
                }
2141
                if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jm);
763,758✔
2142
                else                       mpf_add(sum,sum,jm);
751,218✔
2143
        }
2144
        mpf_clear(jjm); mpf_clear(jm);
3,606✔
2145
}
3,606✔
2146

2147
/*
2148
                 #] EndTable : 
2149
                 #[ deltaMZV :
2150
*/
2151

2152
void deltaMZV(mpf_t result, WORD *indexes, int depth)
7,566✔
2153
{
2154
        GETIDENTITY
5,044✔
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 ) {
7,566✔
2160
                if ( indexes[0] == 1 ) {
3,804✔
2161
                        mpf_set(result,mpfdelta1);
1,650✔
2162
                        return;
1,650✔
2163
                }
2164
                SimpleDelta(result,indexes[0]);
2,154✔
2165
        }
2166
        else if ( depth == 2 ) {
3,762✔
2167
                if ( indexes[0] == 1 && indexes[1] == 1 ) {
1,470✔
2168
                        mpf_pow_ui(result,mpfdelta1,2);
486✔
2169
                        mpf_div_2exp(result,result,1);
486✔
2170
                }
2171
                else {
2172
                        SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
984✔
2173
                        EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,indexes[1],0);
984✔
2174
                };
2175
        }
2176
        else if ( depth > 2 ) {
2,292✔
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++ ) {
7,548✔
2183
                        if ( indexes[d] != 1 ) break;
6,678✔
2184
                }
2185
                if ( d == depth ) {        /* divide by fac_(depth) */
2,292✔
2186
                        mpf_pow_ui(result,mpfdelta1,depth);
870✔
2187
                        for ( d = 2; d <= depth; d++ ) {
5,196✔
2188
                                mpf_div_ui(result,result,(unsigned long)d);
3,456✔
2189
                        }
2190
                }
2191
                else {
2192
                        d = depth-1;
1,422✔
2193
                        SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
1,422✔
2194
                        d--; indexes++;
1,422✔
2195
                        for(;;) {
6,726✔
2196
                                DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,0);
4,074✔
2197
                                d--; indexes++;
4,074✔
2198
                                if ( d == 0 ) {
4,074✔
2199
                                        EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,*indexes,0);
1,422✔
2200
                                        break;
1,422✔
2201
                                }
2202
                                mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2,652✔
2203
                                AT.mpf_tab2 = (void *)mpftab3;
2,652✔
2204
                        }
2205
                }
2206
        }
UNCOV
2207
        else if ( depth == 0 ) {
×
UNCOV
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

2219
void deltaEuler(mpf_t result, WORD *indexes, int depth)
990✔
2220
{
2221
        GETIDENTITY
660✔
2222
        int m;
990✔
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 ) {
990✔
2233
                SimpleDelta(result,indexes[0]);
390✔
2234
        }
2235
        else if ( depth == 2 ) {
600✔
2236
                SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
348✔
2237
                m = indexes[1]; if ( indexes[0] < 0 ) m = -m;
348✔
2238
                EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,0);
348✔
2239
        }
2240
        else if ( depth > 2 ) {
252✔
2241
                int d;
252✔
2242
                mpf_t *mpftab3;
252✔
2243
                d = depth-1;
252✔
2244
                SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
252✔
2245
                d--; indexes++;
252✔
2246
                m = *indexes; if ( indexes[-1] < 0 ) m = -m;
252✔
2247
                for(;;) {
348✔
2248
                        DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,0);
300✔
2249
                        d--; indexes++;
300✔
2250
                        m = *indexes; if ( indexes[-1] < 0 ) m = -m;
300✔
2251
                        if ( d == 0 ) {
300✔
2252
                                EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,0);
252✔
2253
                                break;
252✔
2254
                        }
2255
                        mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
48✔
2256
                        AT.mpf_tab2 = (void *)mpftab3;
48✔
2257
                }
2258
        }
UNCOV
2259
        else if ( depth == 0 ) {
×
UNCOV
2260
                mpf_set_ui(result,1L);
×
2261
        }
2262
#ifdef DEBUG
2263
        gmp_printf("%.*Fe\n",40,result);
2264
#endif
2265
}
990✔
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

2275
void deltaEulerC(mpf_t result, WORD *indexes, int depth)
990✔
2276
{
2277
        GETIDENTITY
660✔
2278
        int m;
990✔
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);
990✔
2289
        if ( depth == 1 ) {
990✔
2290
                if ( indexes[0] == 0 ) {
390✔
UNCOV
2291
                        MLOCK(ErrorMessageLock);
×
UNCOV
2292
                        MesPrint("Illegal index in depth=1 deltaEulerC: %d\n",indexes[0]);
×
UNCOV
2293
                        MUNLOCK(ErrorMessageLock);
×
UNCOV
2294
                        Terminate(-1);
×
2295
                }
2296
                if ( indexes[0] < 0 ) SimpleDeltaC(result,indexes[0]);
390✔
2297
                else                  SimpleDelta(result,indexes[0]);
150✔
2298
        }
2299
        else if ( depth == 2 ) {
600✔
2300
                int par;
348✔
2301
                m = indexes[0];
348✔
2302
                if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth,-m,2);
348✔
2303
                else         SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth, m,1);
132✔
2304
                m = indexes[1];
348✔
2305
                if ( m < 0 ) { m = -m; par = indexes[0] < 0 ? 0: 1; }
348✔
2306
                else { par = indexes[0] < 0 ? -1: 0; }
150✔
2307
                EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,par);
348✔
2308
        }
2309
        else if ( depth > 2 ) {
252✔
2310
                int d, par;
252✔
2311
                mpf_t *mpftab3;
252✔
2312
                d = depth-1;
252✔
2313
                m = indexes[0];
252✔
2314
        ZeroTable(mpftab1,AC.DefaultPrecision+1);
252✔
2315
                if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1,-m,2);
252✔
2316
                else         SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1, m,1);
60✔
2317
                d--; indexes++; m = indexes[0];
252✔
2318
                if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
252✔
2319
                else { par = indexes[-1] < 0 ? -1: 0; }
120✔
2320
                for(;;) {
348✔
2321
                ZeroTable(mpftab2,AC.DefaultPrecision-AC.MaxWeight+d);
300✔
2322
                        DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,par);
300✔
2323
                        d--; indexes++; m = indexes[0];
300✔
2324
                        if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
300✔
2325
                        else { par = indexes[-1] < 0 ? -1: 0; }
144✔
2326
                        if ( d == 0 ) {
300✔
2327
                                mpf_set_ui(result,0);
252✔
2328
                                EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,par);
252✔
2329
                                break;
252✔
2330
                        }
2331
                        mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
48✔
2332
                        AT.mpf_tab2 = (void *)mpftab3;
48✔
2333
                }
2334
        }
UNCOV
2335
        else if ( depth == 0 ) {
×
UNCOV
2336
                mpf_set_ui(result,1L);
×
2337
        }
2338
#ifdef DEBUG
2339
        gmp_printf("%.*Fe\n",40,result);
2340
#endif
2341
}
990✔
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

2351
void CalculateMZVhalf(mpf_t result, WORD *indexes, int depth)
384✔
2352
{
2353
        int i;
384✔
2354
        if ( depth < 0 ) {
384✔
UNCOV
2355
                MLOCK(ErrorMessageLock);
×
UNCOV
2356
                MesPrint("Illegal depth in CalculateMZVhalf: %d",depth);
×
UNCOV
2357
                MUNLOCK(ErrorMessageLock);
×
UNCOV
2358
                Terminate(-1);
×
2359
        }
2360
        for ( i = 0; i < depth; i++ ) {
1,542✔
2361
                if ( indexes[i] <= 0 ) {
1,164✔
2362
                        MLOCK(ErrorMessageLock);
6✔
2363
                        MesPrint("Illegal index[%d] in CalculateMZVhalf: %d",i,indexes[i]);
6✔
2364
                        MUNLOCK(ErrorMessageLock);
6✔
2365
                        Terminate(-1);
1,164✔
2366
                }
2367
        }
2368
        deltaMZV(result,indexes,depth);
378✔
2369
}
378✔
2370

2371
/*
2372
                 #] CalculateMZVhalf : 
2373
                 #[ CalculateMZV :
2374
*/
2375

2376
void CalculateMZV(mpf_t result, WORD *indexes, int depth)
834✔
2377
{
2378
        GETIDENTITY
556✔
2379
        int num1, num2 = 0, i, j = 0;
834✔
2380
        if ( depth < 0 ) {
834✔
UNCOV
2381
                MLOCK(ErrorMessageLock);
×
UNCOV
2382
                MesPrint("Illegal depth in CalculateMZV: %d",depth);
×
UNCOV
2383
                MUNLOCK(ErrorMessageLock);
×
UNCOV
2384
                Terminate(-1);
×
2385
        }
2386
        if ( indexes[0] == 1 ) {
834✔
2387
                MLOCK(ErrorMessageLock);
6✔
2388
                MesPrint("Divergent MZV in CalculateMZV");
6✔
2389
                MUNLOCK(ErrorMessageLock);
6✔
2390
                Terminate(-1);
6✔
2391
        }
2392
/*        MesPrint("calculateMZV(%a)",depth,indexes); */
2393
        for ( i = 0; i < depth; i++ ) {
2,082✔
2394
                if ( indexes[i] <= 0 ) {
1,260✔
2395
                        MLOCK(ErrorMessageLock);
6✔
2396
                        MesPrint("Illegal index[%d] in CalculateMZV: %d",i,indexes[i]);
6✔
2397
                        MUNLOCK(ErrorMessageLock);
6✔
2398
                        Terminate(-1);
6✔
2399
                }
2400
                AT.indi1[i] = indexes[i];
1,254✔
2401
        }
2402
        num1 = depth; i = 0;
822✔
2403
        deltaMZV(result,indexes,depth);
822✔
2404
        for(;;) {
6,366✔
2405
                if ( AT.indi1[0] > 1 ) {
3,594✔
2406
                        AT.indi1[0] -= 1;
2,340✔
2407
                        for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
7,794✔
2408
                        AT.indi2[0] = 1; num2++;
2,340✔
2409
                }
2410
                else {
2411
                        AT.indi2[0] += 1;
1,254✔
2412
                        for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
1,926✔
2413
                        num1--;
1,254✔
2414
                        if ( num1 == 0 ) break;
1,254✔
2415
                }
2416
                deltaMZV(aux1,AT.indi1,num1);
2,772✔
2417
                deltaMZV(aux2,AT.indi2,num2);
2,772✔
2418
                mpf_mul(aux3,aux1,aux2);
2,772✔
2419
                mpf_add(result,result,aux3);
2,772✔
2420
        }
2421
        deltaMZV(aux3,AT.indi2,num2);
822✔
2422
        mpf_add(result,result,aux3);
822✔
2423
}
822✔
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

2447
void CalculateEuler(mpf_t result, WORD *Zindexes, int depth)
324✔
2448
{
2449
        GETIDENTITY
216✔
2450
        int s1, num1, num2, i, j;
324✔
2451

2452
        WORD *indexes = AT.WorkPointer;
324✔
2453
        for ( i = 0; i < depth; i++ ) indexes[i] = Zindexes[i];
1,146✔
2454
        for ( i = 0; i < depth-1; i++ ) {
822✔
2455
                if ( Zindexes[i] < 0 ) {
498✔
2456
                        for ( j = i+1; j < depth; j++ ) indexes[j] = -indexes[j];
864✔
2457
                }
2458
        }
2459

2460
        if ( depth < 0 ) {
324✔
UNCOV
2461
                MLOCK(ErrorMessageLock);
×
UNCOV
2462
                MesPrint("Illegal depth in CalculateEuler: %d\n",depth);
×
UNCOV
2463
                MUNLOCK(ErrorMessageLock);
×
UNCOV
2464
                Terminate(-1);
×
2465
        }
2466
        if ( indexes[0] == 1 ) {
324✔
2467
                MLOCK(ErrorMessageLock);
6✔
2468
                MesPrint("Divergent Euler sum in CalculateEuler\n");
6✔
2469
                MUNLOCK(ErrorMessageLock);
6✔
2470
                Terminate(-1);
6✔
2471
        }
2472
        for ( i = 0, j = 0; i < depth; i++ ) {
1,128✔
2473
                if ( indexes[i] == 0 ) {
810✔
UNCOV
2474
                        MLOCK(ErrorMessageLock);
×
UNCOV
2475
                        MesPrint("Illegal index[%d] in CalculateEuler: %d\n",i,indexes[i]);
×
UNCOV
2476
                        MUNLOCK(ErrorMessageLock);
×
UNCOV
2477
                        Terminate(-1);
×
2478
                }
2479
                if ( indexes[i] < 0 ) j = 1;
810✔
2480
                AT.indi1[i] = indexes[i];
810✔
2481
        }
2482
        if ( j == 0 ) {
318✔
2483
                CalculateMZV(result,indexes,depth);
42✔
2484
                return;
42✔
2485
        }
2486
        num1 = depth; AT.indi2[0] = 0; num2 = 0;
276✔
2487
        deltaEuler(result,AT.indi1,depth);
276✔
2488
        s1 = 0;
276✔
2489
        for(;;) {
990✔
2490
                s1++;
990✔
2491
                if ( AT.indi1[0] > 1 ) {
990✔
2492
                        AT.indi1[0] -= 1;
90✔
2493
                        for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
162✔
2494
                        AT.indi2[0] = 1; num2++;
90✔
2495
                }
2496
                else if ( AT.indi1[0] < -1 ) {
900✔
2497
                        AT.indi1[0] += 1;
162✔
2498
                        for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
270✔
2499
                        AT.indi2[0] = 1; num2++;
162✔
2500
                }
2501
                else if ( AT.indi1[0] == -1 ) {
738✔
2502
                        for ( j = num2; j > 0; j-- ) AT.indi2[j] = AT.indi2[j-1];
1,026✔
2503
                        AT.indi2[0] = -1; num2++;
486✔
2504
                        for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
1,026✔
2505
                        num1--;
486✔
2506
                }
2507
                else {
2508
                        AT.indi2[0] = AT.indi2[0] < 0 ? AT.indi2[0]-1: AT.indi2[0]+1;
252✔
2509
                        for ( j = 1; j < num1; j++ ) AT.indi1[j-1] = AT.indi1[j];
432✔
2510
                        num1--;
252✔
2511
                }
2512
                if ( num1 == 0 ) break;
990✔
2513
                deltaEuler(aux1,AT.indi1,num1);
714✔
2514
                deltaEulerC(aux2,AT.indi2,num2);
714✔
2515
                mpf_mul(aux3,aux1,aux2);
714✔
2516
                if ( (depth+num1+num2+s1)%2 == 0 ) mpf_add(result,result,aux3);
714✔
2517
                else                               mpf_sub(result,result,aux3);
408✔
2518
        }
2519
        deltaEulerC(aux3,AT.indi2,num2);
276✔
2520
        if ( (depth+num2+s1)%2 == 0 ) mpf_add(result,result,aux3);
276✔
2521
        else                          mpf_sub(result,result,aux3);
162✔
2522
}
2523

2524
/*
2525
                 #] CalculateEuler : 
2526
                 #[ ExpandMZV :
2527
*/
2528

UNCOV
2529
int ExpandMZV(WORD *term, WORD level)
×
2530
{
UNCOV
2531
        DUMMYUSE(term);
×
2532
        DUMMYUSE(level);
×
UNCOV
2533
        return(0);
×
2534
}
2535

2536
/*
2537
                 #] ExpandMZV : 
2538
                 #[ ExpandEuler :
2539
*/
2540

UNCOV
2541
int ExpandEuler(WORD *term, WORD level)
×
2542
{
UNCOV
2543
        DUMMYUSE(term);
×
UNCOV
2544
        DUMMYUSE(level);
×
UNCOV
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

2569
int EvaluateEuler(PHEAD WORD *term, WORD level, WORD par)
1,380✔
2570
{
2571
        WORD *t, *tstop, *tt, *tnext, sumweight, depth, first = 1, *newterm, i;
1,380✔
2572
        WORD *oldworkpointer = AT.WorkPointer, nsize, *indexes;
1,380✔
2573
        int retval;
1,380✔
2574
        tstop = term + *term; tstop -= ABS(tstop[-1]);
1,380✔
2575
        if ( AT.WorkPointer < term+*term ) AT.WorkPointer = term + *term;
1,380✔
2576
/*
2577
        Step 1. We also need to verify that the argument we find is legal
2578
*/
2579
        t = term+1;
1,380✔
2580
        while ( t < tstop ) {
4,002✔
2581
                if ( ( *t == par ) || ( ( par == ALLMZVFUNCTIONS ) && (
2,652✔
2582
                        *t == MZV || *t == EULER || *t == MZVHALF ) ) ) {
264✔
2583
        /* all arguments should be small integers */
2584
                        indexes = AT.WorkPointer;
1,524✔
2585
                        sumweight = 0; depth = 0;
1,524✔
2586
                        tnext = t + t[1]; tt = t + FUNHEAD;
1,524✔
2587
                        while ( tt < tnext ) {
4,728✔
2588
                                if ( *tt != -SNUMBER ) goto nextfun;
3,204✔
2589
                                if ( tt[1] == 0 ) goto nextfun;
3,204✔
2590
                                indexes[depth] = tt[1];
3,204✔
2591
                                sumweight += ABS(tt[1]); depth++;
3,204✔
2592
                                tt += 2;
3,204✔
2593
                        }
2594
                        /* euler sum without arguments, i.e. mzv_(), euler_() or mzvhalf_() */
2595
                        if ( depth == 0) goto nextfun;
1,524✔
2596
                        if ( sumweight > AC.MaxWeight ) {
1,506✔
2597
                                MLOCK(ErrorMessageLock);
6✔
2598
                                MesPrint("Error: Weight of Euler/MZV sum greater than %d.",AC.MaxWeight);
6✔
2599
                                MesPrint("Please increase the maximum weight in %#startfloat.");
6✔
2600
                                MUNLOCK(ErrorMessageLock);
6✔
2601
                                Terminate(-1);
6✔
2602
                        }
2603
/*
2604
                        Step 2: evaluate:
2605
*/
2606
                        AT.WorkPointer += depth;
1,500✔
2607
                        if ( first ) {
1,500✔
2608
                                if ( *t == MZV ) CalculateMZV(aux4,indexes,depth);
1,176✔
2609
                                else if ( *t == EULER ) CalculateEuler(aux4,indexes,depth);
708✔
2610
                                else if ( *t == MZVHALF ) CalculateMZVhalf(aux4,indexes,depth);
384✔
2611
                                first = 0;
2612
                        }
2613
                        else {
2614
                                if ( *t == MZV ) CalculateMZV(aux5,indexes,depth);
324✔
UNCOV
2615
                                else if ( *t == EULER ) CalculateEuler(aux5,indexes,depth);
×
UNCOV
2616
                                else if ( *t == MZVHALF ) CalculateMZVhalf(aux5,indexes,depth);
×
2617
                                mpf_mul(aux4,aux4,aux5);
324✔
2618
                        }
2619
                        *t = 0;
1,476✔
2620
                }
2621
nextfun:
1,128✔
2622
                t += t[1];
2,622✔
2623
        }
2624
        if ( first == 1 ) return(Generator(BHEAD term,level));
1,350✔
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];
1,152✔
2631
        if ( nsize < 0 ) {
1,152✔
2632
                mpf_neg(aux4,aux4);
72✔
2633
                nsize = -nsize;
72✔
2634
        }
2635
        if ( nsize == 3 ) {
1,152✔
2636
                if ( tstop[0] != 1 ) {
1,152✔
2637
                        mpf_mul_ui(aux4,aux4,(ULONG)((UWORD)tstop[0]));
132✔
2638
                }
2639
                if ( tstop[1] != 1 ) {
1,152✔
2640
                        mpf_div_ui(aux4,aux4,(ULONG)((UWORD)tstop[1]));
132✔
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 ) {
3,510✔
2652
                if ( *t == FLOATFUN ) {
2,358✔
UNCOV
2653
                        UnpackFloat(aux5,t);
×
UNCOV
2654
                        mpf_mul(aux4,aux4,aux5);
×
2655
                }
2656
                t += t[1];
2,358✔
2657
        }
2658
/*
2659
        Now we should compose the new term in the WorkSpace.
2660
*/
2661
        t = term+1;
1,152✔
2662
        newterm = AT.WorkPointer;
1,152✔
2663
        tt = newterm+1;
1,152✔
2664
        while ( t < tstop ) {
1,152✔
2665
                if ( *t == 0 || *t == FLOATFUN ) t += t[1];
2,358✔
2666
                else {
2667
                        i = t[1]; NCOPY(tt,t,i);
11,922✔
2668
                }
2669
        }
2670
        PackFloat(tt,aux4);
1,152✔
2671
        tt += tt[1];
1,152✔
2672
        *tt++ = 1; *tt++ = 1; *tt++ = 3;
1,152✔
2673
        *newterm = tt-newterm;
1,152✔
2674
        AT.WorkPointer = tt;
1,152✔
2675
        retval = Generator(BHEAD newterm,level);
1,152✔
2676
        AT.WorkPointer = oldworkpointer;
1,152✔
2677
        return(retval);
1,152✔
2678
}
2679

2680
/*
2681
                 #] EvaluateEuler : 
2682
          #] MZV : 
2683
          #[ Functions :
2684
                 #[ CoEvaluate :
2685

2686
                Current subkeys: mzv_, euler_ and sqrt_.
2687
*/
2688

2689
int CoEvaluate(UBYTE *s)
432✔
2690
{
2691
        GETIDENTITY
288✔
2692
        UBYTE *subkey, c;
432✔
2693
        WORD numfun, type;
432✔
2694
        int error = 0;
432✔
2695
        if ( AT.aux_ == 0 ) {
432✔
2696
                MesPrint("&Illegal attempt to evaluate a function without activating floating point numbers.");
6✔
2697
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
2698
                return(1);
6✔
2699
        }
2700
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
426✔
2701
        if ( *s == 0 ) {
426✔
2702
/*
2703
                No subkey, which means all functions.
2704
*/
2705
                Add3Com(TYPEEVALUATE,ALLFUNCTIONS);
42✔
2706
/*
2707
                The MZV, EULER and MZVHALF are done separately
2708
*/
2709
                Add3Com(TYPEEVALUATE,ALLMZVFUNCTIONS);
42✔
2710
                return(0);        
42✔
2711
        }
2712
        while ( *s ) {
738✔
2713
        subkey = s;
2714
        while ( FG.cTable[*s] == 0 ) s++;
1,836✔
2715
          if ( *s == '2' ) s++; /* cases li2_ and atan2_ */
402✔
2716
          if ( *s == '_' ) s++;
402✔
2717
          c = *s; *s = 0;
402✔
2718
/*
2719
                We still need provisions for pi_ and possibly other constants.
2720
*/
2721
          if ( ( ( type = GetName(AC.varnames,subkey,&numfun,NOAUTO) ) != CFUNCTION )
402✔
2722
                        || ( functions[numfun].spec != 0 ) ) {
354✔
2723

2724
                if ( type == CSYMBOL ) {
48✔
2725
                        Add4Com(TYPEEVALUATE,SYMBOL,numfun);
36✔
2726
                        break;
36✔
2727
                }
2728
/*
2729
                        This cannot work.
2730
*/
2731
                MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
12✔
2732
                return(1);
12✔
2733
          }
2734
          else {
2735
                switch ( numfun+FUNCTION ) {
354✔
2736
                        case MZV:
348✔
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);
348✔
2767
                                break;
348✔
2768
                        default:
6✔
2769
                                MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
6✔
2770
                                error = 1;
6✔
2771
                                break;
6✔
2772
                }
2773
          }
2774
          *s = c;
354✔
2775
          while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
372✔
2776
        }
2777
        return(error);
2778
}
2779

2780
/*
2781
                 #] CoEvaluate : 
2782
          #] Functions : 
2783
*/
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc