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

form-dev / form / 20995074137

14 Jan 2026 01:03PM UTC coverage: 53.36% (+0.02%) from 53.341%
20995074137

Pull #772

github

web-flow
Merge 089223155 into 4d1d77d03
Pull Request #772: fix: protect error messages in float.c with locks.

20 of 54 new or added lines in 1 file covered. (37.04%)

1 existing line in 1 file now uncovered.

44182 of 82800 relevant lines covered (53.36%)

5357853.32 hits per line

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

85.35
/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-2023 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)
18✔
215
{
216
        int i;
18✔
217
        for ( i = 0; i < t->_mp_prec; i++ ) t->_mp_d[i] = 0;
198✔
218
        t->_mp_size = 0;
18✔
219
        t->_mp_exp = 0;
18✔
220
}
18✔
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)
11,682✔
272
{
273
        WORD *t, nlimbs, num, nnum;
11,682✔
274
        mp_limb_t *d = infloat->_mp_d; /* Pointer to the limbs.  */
11,682✔
275
        int i;
11,682✔
276
        long e = infloat->_mp_exp;
11,682✔
277
        t = fun;
11,682✔
278
        *t++ = FLOATFUN;
11,682✔
279
        t++;
11,682✔
280
        FILLFUN(t);
11,682✔
281
        *t++ = -SNUMBER;
11,682✔
282
        *t++ = infloat->_mp_prec;
11,682✔
283
        *t++ = -SNUMBER;
11,682✔
284
        *t++ = infloat->_mp_size;
11,682✔
285
/*
286
        Now the exponent which is a signed long
287
*/
288
        if ( e < 0 ) {
11,682✔
289
                e = -e;
348✔
290
                if ( ( e >> (BITSINWORD-1) ) == 0 ) {
348✔
291
                        *t++ = -SNUMBER; *t++ = -e;
186✔
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,334✔
303
                        *t++ = -SNUMBER; *t++ = e;
11,172✔
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;
11,682✔
318
        if ( nlimbs == 0 ) {
11,682✔
319
                *t++ = -SNUMBER;
1,236✔
320
                *t++ = 0;
1,236✔
321
        }
322
        else if ( nlimbs == 1 && (ULONG)(*d) < ((ULONG)1)<<(BITSINWORD-1) ) {
10,446✔
323
                *t++ = -SNUMBER;
1,872✔
324
                *t++ = (UWORD)(*d);
1,872✔
325
        }
326
        else {
327
          if ( d[nlimbs-1] < ((ULONG)1)<<BITSINWORD ) {
8,574✔
328
                num = 2*nlimbs-1; /* number of UWORDS needed */
6,516✔
329
          }
330
          else {
331
                num = 2*nlimbs;   /* number of UWORDS needed */
2,058✔
332
          }
333
          nnum = num;
8,574✔
334
          *t++ = 2*num+2+ARGHEAD;
8,574✔
335
          *t++ = 0;
8,574✔
336
          FILLARG(t);
8,574✔
337
          *t++ = 2*num+2;
8,574✔
338
          while ( num > 1 ) {
28,908✔
339
                *t++ = (UWORD)(*d); *t++ = (UWORD)(((ULONG)(*d))>>BITSINWORD); d++;
20,334✔
340
                num -= 2;
20,334✔
341
          }
342
          if ( num == 1 ) { *t++ = (UWORD)(*d); }
8,574✔
343
          *t++ = 1;
8,574✔
344
          for ( i = 1; i < nnum; i++ ) *t++ = 0;
47,184✔
345
          *t++ = 2*nnum+1; /* the sign is hidden in infloat->_mp_size */
8,574✔
346
        }
347
        fun[1] = t-fun;
11,682✔
348
        return(fun[1]);
11,682✔
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,018✔
367
{
368
        UWORD *t;
18,018✔
369
        WORD *f;
18,018✔
370
        int num, i;
18,018✔
371
        mp_limb_t *d;
18,018✔
372
/*
373
        Very first step: check whether we can use float_:
374
*/
375
        GETIDENTITY
12,012✔
376
        if ( AT.aux_ == 0 ) {
18,018✔
NEW
377
                MLOCK(ErrorMessageLock);
×
378
                MesPrint("Illegal attempt at using a float_ function without proper startup.");
×
379
                MesPrint("Please use %#StartFloat <options> first.");
×
NEW
380
                MUNLOCK(ErrorMessageLock);
×
UNCOV
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,018✔
389
        f = fun + FUNHEAD + 2;
18,018✔
390
        if ( ABS(f[1]) > f[-1]+1 ) goto Incorrect;
18,018✔
391
        if ( f[1] > outfloat->_mp_prec+1
18,018✔
392
          || outfloat->_mp_d == 0 ) {
18,018✔
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,018✔
404
        outfloat->_mp_size = num;
18,018✔
405
        if ( num < 0 ) { num = -num; }
18,018✔
406
        f += 2;
18,018✔
407
        if ( *f == -SNUMBER ) {
18,018✔
408
                outfloat->_mp_exp = (mp_exp_t)(f[1]);
17,694✔
409
                f += 2;
17,694✔
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,018✔
426
        if ( outfloat->_mp_size == 0 ) {
18,018✔
427
                for ( i = 0; i < outfloat->_mp_prec; i++ ) *d++ = 0;
3,708✔
428
                return(0);
429
        }
430
        else if ( *f == -SNUMBER ) {
16,782✔
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 */
14,838✔
436
        t = (UWORD *)(f+ARGHEAD+1);
14,838✔
437
        while ( num > 1 ) {
47,706✔
438
                *d++ = (mp_limb_t)((((ULONG)(t[1]))<<BITSINWORD)+t[0]);
32,868✔
439
                t += 2; num -= 2;
32,868✔
440
        }
441
        if ( num == 1 ) *d++ = (mp_limb_t)((UWORD)(*t));
14,838✔
442
        for ( i = d-outfloat->_mp_d; i <= outfloat->_mp_prec; i++ ) *d++ = 0;
19,254✔
443
        return(0);
444
Incorrect:
18,018✔
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)
39,204✔
457
{
458
        WORD *fstop, *f, num, nnum, i;
39,204✔
459
        fstop = fun+fun[1];
39,204✔
460
        f = fun + FUNHEAD;
39,204✔
461
        num = 0;
39,204✔
462
/*
463
        Count arguments
464
*/
465
        while ( f < fstop ) { num++; NEXTARG(f); }
195,984✔
466
        if ( num != 4 ) return(0);
39,204✔
467
        f = fun + FUNHEAD;
39,192✔
468
        if ( *f != -SNUMBER ) return(0);
39,192✔
469
        if ( f[1] < 0 ) return(0);
39,180✔
470
        f += 2;
39,180✔
471
        if ( *f != -SNUMBER ) return(0);
39,180✔
472
        num = ABS(f[1]); /* number of limbs */
39,180✔
473
        f += 2;
39,180✔
474
        if ( *f == -SNUMBER ) { f += 2; }
39,180✔
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);
39,180✔
483
        if ( *f == -SNUMBER ) { if ( num != 1 ) return(0); }
36,906✔
484
        else {
485
                nnum = (ABS(f[*f-1])-1)/2;
33,060✔
486
                if ( ( *f != 4*num+2+ARGHEAD ) && ( *f != 4*num+ARGHEAD ) ) return(0);
33,060✔
487
                if ( ( nnum != 2*num ) && ( nnum != 2*num-1 ) ) return(0);
33,060✔
488
                f += ARGHEAD+nnum+1;
33,060✔
489
                if ( f[0] != 1 ) return(0);
33,060✔
490
                for ( i = 1; i < nnum; i++ ) {
178,008✔
491
                        if ( f[i] != 0 ) return(0);
144,948✔
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,252✔
516
{
517
        int nlimbs, sgn = 1;
9,252✔
518
        mp_limb_t *d;
9,252✔
519
        UWORD *b = a;
9,252✔
520
        WORD nb = na;
9,252✔
521

522
        if ( nb == 0 ) {
9,252✔
523
                z->_mp_size = 0;
×
524
                z->_mp_d[0] = 0;
×
525
                return;
×
526
        }
527
        if ( nb < 0 ) { sgn = -1; nb = -nb; }
9,252✔
528
        nlimbs = (nb+1)/2;
9,252✔
529
        if ( mpz_cmp_si(z,0L) <= 1 ) {
9,252✔
530
                mpz_set_ui(z,10000000);
9,252✔
531
        }
532
        if ( z->_mp_alloc <= nlimbs ) {
9,252✔
533
                mpz_t zz;
9,252✔
534
                mpz_init(zz);
9,252✔
535
                while ( z->_mp_alloc <= nlimbs ) {
27,822✔
536
                        mpz_mul(zz,z,z);
18,570✔
537
                        mpz_set(z,zz);
18,570✔
538
                }
539
                mpz_clear(zz);
9,252✔
540
        }
541
        z->_mp_size = sgn*nlimbs;
9,252✔
542
        d = z->_mp_d;
9,252✔
543
        while ( nb > 1 ) {
9,762✔
544
                *d++ = (((mp_limb_t)(b[1]))<<BITSINWORD)+(mp_limb_t)(b[0]);
510✔
545
                b += 2; nb -= 2;
510✔
546
        }
547
        if ( nb == 1 ) { *d = (mp_limb_t)(*b); }
9,252✔
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)
66✔
560
{
561
        mp_limb_t *d = z->_mp_d;
66✔
562
        int nlimbs = ABS(z->_mp_size), i;
66✔
563
        UWORD j;
66✔
564
        if ( nlimbs == 0 ) { *na = 0; return; }
66✔
565
        *na = 0;
66✔
566
        for ( i = 0; i < nlimbs-1; i++ ) {
108✔
567
                *a++ = (UWORD)(*d);
42✔
568
                *a++ = (UWORD)((*d++)>>BITSINWORD);
42✔
569
                *na += 2;
42✔
570
        }
571
        *na += 1;
66✔
572
        *a++ = (UWORD)(*d);
66✔
573
        j = (UWORD)((*d)>>BITSINWORD);
66✔
574
        if ( j != 0 ) { *a = j; *na += 1; }
66✔
575
        if ( z->_mp_size < 0 ) *na = -*na;
66✔
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)
66✔
586
{
587
        mpz_t z;
66✔
588
        WORD nout, nx;
66✔
589
        UWORD x;
66✔
590
        mpz_init(z);
66✔
591
        mpz_set_f(z,floatin);
66✔
592
        ZtoForm(out,&nout,z);
66✔
593
        mpz_clear(z);
66✔
594
        x = out[0]; nx = 0;
66✔
595
        while ( x ) { nx++; x >>= 1; }
450✔
596
        *bitsused = (nout-1)*BITSINWORD + nx;
66✔
597
        return(nout);
66✔
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,000✔
609
{
610
        mpz_t z;
9,000✔
611
        mpz_init(z);
9,000✔
612
        FormtoZ(z,formlong,longsize);
9,000✔
613
        mpf_set_z(result,z);
9,000✔
614
        mpz_clear(z);
9,000✔
615
}
9,000✔
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,500✔
625
{
626
        GETIDENTITY
3,000✔
627
        int nnum, nden;
4,500✔
628
        UWORD *num, *den;
4,500✔
629
        int sgn = 0;
4,500✔
630
        if ( ratsize < 0 ) { ratsize = -ratsize; sgn = 1; }
4,500✔
631
        nnum = nden = (ratsize-1)/2;
4,500✔
632
        num = formrat; den = formrat+nnum;
4,500✔
633
        while ( num[nnum-1] == 0 ) { nnum--; }
5,328✔
634
        while ( den[nden-1] == 0 ) { nden--; }
4,578✔
635
        IntegerToFloat(aux2,num,nnum);
4,500✔
636
        IntegerToFloat(aux3,den,nden);
4,500✔
637
        mpf_div(result,aux2,aux3);
4,500✔
638
        if ( sgn > 0 ) mpf_neg(result,result);
4,500✔
639
}
4,500✔
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)
6✔
673
{
674
        GETIDENTITY
4✔
675
        WORD *out = AT.WorkPointer;
6✔
676
        WORD s; /* the sign. */
6✔
677
        UWORD *a, *b, *c, *d, *mc;
6✔
678
        WORD na, nb, nc, nd, i;
6✔
679
        int nout;
6✔
680
        LONG oldpWorkPointer = AT.pWorkPointer;
6✔
681
        long bitsused = 0, totalbitsused = 0, totalbits = AC.DefaultPrecision;
6✔
682
        int retval = 0, startnul;
6✔
683
        WantAddPointers(AC.DefaultPrecision);  /* Horrible overkill */
30✔
684
        AT.pWorkSpace[AT.pWorkPointer++] = out;
6✔
685
        a = NumberMalloc("FloatToRat");
6✔
686
        b = NumberMalloc("FloatToRat");
6✔
687

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

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

695
        mpf_trunc(aux1,floatin);     /* This should now be an integer */
6✔
696
        mpf_sub(aux2,floatin,aux1);  /* and this >= 0 */
6✔
697
        if ( mpf_sgn(aux1) == 0 ) { *out++ = 0; startnul = 1; }
6✔
698
        else {
699
                nout = FloatToInteger((UWORD *)out,aux1,&totalbitsused);
6✔
700
                out += nout;
6✔
701
                startnul = 0;
6✔
702
        }
703
        AT.pWorkSpace[AT.pWorkPointer++] = out;
6✔
704
        if ( mpf_sgn(aux2) ) {
6✔
705
          for(;;) {
114✔
706
                mpf_ui_div(aux3,1,aux2);
60✔
707
                mpf_trunc(aux1,aux3);
60✔
708
                mpf_sub(aux2,aux3,aux1);
60✔
709
                if ( mpf_sgn(aux1) == 0 ) { *out++ = 0; }
60✔
710
                else {
711
                        nout = FloatToInteger((UWORD *)out,aux1,&bitsused);
60✔
712
                        out += nout;
60✔
713
                        totalbitsused += bitsused;
60✔
714
                }
715
                if ( bitsused > (totalbits-totalbitsused)/2 ) { break; }
60✔
716
                if ( mpf_sgn(aux2) == 0 ) {
54✔
717
                        /*if ( startnul == 1 )*/ AT.pWorkSpace[AT.pWorkPointer++] = out;
×
718
                        break;
×
719
                }
720
                AT.pWorkSpace[AT.pWorkPointer++] = out;
54✔
721
          }
722
/*
723
          At this point we have the function with the repeated fraction.
724
          Now we should work out the fraction. Form code would be:
725
                repeat id   dum_(?a,x1?,x2?) = dum_(?a,x1+1/x2);
726
                id        dum_(x?) = x;
727
          We have to work backwards. This is why we made a list of pointers
728
          in AT.pWorkSpace
729

730
          Now we need the long integers a and b.
731
          Note that by construction there should never be a GCD!
732
*/
733
          out = (WORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
6✔
734
          na = 1; a[0] = 1;
6✔
735
          c = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
6✔
736
          nc = nb = ((UWORD *)out)-c;
6✔
737
          if ( nc > 10 ) {
6✔
738
                mc = c;
×
739
                c = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
×
740
                nc = nb = ((UWORD *)mc)-c;
×
741
          }
742
          for ( i = 0; i < nb; i++ ) b[i] = c[i];
12✔
743
          mc = c = NumberMalloc("FloatToRat");
6✔
744
          while ( AT.pWorkPointer > oldpWorkPointer ) {
60✔
745
                d = (UWORD *)(AT.pWorkSpace[--AT.pWorkPointer]);
54✔
746
                nd = (UWORD *)(AT.pWorkSpace[AT.pWorkPointer+1])-d; /* This is the x1 in the formula */
54✔
747
                if ( nd == 1 && *d == 0 ) break;
54✔
748
                c = a; a = b; b = c; nc = na; na = nb; nb = nc; /* 1/x2 */
54✔
749
                MulLong(d,nd,a,na,mc,&nc);
54✔
750
                AddLong(mc,nc,b,nb,b,&nb);
54✔
751
          }
752
          NumberFree(mc,"FloatToRat");
6✔
753
          if ( startnul == 0 ) {
6✔
754
                c = a; a = b; b = c; nc = na; na = nb; nb = nc;
6✔
755
          }
756
        }
757
        else {
758
                c = (UWORD *)(AT.pWorkSpace[oldpWorkPointer]);
×
759
                na = (UWORD *)out - c;
×
760
                for ( i = 0; i < na; i++ ) a[i] = c[i];
×
761
                b[0] = 1; nb = 1;
×
762
        }
763
/*
764
        Now we have the fraction in a/b. Create the rational and add the sign.
765
*/
766
        d = ratout;
6✔
767
        if ( na == nb ) {
6✔
768
                *nratout = (2*na+1)*s;
6✔
769
                for ( i = 0; i < na; i++ ) *d++ = a[i];
12✔
770
                for ( i = 0; i < nb; i++ ) *d++ = b[i];
12✔
771
        }
772
        else if ( na < nb ) {
×
773
                *nratout = (2*nb+1)*s;
×
774
                for ( i = 0; i < na; i++ ) *d++ = a[i];
×
775
                for ( ; i < nb; i++ ) *d++ = 0;
×
776
                for ( i = 0; i < nb; i++ ) *d++ = b[i];
×
777
        }
778
        else {
779
                *nratout = (2*na+1)*s;
×
780
                for ( i = 0; i < na; i++ ) *d++ = a[i];
×
781
                for ( i = 0; i < nb; i++ ) *d++ = b[i];
×
782
                for ( ; i < na; i++ ) *d++ = 0;
×
783
        }
784
        *d = (UWORD)(*nratout);
6✔
785
        NumberFree(b,"FloatToRat");
6✔
786
        NumberFree(a,"FloatToRat");
6✔
787
        AT.pWorkPointer = oldpWorkPointer;
6✔
788
/*
789
        Just for check we go back to float
790
*/
791
        if ( s < 0 ) mpf_neg(floatin,floatin);
6✔
792
/*
793
        {
794
                WORD n = *ratout;
795
                RatToFloat(aux1,ratout,n);
796
                mpf_sub(aux2,floatin,aux1);
797
                gmp_printf("Diff is %.*Fe\n",40,aux2);
798
        }
799
*/
800
        return(retval);
6✔
801
}
802

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

820
        Used by the compiler. It reads a floating point number and
821
        outputs it at AT.WorkPointer as if it were a float_ function
822
        with its arguments.
823
        The call enters with s[-1] == TFLOAT.
824
*/
825

826
SBYTE *ReadFloat(SBYTE *s)
1,458✔
827
{
828
        GETIDENTITY
972✔
829
        SBYTE *ss, c;
1,458✔
830
        ss = s;
1,458✔
831
        while ( *ss > 0 ) ss++;
16,068✔
832
        c = *ss; *ss = 0;
1,458✔
833
        gmp_sscanf((char *)s,"%Ff",aux1);
1,458✔
834
        if ( AT.WorkPointer > AT.WorkTop ) {
1,458✔
835
                MLOCK(ErrorMessageLock);
×
836
                MesWork();
×
837
                MUNLOCK(ErrorMessageLock);
×
838
                Terminate(-1);
×
839
        }
840
        PackFloat(AT.WorkPointer,aux1);
1,458✔
841
        *ss = c;
1,458✔
842
        return(ss);
1,458✔
843
}
844

845
/*
846
                 #] ReadFloat : 
847
                 #[ CheckFloat :
848

849
        For the tokenizer. Tests whether the input string can be a float.
850
*/
851

852
UBYTE *CheckFloat(UBYTE *ss, int *spec)
13,296,836✔
853
{
854
        GETIDENTITY
8,864,560✔
855
        UBYTE *s = ss;
13,296,836✔
856
        int gotdot = 0;
13,296,836✔
857
        /* A single dot is not a valid float */
858
        if ( *s == '.' && FG.cTable[s[-1]] != 1 && FG.cTable[s[1]] != 1 ) return(ss);
13,296,836✔
859
        while ( FG.cTable[s[-1]] == 1 ) s--;
34,957,360✔
860
        /* This cannot be a valid float */
861
        if ( *s != '.' && FG.cTable[*s] != 1 ) return(ss);
13,296,836✔
862
        *spec = 0;
13,296,836✔
863
        while ( FG.cTable[*s] == 1 ) s++;
35,350,444✔
864
        if ( *s == '.' ) {
13,296,836✔
865
                gotdot = 1;
1,446✔
866
                s++;
1,446✔
867
                while ( FG.cTable[*s] == 1 ) s++;
4,170✔
868
        }
869
/*
870
        Now we have had the mantissa part, which may be zero.
871
        Check for an exponent.
872
*/
873
        if ( *s == 'e' || *s == 'E' ) {
13,296,836✔
874
                s++;
864✔
875
                if ( *s == '-' || *s == '+' ) s++;
864✔
876
                if ( FG.cTable[*s] == 1 ) {
864✔
877
                        s++;
864✔
878
                        while ( FG.cTable[*s] == 1 ) s++;
7,638✔
879
                }
880
                else { return(ss); }
881
        }
882
        else if ( gotdot == 0 ) return(ss); /* No radix point and no exponent */
13,295,972✔
883
        if ( AT.aux_ == 0 ) { /* no floating point system */
1,458✔
884
                *spec = -1;
×
885
                return(s);
×
886
        }
887
        return(s);
888
}
889

890
/*
891
                 #] CheckFloat : 
892
          #] Low Level : 
893
          #[ Float Routines :
894
                 #[ SetFloatPrecision :
895

896
                Sets the default precision (in bits) of the floats and allocate
897
                buffer space for an output string.
898
                The buffer is used by PrintFloat (decimal output) and Strictrounding 
899
                (binary or decimal output), so it must accommodate the larger space
900
                requirement:
901
                exponent: up to 12 chars.
902
                mantissa: prec + a little bit extra
903
*/
904

905
int SetFloatPrecision(WORD prec)
504✔
906
{
907
        if ( prec <= 0 ) {
504✔
908
                MesPrint("&Illegal value for number of bits for floating point constants: %d",prec);
×
909
                return(-1);
×
910
        }
911
        else {
912
                AC.DefaultPrecision = prec;
504✔
913
                if ( AO.floatspace != 0 ) M_free(AO.floatspace,"floatspace");
504✔
914
                AO.floatsize = (prec+20)*sizeof(char);
504✔
915
                AO.floatspace = (UBYTE *)Malloc1(AO.floatsize,"floatspace");
504✔
916
                mpf_set_default_prec(prec);
504✔
917
                return(0);
504✔
918
        }
919
}
920

921
/*
922
                 #] SetFloatPrecision : 
923
                 #[ PrintFloat :
924

925
        Print the float_ function with its arguments as a floating point
926
        number with numdigits digits.
927
        If however we use rawfloat as a format option it prints it as a
928
        regular Form function and it should never come here because the
929
        print routines in sch.c should intercept it.
930
        The buffer AO.floatspace is allocated when the precision of the
931
        floats is set in the routine SetFloatPrecision.
932
*/
933

934
int PrintFloat(WORD *fun,int numdigits)
4,914✔
935
{
936
        GETIDENTITY
3,276✔
937
        UBYTE *s1, *s2;
4,914✔
938
        int n = 0;
4,914✔
939
        int prec = (AC.DefaultPrecision-AC.MaxWeight-1)*log10(2.0);
4,914✔
940
        if ( numdigits > prec || numdigits == 0 ) {
4,914✔
941
                numdigits = prec;
4,626✔
942
        }
943
/* 
944
        GMP's gmp_snprintf always prints a non-zero number before the decimal point, so we 
945
        ask for one digit less. 
946
*/
947
        if ( UnpackFloat(aux4,fun) == 0 )
4,914✔
948
                n = gmp_snprintf((char *)(AO.floatspace),AO.floatsize,"%.*Fe",numdigits-1,aux4);
4,914✔
949
        if ( n > 0 ) {
4,914✔
950
                int n1, n2 = n;
4,914✔
951
                s1 = AO.floatspace+n;
4,914✔
952
                while ( s1 > AO.floatspace && s1[-1] != 'e'
30,576✔
953
                 && s1[-1] != 'E' && s1[-1] != '.' ) { s1--; n2--; }
25,662✔
954
                if ( s1 > AO.floatspace && s1[-1] != '.' ) {
4,914✔
955
                        s1--; n2--;
4,914✔
956
                        s2 = s1; n1 = n2;
4,914✔
957
                        while ( s1[-1] == '0' ) { s1--; n1--; }
32,574✔
958
                        if ( s1[-1] == '.' ) { s1++; n1++; }
4,914✔
959
                        n -= (n2-n1);
4,914✔
960
                        while ( n1 < n ) { *s1++ = *s2++; n1++; }
30,576✔
961
                        *s1 = 0;
4,914✔
962
                }
963
                if ( AC.OutputMode == FORTRANMODE ) {
4,914✔
964
                        s1 = AO.floatspace+n;
720✔
965
                        while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) { 
3,600✔
966
                                s1--; 
2,880✔
967
                        }
968
                        if ( ( AO.DoubleFlag & 2 ) == 2 ) { *s1 = 'Q'; } /* Quadruple precision fortran */
720✔
969
                        else if ( ( AO.DoubleFlag & 1 ) == 1 ) { *s1 = 'D'; } /* Double precision fortran */
576✔
970
                        else { *s1 = 'E'; } /* Single precision fortran */
432✔
971
                }
972
                if ( AC.OutputMode == MATHEMATICAMODE ) {
4,914✔
973
                        s1 = AO.floatspace+n;
144✔
974
                        s2 = s1+2; *s2-- = 0;
144✔
975
                        while ( s1 > AO.floatspace && *s1 != 'e' && *s1 != 'E' ) { 
720✔
976
                                *s2-- = *s1--; 
576✔
977
                        }
978
                        *s2-- = '^'; *s2 = '*'; /* Replace 'e' by '^*' */
144✔
979
                        n++;
144✔
980
                }
981
        }
982
        return(n);
4,914✔
983
}
984

985
/*
986
                 #] PrintFloat : 
987
                 #[ AddFloats :
988
*/
989

990
int AddFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
×
991
{
992
        int retval = 0;
×
993
        if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
×
994
                mpf_add(aux1,aux1,aux2);
×
995
                PackFloat(fun3,aux1);
×
996
        }
997
        else { retval = -1; }
998
        return(retval);
×
999
}
1000

1001
/*
1002
                 #] AddFloats : 
1003
                 #[ MulFloats :
1004
*/
1005

1006
int MulFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
×
1007
{
1008
        int retval = 0;
×
1009
        if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
×
1010
                mpf_mul(aux1,aux1,aux2);
×
1011
                PackFloat(fun3,aux1);
×
1012
        }
1013
        else { retval = -1; }
1014
        return(retval);
×
1015
}
1016

1017
/*
1018
                 #] MulFloats : 
1019
                 #[ DivFloats :
1020
*/
1021

1022
int DivFloats(PHEAD WORD *fun3, WORD *fun1, WORD *fun2)
×
1023
{
1024
        int retval = 0;
×
1025
        if ( UnpackFloat(aux1,fun1) == 0 && UnpackFloat(aux2,fun2) == 0 ) {
×
1026
                mpf_div(aux1,aux1,aux2);
×
1027
                PackFloat(fun3,aux1);
×
1028
        }
1029
        else { retval = -1; }
1030
        return(retval);
×
1031
}
1032

1033
/*
1034
                 #] DivFloats : 
1035
                 #[ AddRatToFloat :
1036

1037
                Note: this can be optimized, because often the rat is rather simple.
1038
*/
1039

1040
int AddRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat)
×
1041
{
1042
        int retval = 0;
×
1043
        if ( UnpackFloat(aux2,infun) == 0 ) {
×
1044
                RatToFloat(aux1,formrat,nrat);
×
1045
                mpf_add(aux2,aux2,aux1);
×
1046
                PackFloat(outfun,aux2);
×
1047
        }
1048
        else retval = -1;
1049
        return(retval);
×
1050
}
1051

1052
/*
1053
                 #] AddRatToFloat : 
1054
                 #[ MulRatToFloat :
1055

1056
                Note: this can be optimized, because often the rat is rather simple.
1057
*/
1058

1059
int MulRatToFloat(PHEAD WORD *outfun, WORD *infun, UWORD *formrat, WORD nrat)
×
1060
{
1061
        int retval = 0;
×
1062
        if ( UnpackFloat(aux2,infun) == 0 ) {
×
1063
                RatToFloat(aux1,formrat,nrat);
×
1064
                mpf_mul(aux2,aux2,aux1);
×
1065
                PackFloat(outfun,aux2);
×
1066
        }
1067
        else retval = -1;
1068
        return(retval);
×
1069
}
1070

1071
/*
1072
                 #] MulRatToFloat : 
1073
                 #[ SetupMZVTables :
1074
*/
1075

1076
void SetupMZVTables(void)
246✔
1077
{
1078
/*
1079
        Sets up a table of N+1 mpf_t floats with variable precision.
1080
        It assumes that each next element needs one bit less.
1081
        Initializes all of them.
1082
        We take some extra space, to have one limb overflow everywhere.
1083
        Because the depth of the MZV's can get close to the weight
1084
        and each deeper sum goes one higher, we make the tablesize a bit bigger.
1085
        This may not be needed if we fiddle with the sum boundaries.
1086
*/
1087
#ifdef WITHPTHREADS
1088
        int i, Nw, id, totnum;
164✔
1089
        size_t N;
164✔
1090
        mpf_t *a;
164✔
1091
        Nw = AC.DefaultPrecision;
164✔
1092
        N = (size_t)Nw;
164✔
1093
        totnum = AM.totalnumberofthreads;
164✔
1094
    for ( id = 0; id < totnum; id++ ) {
820✔
1095
                AB[id]->T.mpf_tab1 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab1");
656✔
1096
                a = (mpf_t *)AB[id]->T.mpf_tab1;
656✔
1097
                for ( i = 0; i <=Nw; i++ ) {
43,680✔
1098
/*
1099
        As explained in the comment above, we could make this variable precision
1100
        using mpf_init2.
1101
*/
1102
                        mpf_init(a[i]);
43,024✔
1103
                }
1104
                AB[id]->T.mpf_tab2 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab2");
656✔
1105
                a = (mpf_t *)AB[id]->T.mpf_tab2;
656✔
1106
                for ( i = 0; i <=Nw; i++ ) {
43,680✔
1107
                        mpf_init(a[i]);
43,024✔
1108
                }
1109
        }
1110
#else
1111
        int i, Nw;
82✔
1112
        size_t N;
82✔
1113
        Nw = AC.DefaultPrecision;
82✔
1114
        N = (size_t)Nw;
82✔
1115
        AT.mpf_tab1 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab1");
82✔
1116
        for ( i = 0; i <= Nw; i++ ) {
5,460✔
1117
/*
1118
        As explained in the comment above, we could make this variable precision
1119
        using mpf_init2.
1120
*/
1121
                mpf_init(mpftab1[i]);
5,378✔
1122
        }
1123
        AT.mpf_tab2 = (void *)Malloc1((N+2)*sizeof(mpf_t),"mpftab2");
82✔
1124
        for ( i = 0; i <= Nw; i++ ) {
5,460✔
1125
                mpf_init(mpftab2[i]);
5,378✔
1126
        }
1127
#endif
1128
        AS.delta_1 = (void *)Malloc1(sizeof(mpf_t),"delta1");
246✔
1129
        mpf_init(mpfdelta1);
246✔
1130
        SimpleDelta(mpfdelta1,1); /* this can speed up things. delta1 = ln(2) */
246✔
1131
}
246✔
1132

1133
/*
1134
                 #] SetupMZVTables : 
1135
                 #[ SetupMPFTables :
1136
        
1137
                Allocates the aux variables
1138
*/
1139

1140
void SetupMPFTables(void)
504✔
1141
{
1142
#ifdef WITHPTHREADS
1143
        int id, totnum;
336✔
1144
        mpf_t *a;
336✔
1145
#ifdef WITHSORTBOTS
1146
        totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
336✔
1147
#endif
1148
    for ( id = 0; id < totnum; id++ ) {
2,016✔
1149
/*
1150
                We work here with a[0] etc because the aux1 etc contain B which
1151
                in the current routine would be AB[0] only
1152
*/
1153
                AB[id]->T.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AB[id]->T.aux_");
1,680✔
1154
                a = (mpf_t *)AB[id]->T.aux_;
1,680✔
1155
                mpf_inits(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
1,680✔
1156
                if ( AB[id]->T.indi1 ) M_free(AB[id]->T.indi1,"indi1");
1,680✔
1157
                AB[id]->T.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
1,680✔
1158
                AB[id]->T.indi2 = AB[id]->T.indi1 + AC.MaxWeight;
1,680✔
1159
        }
1160
#else
1161
        AT.aux_ = (void *)Malloc1(sizeof(mpf_t)*8,"AT.aux_");
168✔
1162
        mpf_inits(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
168✔
1163
        if ( AT.indi1 ) M_free(AT.indi1,"indi1");
168✔
1164
        AT.indi1 = (WORD *)Malloc1(sizeof(WORD)*AC.MaxWeight*2,"indi1");
168✔
1165
        AT.indi2 = AT.indi1 + AC.MaxWeight;
168✔
1166
#endif
1167
}
504✔
1168

1169
/*
1170
                 #] SetupMPFTables : 
1171
                 #[ ClearMZVTables :
1172
*/
1173

1174
void ClearMZVTables(void)
252✔
1175
{
1176
#ifdef WITHPTHREADS
1177
        int i, id, totnum;
168✔
1178
        mpf_t *a;
168✔
1179
        totnum = AM.totalnumberofthreads;
168✔
1180
    for ( id = 0; id < totnum; id++ ) {
840✔
1181
                if ( AB[id]->T.mpf_tab1 ) { 
672✔
1182
/*
1183
                        We work here with a[0] etc because the aux1, mpftab1 etc contain B 
1184
                        which in the current routine would be AB[0] only
1185
*/
1186
                        a = (mpf_t *)AB[id]->T.mpf_tab1;
39,344✔
1187
                        for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
39,344✔
1188
                                mpf_clear(a[i]);
38,784✔
1189
                        }
1190
                        M_free(AB[id]->T.mpf_tab1,"mpftab1"); 
560✔
1191
                        AB[id]->T.mpf_tab1 = 0; 
560✔
1192
                }
1193
                if ( AB[id]->T.mpf_tab2 ) { 
672✔
1194
                        a = (mpf_t *)AB[id]->T.mpf_tab2;
39,344✔
1195
                        for ( i = 0; i <=AC.DefaultPrecision; i++ ) {
39,344✔
1196
                                mpf_clear(a[i]);
38,784✔
1197
                        }
1198
                        M_free(AB[id]->T.mpf_tab2,"mpftab2"); 
560✔
1199
                        AB[id]->T.mpf_tab2 = 0; 
560✔
1200
                }
1201
        }
1202
#ifdef WITHSORTBOTS
1203
        totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
168✔
1204
#endif
1205
    for ( id = 0; id < totnum; id++ ) {
1,008✔
1206
                if ( AB[id]->T.aux_ ) { 
840✔
1207
                        a = (mpf_t *)AB[id]->T.aux_;
840✔
1208
                        mpf_clears(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],(mpf_ptr)0);
840✔
1209
                        M_free(AB[id]->T.aux_,"AB[id]->T.aux_");
840✔
1210
                        AB[id]->T.aux_ = 0; 
840✔
1211
                }
1212
                if ( AB[id]->T.indi1 ) { M_free(AB[id]->T.indi1,"indi1"); AB[id]->T.indi1 = 0; }
840✔
1213
        }
1214
#else
1215
        int i;
84✔
1216
        if ( AT.mpf_tab1 ) { 
84✔
1217
                for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
4,918✔
1218
                        mpf_clear(mpftab1[i]);
4,848✔
1219
                }
1220
                M_free(AT.mpf_tab1,"mpftab1"); 
70✔
1221
                AT.mpf_tab1 = 0; 
70✔
1222
        }
1223
        if ( AT.mpf_tab2 ) { 
84✔
1224
                for ( i = 0; i <= AC.DefaultPrecision; i++ ) {
4,918✔
1225
                        mpf_clear(mpftab2[i]);
4,848✔
1226
                }
1227
                M_free(AT.mpf_tab2,"mpftab2"); 
70✔
1228
                AT.mpf_tab2 = 0; 
70✔
1229
        }
1230
        if ( AT.aux_ ) { 
84✔
1231
                mpf_clears(aux1,aux2,aux3,aux4,aux5,auxjm,auxjjm,auxsum,(mpf_ptr)0);
84✔
1232
                M_free(AT.aux_,"AT.aux_"); 
84✔
1233
                AT.aux_ = 0; 
84✔
1234
        }
1235
        if ( AT.indi1 ) { M_free(AT.indi1,"indi1"); AT.indi1 = 0; }
84✔
1236
#endif
1237
        if ( AO.floatspace ) { M_free(AO.floatspace,"floatspace"); AO.floatspace = 0;
252✔
1238
                AO.floatsize = 0; }
252✔
1239
        if ( AS.delta_1 ) { 
252✔
1240
                mpf_clear(mpfdelta1);
210✔
1241
                M_free(AS.delta_1,"delta1"); 
210✔
1242
                AS.delta_1 = 0; 
210✔
1243
        }
1244
}
252✔
1245

1246
/*
1247
                 #] ClearMZVTables : 
1248
                 #[ CoToFloat :
1249
*/
1250

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

1268
/*
1269
                 #] CoToFloat : 
1270
                 #[ CoToRat :
1271
*/
1272

1273
int CoToRat(UBYTE *s)
12✔
1274
{
1275
        GETIDENTITY
8✔
1276
        if ( AT.aux_ == 0 ) {
12✔
1277
                MesPrint("&Illegal attempt to convert from float_ without activating floating point numbers.");
6✔
1278
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
1279
                return(1);
6✔
1280
        }
1281
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
6✔
1282
        if ( *s ) {
6✔
1283
                MesPrint("&Illegal argument(s) in ToRat statement: '%s'",s);
×
1284
                return(1);
×
1285
        }
1286
        Add2Com(TYPETORAT);
6✔
1287
        return(0);
6✔
1288
}
1289

1290
/*
1291
                 #] CoToRat : 
1292
                 #[ CoStrictRounding : 
1293

1294
                Syntax: StrictRounding [precision][base]
1295
                - precision: number of digits to round to (optional)
1296
                - base: 'd' for decimal (base 10) or 'b' for binary (base 2)
1297
                
1298
                If no arguments are provided, uses default precision with binary base.
1299
*/
1300
int CoStrictRounding(UBYTE *s)
42✔
1301
{
1302
        GETIDENTITY
28✔
1303
        WORD x;
42✔
1304
        int base;
42✔
1305
        if ( AT.aux_ == 0 ) {
42✔
1306
                MesPrint("&Illegal attempt for strict rounding without activating floating point numbers.");
6✔
1307
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
1308
                return(1);
6✔
1309
        }
1310
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
36✔
1311
        if ( *s == 0 ) {
36✔
1312
                /* No subkey, which means round to default precision */
1313
                x = AC.DefaultPrecision - AC.MaxWeight - 1;
6✔
1314
                base = 2;
6✔
1315
        }
1316
        else if ( FG.cTable[*s] == 1 ) { /* number */
30✔
1317
                ParseNumber(x,s)
48✔
1318
                if ( tolower(*s) == 'd' ) { base = 10; s++; }      /* decimal base */
24✔
1319
                else if ( tolower(*s) == 'b' ){ base = 2; s++; }  /* binary base */
18✔
1320
                else goto IllPar;  /* invalid base specification */
12✔
1321
        }
1322
        else {
1323
                goto IllPar;
6✔
1324
        }
1325
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
18✔
1326
        
1327
        /* Check for invalid arguments */
1328
        if ( *s ) {
18✔
1329
IllPar:
×
1330
                MesPrint("&Illegal argument(s) in StrictRounding statement: '%s'",s);
18✔
1331
                return(1);
18✔
1332
        }
1333
        Add4Com(TYPESTRICTROUNDING,x,base);
18✔
1334
        return(0);
18✔
1335
} 
1336
/*
1337
                 #] CoStrictRounding : 
1338
                 #[ CoChop :
1339

1340
                LHS notation of the chop statement: 
1341
                        TYPECHOP, length, FLOATFUN, ... 
1342
                where FLOATFUN, ... represents the threshold of the chop statement in 
1343
                the notation of a float_ function with its arguments. 
1344

1345
*/
1346

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

1368
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
30✔
1369
        
1370
        /* 
1371
                The argument of chop can be 
1372
                 1: a floating-point number
1373
                 2: an integer, rational number or power
1374
         */
1375
        if ( FG.cTable[*s] == 1 || *s == '.' ) { 
30✔
1376
                /* 1: Attempt to parse as floating-point number */
1377
                ss = CheckFloat(s, &spec);
30✔
1378
                if ( ss > s ) {
30✔
1379
                        /* CheckFloat found a valid float */
1380
                        AT.WorkPointer = w;
6✔
1381
                        /* 
1382
                                Reads the floating point number and outputs it at AT.WorkPointer as if it were a float_ 
1383
                                function with its arguments.
1384
                         */
1385
                        ReadFloat((SBYTE *)s); 
6✔
1386
                        s = ss;
6✔
1387
                        w += w[1];
6✔
1388
                }
1389
                else {
1390
                        /* 2: CheckFloat didn't find a float, we now try for rationals and powers */
1391
                        /* Parse the integer part (numerator for rationals) */
1392
                        if ( FG.cTable[*s] == 1 ) {
24✔
1393
                                ParseNumber(x,s)
60✔
1394
                                mpf_set_ui(aux1,x);
24✔
1395
                        }
1396
                        while ( *s == ' ' || *s == '\t' ) s++;
24✔
1397
                        /* Check for rational number or power*/
1398
                        if ( *s == '/' || *s == '^' ) {
24✔
1399
                                c = *s; s++; 
18✔
1400
                                while ( *s == ' ' || *s == '\t' ) s++;
18✔
1401
                                if ( *s == '-' ) { s++; pow = -1; } /* negative power */
18✔
1402
                                /* Parse the denominator or power */
1403
                                if ( FG.cTable[*s] == 1 ) {
18✔
1404
                                        ParseNumber(x,s)
60✔
1405
                                        if ( c == '/' ) { /* rational */
18✔
1406
                                                if ( x == 0 ) {
6✔
1407
                                                        MesPrint("&Division by zero in chop statement.");
×
1408
                                                        return(1);
×
1409
                                                }
1410
                                                /* Perform the division */
1411
                                                mpf_div_ui(aux1, aux1,x);
6✔
1412
                                        }
1413
                                        else { /* Power */
1414
                                                mpf_pow_ui(aux1,aux1,x);
12✔
1415
                                                if ( pow == -1 ) {
12✔
1416
                                                        mpf_ui_div(aux1,(unsigned long) 1, aux1);
6✔
1417
                                                }
1418
                                        }
1419
                                }
1420
                        }
1421
                        /* Put aux1 in the notation of a float_ function */
1422
                        PackFloat(w, aux1);
24✔
1423
                        w += w[1];
24✔
1424
                }
1425
        }
1426
        if ( *s ) {
30✔
1427
                MesPrint("&Illegal argument(s) in Chop statement: '%s'",s);
×
1428
                return(1);
×
1429
        }
1430
        AT.WorkPointer = OldWork;
30✔
1431
        AT.WorkPointer[1] = w - AT.WorkPointer;  /* Set total length */
30✔
1432
        AddNtoL(AT.WorkPointer[1],AT.WorkPointer); /* Add the LHS to the compiler buffer */
30✔
1433
        return(0);
30✔
1434
}
1435

1436
/*
1437
                 #] CoChop : 
1438
                 #[ ToFloat :
1439

1440
                Converts the coefficient to floating point if it is still a rat.
1441
*/
1442

1443
int ToFloat(PHEAD WORD *term, WORD level)
282✔
1444
{
1445
        WORD *t, *tstop, nsize, nsign = 3;
282✔
1446
        t = term+*term;
282✔
1447
        nsize = ABS(t[-1]);
282✔
1448
        tstop = t - nsize;
282✔
1449
        if ( t[-1] < 0 ) { nsign = -nsign; }
282✔
1450
        if ( nsize == 3 && t[-2] == 1 && t[-3] == 1 ) { /* Could be float */
282✔
1451
                t = term + 1;
144✔
1452
                while ( t < tstop ) {
282✔
1453
                        if ( ( *t == FLOATFUN ) && ( t+t[1] == tstop ) ) {
138✔
1454
                                return(Generator(BHEAD term,level));
×
1455
                        }
1456
                        t += t[1];
138✔
1457
                }
1458
        }
1459
        RatToFloat(aux4,(UWORD *)tstop,nsize);
282✔
1460
        PackFloat(tstop,aux4);
282✔
1461
        tstop += tstop[1];
282✔
1462
        *tstop++ = 1; *tstop++ = 1; *tstop++ = nsign;
282✔
1463
        *term = tstop - term;
282✔
1464
        AT.WorkPointer = tstop;
282✔
1465
        return(Generator(BHEAD term,level));
282✔
1466
}
1467

1468
/*
1469
                 #] ToFloat : 
1470
                 #[ ToRat :
1471

1472
                Tries to convert the coefficient to rational if it is still a float.
1473
*/
1474

1475
int ToRat(PHEAD WORD *term, WORD level)
6✔
1476
{
1477
        WORD *tstop, *t, nsize, nsign, ncoef;
6✔
1478
/*
1479
        1: find the float which should be at the end.
1480
*/
1481
        tstop = term + *term; nsize = ABS(tstop[-1]);
6✔
1482
        nsign = tstop[-1] < 0 ? -1: 1; tstop -= nsize;
6✔
1483
        t = term+1;
6✔
1484
        while ( t < tstop ) {
6✔
1485
                if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
6✔
1486
                nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
6✔
1487
                t += t[1];
×
1488
        }
1489
        if ( t < tstop ) {
6✔
1490
/*
1491
                Now t points at the float_ function and everything is correct.
1492
                The result can go straight over the float_ function.
1493
*/
1494
                UnpackFloat(aux4,t);
6✔
1495
                if ( FloatToRat((UWORD *)t,&ncoef,aux4) == 0 ) {
6✔
1496
                        t += ABS(ncoef);
6✔
1497
                        t[-1] = ncoef*nsign;
6✔
1498
                        *term = t - term;
6✔
1499
                }
1500
        }
1501
        return(Generator(BHEAD term,level));
6✔
1502
}
1503

1504
/*
1505
                 #] ToRat : 
1506
                 #[ StrictRounding : 
1507

1508
                Rounds floating point numbers to a specified precision
1509
                in a given base (decimal or binary).
1510
*/
1511
int StrictRounding(PHEAD WORD *term, WORD level, WORD prec, WORD base) {
36✔
1512
        WORD *t,*tstop;
36✔
1513
        int sign,size,maxprec = AC.DefaultPrecision-AC.MaxWeight-1;
36✔
1514
        /* maxprec is in bits */
1515
        if ( base == 2 && prec > maxprec ) {
36✔
1516
                prec = maxprec;
1517
        }
1518
        if ( base == 10 && prec > (int)(maxprec*log10(2.0)) ) {
36✔
1519
                prec = maxprec*log10(2.0);
×
1520
        }
1521
        /* Find the float which should be at the end. */
1522
        tstop = term + *term; size = ABS(tstop[-1]);
36✔
1523
        sign = tstop[-1] < 0 ? -1: 1; tstop -= size;
36✔
1524
        t = term+1;
36✔
1525
        while ( t < tstop ) {
48✔
1526
                if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
36✔
1527
                size == 3 && tstop[0] == 1 && tstop[1] == 1) {
24✔
1528
                        break;
1529
                }
1530
                t += t[1];
12✔
1531
        }
1532
        if ( t < tstop ) {
36✔
1533
/*
1534
                Now t points at the float_ function and everything is correct.
1535
                The result can go straight over the float_ function.
1536
*/
1537
                char *s;
24✔
1538
                mp_exp_t exp;
24✔
1539
                /* Extract the floating point value */
1540
                UnpackFloat(aux4,t);
24✔
1541
                /* Convert to string: 
1542
                   - Format as MeN with M the mantissa and N the exponent 
1543
                   - the generated string by mpf_get_str is the fraction/mantissa with 
1544
                   an implicit radix point immediately to the left of the first digit. 
1545
                   The applicable exponent is written in exp. */
1546
                s = (char *)AO.floatspace;
24✔
1547
                *s++ = '.';
24✔
1548
                mpf_get_str(s,&exp, base, prec, aux4);
24✔
1549
                while ( *s != 0 ) s++;
90✔
1550
                *s++ = 'e';
24✔
1551
                snprintf(s,AO.floatsize-(s-(char *)AO.floatspace),"%ld",exp);
24✔
1552
                /* Negative base values are used to specify that the exponent is in decimal */
1553
                mpf_set_str(aux4,(char *)AO.floatspace,-base);
24✔
1554
                /* Pack the rounded floating point value back into the term */
1555
                PackFloat(t,aux4);
24✔
1556
                t+=t[1];
24✔
1557
                *t++ = 1; *t++ = 1; *t++ = 3*sign;
24✔
1558
                *term = t - term;
24✔
1559
        }
1560
        return(Generator(BHEAD term,level));
36✔
1561
}
1562
/*
1563
                 #] StrictRounding : 
1564
                 #[ Chop :
1565

1566
        Removes terms with a floating point number smaller than a given threshold. 
1567
 
1568
        Search for a FLOATFUN and compares its absolute value against the threshold 
1569
        specified in the chop statement. This threshold can be obtained from the 
1570
        LHS of the chop statement in the compiler buffer.
1571
 
1572
 */
1573
int Chop(PHEAD WORD *term, WORD level)
150✔
1574
{
1575
        WORD *tstop, *t, nsize, *threshold; 
150✔
1576
        CBUF *C = cbuf+AM.rbufnum;
150✔
1577
        /* Find the float which should be at the end. */
1578
        tstop = term + *term; 
150✔
1579
        nsize = ABS(tstop[-1]); tstop -= nsize;
150✔
1580
        t = term+1;
150✔
1581
        while ( t < tstop ) {
300✔
1582
                if ( *t == FLOATFUN && t + t[1] == tstop && TestFloat(t) &&
270✔
1583
                nsize == 3 && tstop[0] == 1 && tstop[1] == 1 ) break;
120✔
1584
                t += t[1];
150✔
1585
        }
1586
        if ( t < tstop ) {
150✔
1587
                /* Get threshold value from compiler buffer */
1588
                threshold = C->lhs[level];
120✔
1589
                threshold += 2;  /* Skip TYPECHOP header */
120✔
1590
                UnpackFloat(aux5, threshold); 
120✔
1591
                
1592
                /* Extract float and compute its absolute value */
1593
                UnpackFloat(aux4, t);
120✔
1594
                mpf_abs(aux4, aux4);
120✔
1595
                
1596
                /* Remove if < threshold */
1597
                if ( mpf_cmp(aux4, aux5) < 0 ) return(0);
120✔
1598
        }
1599
        return(Generator(BHEAD term,level));
66✔
1600
}
1601

1602
/*
1603
                 #] Chop : 
1604
          #] Float Routines : 
1605
          #[ Sorting :
1606

1607
                We need a method to see whether two terms need addition that could
1608
                involve floating point numbers.
1609
                1: if PolyWise is active, we do not need anything, because
1610
                   Poly(Rat)Fun and floating point are mutually exclusive.
1611
                2: This means that there should be only interference in AddCoef.
1612
                   and the AddRat parts in MergePatches, MasterMerge, SortBotMerge
1613
                   and PF_GetLoser.
1614
                The compare routine(s) should recognise the float_ and give off
1615
                a code (SortFloatMode) inside the AT struct:
1616
                0: no float_
1617
                1: float_ in term1 only
1618
                2: float_ in term2 only
1619
                3: float_ in both terms
1620
                Be careful: we have several compare routines, because various codes
1621
                use their own routines and we just set a variable with its address.
1622
                Currently we have Compare1, CompareSymbols and CompareHSymbols.
1623
                Only Compare1 should be active for this. The others should make sure
1624
                that the proper variable is always zero.
1625
                Remember: the sign of the coefficient is in the last word of the term.
1626

1627
                We need two routines:
1628
                1: AddWithFloat for SplitMerge which sorts by pointer.
1629
                2: MergeWithFloat for MergePatches etc which keeps terms as much
1630
                   as possible in their location.
1631
                The routines start out the same, because AT.SortFloatMode, set in
1632
                Compare1, tells more or less what should be done.
1633
                The difference is in where we leave the result.
1634

1635
                In the future we may want to add a feature that makes the result
1636
                zero if the sum comes within a certain distance of the numerical
1637
                accuracy, like for instance 5% of the number of bits.
1638

1639
                 #[ AddWithFloat :
1640
*/
1641

1642
int AddWithFloat(PHEAD WORD **ps1, WORD **ps2)
2,616✔
1643
{
1644
        GETBIDENTITY
1645
        SORTING *S = AT.SS;
2,616✔
1646
        WORD *coef1, *coef2, size1, size2, *fun1, *fun2, *fun3;
2,616✔
1647
        WORD *s1,*s2,sign3,j,jj, *t1, *t2, i;
2,616✔
1648
        s1 = *ps1;
2,616✔
1649
        s2 = *ps2;
2,616✔
1650
        coef1 = s1+*s1; size1 = coef1[-1]; coef1 -= ABS(coef1[-1]);
2,616✔
1651
        coef2 = s2+*s2; size2 = coef2[-1]; coef2 -= ABS(coef2[-1]);
2,616✔
1652
        if ( AT.SortFloatMode == 3 ) {
2,616✔
1653
                fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
3,906✔
1654
                fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
3,906✔
1655
                UnpackFloat(aux1,fun1);
2,022✔
1656
                if ( size1 < 0 ) mpf_neg(aux1,aux1);
2,022✔
1657
                UnpackFloat(aux2,fun2);
2,022✔
1658
                if ( size2 < 0 ) mpf_neg(aux2,aux2);
2,022✔
1659
        }
1660
        else if ( AT.SortFloatMode == 1 ) {
594✔
1661
                fun1 = s1+1; while ( fun1 < coef1 && fun1[0] != FLOATFUN ) fun1 += fun1[1];
306✔
1662
                UnpackFloat(aux1,fun1);
156✔
1663
                if ( size1 < 0 ) mpf_neg(aux1,aux1);
156✔
1664
                fun2 = coef2;
156✔
1665
                RatToFloat(aux2,(UWORD *)coef2,size2);
156✔
1666
        }
1667
        else if ( AT.SortFloatMode == 2 ) {
438✔
1668
                fun2 = s2+1; while ( fun2 < coef2 && fun2[0] != FLOATFUN ) fun2 += fun2[1];
876✔
1669
                fun1 = coef1;
438✔
1670
                RatToFloat(aux1,(UWORD *)coef1,size1);
438✔
1671
                UnpackFloat(aux2,fun2);
438✔
1672
                if ( size2 < 0 ) mpf_neg(aux2,aux2);
438✔
1673
        }
1674
        else {
1675
                MLOCK(ErrorMessageLock);
×
1676
                MesPrint("Illegal value %d for AT.SortFloatMode in AddWithFloat.",AT.SortFloatMode);
×
1677
                MUNLOCK(ErrorMessageLock);
×
1678
                Terminate(-1);
×
1679
                return(0);
×
1680
        }
1681
        mpf_add(aux3,aux1,aux2);
2,616✔
1682
        sign3 = mpf_sgn(aux3);
2,616✔
1683
        if ( sign3 < 0 ) mpf_neg(aux3,aux3);
2,616✔
1684
        fun3 = TermMalloc("AddWithFloat");
2,616✔
1685
        PackFloat(fun3,aux3);
2,616✔
1686
/*
1687
        Now we have to calculate where the sumterm fits.
1688
        If we are sloppy, we can be faster, but run the risk to need the
1689
        extension space, even when it is not needed. At slightly lower speed
1690
        (ie first creating the result in scribble space) we are better off.
1691
        This is why we use TermMalloc.
1692

1693
        The new term will have a rational coefficient of 1,1,+-3.
1694
        The size will be (fun1 or fun2 - term) + fun3 +3;
1695
*/
1696
        if ( AT.SortFloatMode == 3 ) {
2,616✔
1697
                if ( fun1[1] == fun3[1]  ) {
2,022✔
1698
Over1:
738✔
1699
                        i = fun3[1]; t1 = fun1; t2 = fun3; NCOPY(t1,t2,i);
33,972✔
1700
                        *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
1,962✔
1701
                        *s1 = t1-s1; goto Finished;
1,962✔
1702
                }
1703
                else if ( fun2[1] == fun3[1]  ) {
1,284✔
1704
Over2:
198✔
1705
                        i = fun3[1]; t1 = fun2; t2 = fun3; NCOPY(t1,t2,i);
10,380✔
1706
                        *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
630✔
1707
                        *s2 = t1-s2; *ps1 = s2; goto Finished;
630✔
1708
                }
1709
                else if ( fun1[1] >= fun3[1]  ) goto Over1;
1,086✔
1710
                else if ( fun2[1] >= fun3[1]  ) goto Over2;
12✔
1711
        }
1712
        else if ( AT.SortFloatMode == 1 ) {
594✔
1713
                if ( fun1[1] >= fun3[1]  ) goto Over1;
156✔
1714
                else if ( fun3[1]+3 <= ABS(size2) ) goto Over2;
6✔
1715
        }
1716
        else if ( AT.SortFloatMode == 2 ) {
438✔
1717
                if ( fun2[1] >= fun3[1]  ) goto Over2;
438✔
1718
                else if ( fun3[1]+3 <= ABS(size1) ) goto Over1;
12✔
1719
        }
1720
/*
1721
        Does not fit. Go to extension space.
1722
*/
1723
        jj = fun1-s1;
24✔
1724
        j = jj+fun3[1]+3; /* space needed */
24✔
1725
        if ( (S->sFill + j) >= S->sTop2 ) {
24✔
1726
                GarbHand();
×
1727
                s1 = *ps1; /* new position of the term after the garbage collection */
×
1728
                fun1 = s1+jj;
×
1729
        }
1730
        t1 = S->sFill;
24✔
1731
        for ( i = 0; i < jj; i++ ) *t1++ = s1[i];
120✔
1732
        i = fun3[1]; s1 = fun3; NCOPY(t1,s1,i);
744✔
1733
        *t1++ = 1; *t1++ = 1; *t1++ = sign3 < 0 ? -3: 3;
24✔
1734
        *ps1 = S->sFill;
24✔
1735
        **ps1 = t1-*ps1;
24✔
1736
        S->sFill = t1;
24✔
1737
Finished:
2,616✔
1738
        *ps2 = 0;
2,616✔
1739
        TermFree(fun3,"AddWithFloat");
2,616✔
1740
        AT.SortFloatMode = 0;
2,616✔
1741
        if ( **ps1 > AM.MaxTer/((LONG)(sizeof(WORD))) ) {
2,616✔
1742
                MLOCK(ErrorMessageLock);
×
1743
                MesPrint("Term too complex after addition in sort. MaxTermSize = %10l",
×
1744
                AM.MaxTer/sizeof(WORD));
×
1745
                MUNLOCK(ErrorMessageLock);
×
1746
                Terminate(-1);
×
1747
        }
1748
        return(1);
1749
}
1750

1751
/*
1752
                 #] AddWithFloat : 
1753
                 #[ MergeWithFloat :
1754

1755
                Note that we always park the result on top of term1.
1756
                This makes life easier, because the original AddRat in MergePatches
1757
                does this as well.
1758
*/
1759

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

1854
/*
1855
                 #] MergeWithFloat : 
1856
          #] Sorting : 
1857
          #[ MZV :
1858

1859
                The functions here allow the arbitrary precision calculation
1860
                of MZV's and Euler sums.
1861
                They are called when the functions mzv_ and/or euler_ are used
1862
                and the evaluate statement is applied.
1863
                The output is in a float_ function.
1864
                The expand statement tries to express the functions in terms of a basis.
1865
                The bases are the 'standard basis for the euler sums and the
1866
                pushdown bases from the datamine, unless otherwise specified.
1867

1868
                 #[ SimpleDelta :
1869
*/
1870

1871
void SimpleDelta(mpf_t sum, int m)
2,940✔
1872
{
1873
        long s = 1;
2,940✔
1874
        long prec = AC.DefaultPrecision;
2,940✔
1875
        unsigned long xprec = (unsigned long)prec, x;
2,940✔
1876
        int j, jmax, n;
2,940✔
1877
        mpf_t jm,jjm;
2,940✔
1878
        mpf_init(jm); mpf_init(jjm);
2,940✔
1879
        if ( m < 0 ) { s = -1; m = -m; }
2,940✔
1880

1881
/*
1882
        We will loop until 1/2^j/j^m is smaller than the default precision.
1883
        Just running to prec is however overkill, specially when m is large.
1884
        We try to estimate a better value.
1885
        jmax = prec - ((log2(prec)-1)*m).
1886
        Hence we need the leading bit of prec.
1887
        We are still overshooting a bit.
1888
*/
1889
        n = 0; x = xprec;
2,940✔
1890
        while ( x ) { x >>= 1; n++; }
27,252✔
1891
/* 
1892
        We have now n = floor(log2(x))+1. 
1893
*/
1894
        n--;
2,940✔
1895
        jmax = (int)((int)xprec - (n-1)*m);
2,940✔
1896
/*
1897
        For small prec and large m, the estimate can be wrong and even be negative, 
1898
        so we increase jmax until jmax + m*log2(jmax) > prec
1899
*/
1900
        if ( jmax < 0 ) jmax = 1;
2,940✔
1901
        do {
2,940✔
1902
                n = 0;
2,940✔
1903
                x = (unsigned long)jmax;
2,940✔
1904
                while (x) { x >>= 1; n++; }
25,560✔
1905
                n--; // floor(log2(jmax))
2,940✔
1906
                jmax++; 
2,940✔
1907
        } while ( jmax + m * n <= prec );
2,940✔
1908
        mpf_set_ui(sum,0);
2,940✔
1909
        for ( j = 1; j <= jmax; j++ ) {
796,236✔
1910
#ifdef WITHCUTOFF
1911
                xprec--;
790,356✔
1912
                mpf_set_prec_raw(jm,xprec);
790,356✔
1913
                mpf_set_prec_raw(jjm,xprec);
790,356✔
1914
#endif
1915
                mpf_set_ui(jm,1L);
790,356✔
1916
                mpf_div_ui(jjm,jm,(unsigned long)j);
790,356✔
1917
                mpf_pow_ui(jm,jjm,(unsigned long)m);
790,356✔
1918
                mpf_div_2exp(jjm,jm,(unsigned long)j);
790,356✔
1919
                if ( s == -1 && j%2 == 1 ) mpf_sub(sum,sum,jjm);
790,356✔
1920
                else                       mpf_add(sum,sum,jjm);
781,608✔
1921
        }
1922
        mpf_clear(jjm); mpf_clear(jm);
2,940✔
1923
}
2,940✔
1924

1925
/*
1926
                 #] SimpleDelta : 
1927
                 #[ SimpleDeltaC :
1928
*/
1929

1930
void SimpleDeltaC(mpf_t sum, int m)
240✔
1931
{
1932
        long s = 1;
240✔
1933
        long prec = AC.DefaultPrecision;
240✔
1934
        unsigned long xprec = (unsigned long)prec, x;
240✔
1935
        int j, jmax, n;
240✔
1936
        mpf_t jm,jjm;
240✔
1937
        mpf_init(jm); mpf_init(jjm);
240✔
1938
        if ( m < 0 ) { s = -1; m = -m; }
240✔
1939
/*
1940
        We will loop until 1/2^j/j^m is smaller than the default precision.
1941
        Just running to prec is however overkill, specially when m is large.
1942
        We try to estimate a better value.
1943
        jmax = prec - ((log2(prec)-1)*m).
1944
        Hence we need the leading bit of prec.
1945
        We are still overshooting a bit.
1946
*/
1947
        n = 0; x = xprec;
240✔
1948
        while ( x ) { x >>= 1; n++; }
1,920✔
1949
/* 
1950
        We have now n = floor(log2(x))+1. 
1951
*/
1952
        n--;
240✔
1953
        jmax = (int)((int)xprec - (n-1)*m);
240✔
1954
/*
1955
        For small prec and large m, the estimate can be wrong and even be negative, 
1956
        so we increase jmax until jmax + m*log2(jmax) > prec
1957
*/
1958
        if ( jmax < 0 ) jmax = 1;
240✔
1959
        do {
240✔
1960
                n = 0;
240✔
1961
                x = (unsigned long)jmax;
240✔
1962
                while (x) { x >>= 1; n++; }
1,908✔
1963
                n--; // floor(log2(jmax))
240✔
1964
                jmax++; 
240✔
1965
        } while ( jmax + m * n <= prec );
240✔
1966
        if ( s < 0 ) jmax /= 2;
240✔
1967
        mpf_set_si(sum,0L);
240✔
1968
        for ( j = 1; j <= jmax; j++ ) {
9,084✔
1969
#ifdef WITHCUTOFF
1970
                xprec--;
8,604✔
1971
                mpf_set_prec_raw(jm,xprec);
8,604✔
1972
                mpf_set_prec_raw(jjm,xprec);
8,604✔
1973
#endif
1974
                mpf_set_ui(jm,1L);
8,604✔
1975
                mpf_div_ui(jjm,jm,(unsigned long)j);
8,604✔
1976
                mpf_pow_ui(jm,jjm,(unsigned long)m);
8,604✔
1977
                if ( s == -1 ) mpf_div_2exp(jjm,jm,2*(unsigned long)j);
8,604✔
1978
                else           mpf_div_2exp(jjm,jm,(unsigned long)j);
×
1979
                mpf_add(sum,sum,jjm);
8,604✔
1980
        }
1981
        mpf_clear(jjm); mpf_clear(jm);
240✔
1982
}
240✔
1983

1984
/*
1985
                 #] SimpleDeltaC : 
1986
                 #[ SingleTable :
1987
*/
1988

1989
void SingleTable(mpf_t *tabl, int N, int m, int pow)
3,606✔
1990
{
1991
/*
1992
        Creates a table T(1,...,N) with
1993
                T(i) = sum_(j,i,N,[sign_(j)]/2^j/j^m)
1994
        To make this table we have two options:
1995
        1: run the sum backwards with the potential problem that the 
1996
           precision is difficult to manage.
1997
        2: run the sum forwards. Take sum_(j,1,i-1,...) and later subtract.
1998
        When doing Euler sums we may need also 1/4^j
1999
        pow: 1 -> 1/2^j
2000
             2 -> 1/4^j
2001
*/
2002
        GETIDENTITY
2,404✔
2003
        long s = 1;
3,606✔
2004
        int j;
3,606✔
2005
#ifdef WITHCUTOFF
2006
        long prec = mpf_get_default_prec();
3,606✔
2007
#endif
2008
        mpf_t jm,jjm;
3,606✔
2009
        mpf_init(jm); mpf_init(jjm);
3,606✔
2010
        if ( pow < 1 || pow > 2 ) {
3,606✔
NEW
2011
                MLOCK(ErrorMessageLock);
×
NEW
2012
                MesPrint("Wrong parameter pow in SingleTable: %d\n",pow);
×
NEW
2013
                MUNLOCK(ErrorMessageLock);
×
NEW
2014
                Terminate(-1);
×
2015
        }
2016
        if ( m < 0 ) { m = -m; s = -1; }
3,606✔
2017
        mpf_set_si(auxsum,0L);
3,606✔
2018
        for ( j = N; j > 0; j-- ) {
779,850✔
2019
#ifdef WITHCUTOFF
2020
                mpf_set_prec_raw(jm,prec-j);
772,638✔
2021
                mpf_set_prec_raw(jjm,prec-j);
772,638✔
2022
#endif
2023
                mpf_set_ui(jm,1L);
772,638✔
2024
                mpf_div_ui(jjm,jm,(unsigned long)j);
772,638✔
2025
                mpf_pow_ui(jm,jjm,(unsigned long)m);
772,638✔
2026
                mpf_div_2exp(jjm,jm,pow*(unsigned long)j);
772,638✔
2027
                if ( pow == 2 ) mpf_add(auxsum,auxsum,jjm);
772,638✔
2028
                else if ( s == -1 && j%2 == 1 ) mpf_sub(auxsum,auxsum,jjm);
740,982✔
2029
                else                       mpf_add(auxsum,auxsum,jjm);
725,286✔
2030
/*
2031
                And now copy auxsum to tablelement j
2032
*/
2033
                mpf_set(tabl[j],auxsum);
772,638✔
2034
        }
2035
        mpf_clear(jjm); mpf_clear(jm);
3,606✔
2036
}
3,606✔
2037

2038
/*
2039
                 #] SingleTable : 
2040
                 #[ DoubleTable :
2041
*/
2042

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

2091
/*
2092
                 #] DoubleTable : 
2093
                 #[ EndTable :
2094
*/
2095

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

2138
/*
2139
                 #] EndTable : 
2140
                 #[ deltaMZV :
2141
*/
2142

2143
void deltaMZV(mpf_t result, WORD *indexes, int depth)
7,566✔
2144
{
2145
        GETIDENTITY
5,044✔
2146
/*
2147
        Because all sums go roughly like 1/2^j we need about depth steps.
2148
*/
2149
/*        MesPrint("deltaMZV(%a)",depth,indexes); */
2150
        if ( depth == 1 ) {
7,566✔
2151
                if ( indexes[0] == 1 ) {
3,804✔
2152
                        mpf_set(result,mpfdelta1);
1,650✔
2153
                        return;
1,650✔
2154
                }
2155
                SimpleDelta(result,indexes[0]);
2,154✔
2156
        }
2157
        else if ( depth == 2 ) {
3,762✔
2158
                if ( indexes[0] == 1 && indexes[1] == 1 ) {
1,470✔
2159
                        mpf_pow_ui(result,mpfdelta1,2);
486✔
2160
                        mpf_div_2exp(result,result,1);
486✔
2161
                }
2162
                else {
2163
                        SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
984✔
2164
                        EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,indexes[1],0);
984✔
2165
                };
2166
        }
2167
        else if ( depth > 2 ) {
2,292✔
2168
                mpf_t *mpftab3;
2169
                int d;
2170
/*
2171
                Check first whether this is a power of delta1 = ln(2)
2172
*/
2173
                for ( d = 0; d < depth; d++ ) {
7,548✔
2174
                        if ( indexes[d] != 1 ) break;
6,678✔
2175
                }
2176
                if ( d == depth ) {        /* divide by fac_(depth) */
2,292✔
2177
                        mpf_pow_ui(result,mpfdelta1,depth);
870✔
2178
                        for ( d = 2; d <= depth; d++ ) {
5,196✔
2179
                                mpf_div_ui(result,result,(unsigned long)d);
3,456✔
2180
                        }
2181
                }
2182
                else {
2183
                        d = depth-1;
1,422✔
2184
                        SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
1,422✔
2185
                        d--; indexes++;
1,422✔
2186
                        for(;;) {
6,726✔
2187
                                DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,0);
4,074✔
2188
                                d--; indexes++;
4,074✔
2189
                                if ( d == 0 ) {
4,074✔
2190
                                        EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,*indexes,0);
1,422✔
2191
                                        break;
1,422✔
2192
                                }
2193
                                mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
2,652✔
2194
                                AT.mpf_tab2 = (void *)mpftab3;
2,652✔
2195
                        }
2196
                }
2197
        }
2198
        else if ( depth == 0 ) {
×
2199
                mpf_set_ui(result,1L);
×
2200
        }
2201
}
2202

2203
/*
2204
                 #] deltaMZV : 
2205
                 #[ deltaEuler :
2206

2207
                Regular Euler delta with - signs, but everywhere 1/2^j
2208
*/
2209

2210
void deltaEuler(mpf_t result, WORD *indexes, int depth)
990✔
2211
{
2212
        GETIDENTITY
660✔
2213
        int m;
990✔
2214
#ifdef DEBUG
2215
        int i;
2216
        printf(" deltaEuler(");
2217
        for ( i = 0; i < depth; i++ ) {
2218
                if ( i != 0 ) printf(",");
2219
                printf("%d",indexes[i]);
2220
        }
2221
        printf(") = ");
2222
#endif
2223
        if ( depth == 1 ) {
990✔
2224
                SimpleDelta(result,indexes[0]);
390✔
2225
        }
2226
        else if ( depth == 2 ) {
600✔
2227
                SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+1,indexes[0],1);
348✔
2228
                m = indexes[1]; if ( indexes[0] < 0 ) m = -m;
348✔
2229
                EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,0);
348✔
2230
        }
2231
        else if ( depth > 2 ) {
252✔
2232
                int d;
252✔
2233
                mpf_t *mpftab3;
252✔
2234
                d = depth-1;
252✔
2235
                SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,*indexes,1);
252✔
2236
                d--; indexes++;
252✔
2237
                m = *indexes; if ( indexes[-1] < 0 ) m = -m;
252✔
2238
                for(;;) {
348✔
2239
                        DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,0);
300✔
2240
                        d--; indexes++;
300✔
2241
                        m = *indexes; if ( indexes[-1] < 0 ) m = -m;
300✔
2242
                        if ( d == 0 ) {
300✔
2243
                                EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,0);
252✔
2244
                                break;
252✔
2245
                        }
2246
                        mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
48✔
2247
                        AT.mpf_tab2 = (void *)mpftab3;
48✔
2248
                }
2249
        }
2250
        else if ( depth == 0 ) {
×
2251
                mpf_set_ui(result,1L);
×
2252
        }
2253
#ifdef DEBUG
2254
        gmp_printf("%.*Fe\n",40,result);
2255
#endif
2256
}
990✔
2257

2258
/*
2259
                 #] deltaEuler : 
2260
                 #[ deltaEulerC :
2261

2262
                Conjugate Euler delta without - signs, but possibly 1/4^j
2263
                When there is a - in the string we have 1/4.
2264
*/
2265

2266
void deltaEulerC(mpf_t result, WORD *indexes, int depth)
990✔
2267
{
2268
        GETIDENTITY
660✔
2269
        int m;
990✔
2270
#ifdef DEBUG
2271
        int i;
2272
        printf(" deltaEulerC(");
2273
        for ( i = 0; i < depth; i++ ) {
2274
                if ( i != 0 ) printf(",");
2275
                printf("%d",indexes[i]);
2276
        }
2277
        printf(") = ");
2278
#endif
2279
        mpf_set_ui(result,0);
990✔
2280
        if ( depth == 1 ) {
990✔
2281
                if ( indexes[0] == 0 ) {
390✔
NEW
2282
                        MLOCK(ErrorMessageLock);
×
NEW
2283
                        MesPrint("Illegal index in depth=1 deltaEulerC: %d\n",indexes[0]);
×
NEW
2284
                        MUNLOCK(ErrorMessageLock);
×
NEW
2285
                        Terminate(-1);
×
2286
                }
2287
                if ( indexes[0] < 0 ) SimpleDeltaC(result,indexes[0]);
390✔
2288
                else                  SimpleDelta(result,indexes[0]);
150✔
2289
        }
2290
        else if ( depth == 2 ) {
600✔
2291
                int par;
348✔
2292
                m = indexes[0];
348✔
2293
                if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth,-m,2);
348✔
2294
                else         SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+depth, m,1);
132✔
2295
                m = indexes[1];
348✔
2296
                if ( m < 0 ) { m = -m; par = indexes[0] < 0 ? 0: 1; }
348✔
2297
                else { par = indexes[0] < 0 ? -1: 0; }
150✔
2298
                EndTable(result,mpftab1,AC.DefaultPrecision-AC.MaxWeight,m,par);
348✔
2299
        }
2300
        else if ( depth > 2 ) {
252✔
2301
                int d, par;
252✔
2302
                mpf_t *mpftab3;
252✔
2303
                d = depth-1;
252✔
2304
                m = indexes[0];
252✔
2305
        ZeroTable(mpftab1,AC.DefaultPrecision+1);
252✔
2306
                if ( m < 0 ) SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1,-m,2);
252✔
2307
                else         SingleTable(mpftab1,AC.DefaultPrecision-AC.MaxWeight+d+1, m,1);
60✔
2308
                d--; indexes++; m = indexes[0];
252✔
2309
                if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
252✔
2310
                else { par = indexes[-1] < 0 ? -1: 0; }
120✔
2311
                for(;;) {
348✔
2312
                ZeroTable(mpftab2,AC.DefaultPrecision-AC.MaxWeight+d);
300✔
2313
                        DoubleTable(mpftab2,mpftab1,AC.DefaultPrecision-AC.MaxWeight+d,m,par);
300✔
2314
                        d--; indexes++; m = indexes[0];
300✔
2315
                        if ( m < 0 ) { m = -m; par = indexes[-1] < 0 ? 0: 1; }
300✔
2316
                        else { par = indexes[-1] < 0 ? -1: 0; }
144✔
2317
                        if ( d == 0 ) {
300✔
2318
                                mpf_set_ui(result,0);
252✔
2319
                                EndTable(result,mpftab2,AC.DefaultPrecision-AC.MaxWeight,m,par);
252✔
2320
                                break;
252✔
2321
                        }
2322
                        mpftab3 = (mpf_t *)AT.mpf_tab1; AT.mpf_tab1 = AT.mpf_tab2;
48✔
2323
                        AT.mpf_tab2 = (void *)mpftab3;
48✔
2324
                }
2325
        }
2326
        else if ( depth == 0 ) {
×
2327
                mpf_set_ui(result,1L);
×
2328
        }
2329
#ifdef DEBUG
2330
        gmp_printf("%.*Fe\n",40,result);
2331
#endif
2332
}
990✔
2333

2334
/*
2335
                 #] deltaEulerC : 
2336
                 #[ CalculateMZVhalf :
2337

2338
                 This routine is mainly for support when large numbers of
2339
                MZV's have to be calculated at the same time.
2340
*/
2341

2342
void CalculateMZVhalf(mpf_t result, WORD *indexes, int depth)
384✔
2343
{
2344
        int i;
384✔
2345
        if ( depth < 0 ) {
384✔
NEW
2346
                MLOCK(ErrorMessageLock);
×
NEW
2347
                MesPrint("Illegal depth in CalculateMZVhalf: %d",depth);
×
NEW
2348
                MUNLOCK(ErrorMessageLock);
×
NEW
2349
                Terminate(-1);
×
2350
        }
2351
        for ( i = 0; i < depth; i++ ) {
1,542✔
2352
                if ( indexes[i] <= 0 ) {
1,164✔
2353
                        MLOCK(ErrorMessageLock);
6✔
2354
                        MesPrint("Illegal index[%d] in CalculateMZVhalf: %d",i,indexes[i]);
6✔
2355
                        MUNLOCK(ErrorMessageLock);
6✔
2356
                        Terminate(-1);
1,164✔
2357
                }
2358
        }
2359
        deltaMZV(result,indexes,depth);
378✔
2360
}
378✔
2361

2362
/*
2363
                 #] CalculateMZVhalf : 
2364
                 #[ CalculateMZV :
2365
*/
2366

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

2416
/*
2417
                 #] CalculateMZV : 
2418
                 #[ CalculateEuler :
2419

2420
                There is a problem of notation here.
2421
                Basically there are two notations.
2422
                1: Z(m1,m2,m3) = sum_(j3,1,inf,sign_(m3)/j3^abs_(m3)*
2423
                                 sum_(j2,j3+1,inf,sign_(m2)/j2^abs_(m2)*
2424
                                 sum_(j1,j2+1,inf,sign_(m1)/j1^abs_(m1))))
2425
                   See Broadhurst,1996
2426
                2: L(m1,m2,m3) = sum_(j1,1,inf,sign_(m1)*
2427
                                 sum_(j2,1,inf,sign_(m2)*
2428
                                 sum_(j3,1,inf,sign_(m3)
2429
                                                        /j3^abs_(m3)
2430
                                                        /(j2+j3)^abs_(m2)
2431
                                                        /(j1+j2+j3)^abs_(m1) )))
2432
                   See Borwein, Bradley, Broadhurst and Lisonek, 1999
2433
                The L corresponds with the H of the datamine up to sign_(m1*m2*m3)
2434
                The algorithm follows 2, but the more common notation is 1.
2435
                Hence we start with a conversion.
2436
*/
2437

2438
void CalculateEuler(mpf_t result, WORD *Zindexes, int depth)
324✔
2439
{
2440
        GETIDENTITY
216✔
2441
        int s1, num1, num2, i, j;
324✔
2442

2443
        WORD *indexes = AT.WorkPointer;
324✔
2444
        for ( i = 0; i < depth; i++ ) indexes[i] = Zindexes[i];
1,146✔
2445
        for ( i = 0; i < depth-1; i++ ) {
822✔
2446
                if ( Zindexes[i] < 0 ) {
498✔
2447
                        for ( j = i+1; j < depth; j++ ) indexes[j] = -indexes[j];
864✔
2448
                }
2449
        }
2450

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

2515
/*
2516
                 #] CalculateEuler : 
2517
                 #[ ExpandMZV :
2518
*/
2519

2520
int ExpandMZV(WORD *term, WORD level)
×
2521
{
2522
        DUMMYUSE(term);
×
2523
        DUMMYUSE(level);
×
2524
        return(0);
×
2525
}
2526

2527
/*
2528
                 #] ExpandMZV : 
2529
                 #[ ExpandEuler :
2530
*/
2531

2532
int ExpandEuler(WORD *term, WORD level)
×
2533
{
2534
        DUMMYUSE(term);
×
2535
        DUMMYUSE(level);
×
2536
        return(0);
×
2537
}
2538

2539
/*
2540
                 #] ExpandEuler : 
2541
                 #[ EvaluateEuler :
2542

2543
        There are various steps here:
2544
        1: locate an Euler function.
2545
        2: evaluate it into a float.
2546
        3: convert the coefficient to a float and multiply.
2547
        4: Put the new term together.
2548
        5: Restart to see whether there are more Euler functions.
2549
        The compiler should check that there is no conflict between
2550
        the evaluate command and a potential polyfun or polyratfun.
2551
        Yet, when reading in expressions there can be a conflict.
2552
        Hence the Normalize routine should check as well.
2553

2554
        par == MZV: MZV
2555
        par == EULER: Euler
2556
        par == MZVHALF: MZV sums in 1/2 rather than 1. -> deltaMZV.
2557
        par == ALLMZVFUNCTIONS: all of the above.
2558
*/
2559

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

2671
/*
2672
                 #] EvaluateEuler : 
2673
          #] MZV : 
2674
          #[ Functions :
2675
                 #[ CoEvaluate :
2676

2677
                Current subkeys: mzv_, euler_ and sqrt_.
2678
*/
2679

2680
int CoEvaluate(UBYTE *s)
420✔
2681
{
2682
        GETIDENTITY
280✔
2683
        UBYTE *subkey, c;
420✔
2684
        WORD numfun, type;
420✔
2685
        int error = 0;
420✔
2686
        if ( AT.aux_ == 0 ) {
420✔
2687
                MesPrint("&Illegal attempt to evaluate a function without activating floating point numbers.");
6✔
2688
                MesPrint("&Forgotten %#startfloat instruction?");
6✔
2689
                return(1);
6✔
2690
        }
2691
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
414✔
2692
        if ( *s == 0 ) {
414✔
2693
/*
2694
                No subkey, which means all functions.
2695
*/
2696
                Add3Com(TYPEEVALUATE,ALLFUNCTIONS);
42✔
2697
/*
2698
                The MZV, EULER and MZVHALF are done separately
2699
*/
2700
                Add3Com(TYPEEVALUATE,ALLMZVFUNCTIONS);
42✔
2701
                return(0);        
42✔
2702
        }
2703
        while ( *s ) {
720✔
2704
        subkey = s;
2705
        while ( FG.cTable[*s] == 0 ) s++;
1,812✔
2706
          if ( *s == '2' ) s++; /* cases li2_ and atan2_ */
390✔
2707
          if ( *s == '_' ) s++;
390✔
2708
          c = *s; *s = 0;
390✔
2709
/*
2710
                We still need provisions for pi_ and possibly other constants.
2711
*/
2712
          if ( ( ( type = GetName(AC.varnames,subkey,&numfun,NOAUTO) ) != CFUNCTION )
390✔
2713
                        || ( functions[numfun].spec != 0 ) ) {
348✔
2714

2715
                if ( type == CSYMBOL ) {
42✔
2716
                        Add4Com(TYPEEVALUATE,SYMBOL,numfun);
36✔
2717
                        break;
36✔
2718
                }
2719
/*
2720
                        This cannot work.
2721
*/
2722
                MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
6✔
2723
                return(1);
6✔
2724
          }
2725
          else {
2726
                switch ( numfun+FUNCTION ) {
348✔
2727
                        case MZV:
348✔
2728
                        case EULER:
2729
                        case MZVHALF:
2730
/*
2731
                        The following functions are treated in evaluate.c
2732
*/
2733
                        case SQRTFUNCTION:
2734
                        case LNFUNCTION:
2735
                        case EXPFUNCTION:
2736
                        case SINFUNCTION:
2737
                        case COSFUNCTION:
2738
                        case TANFUNCTION:
2739
                        case ASINFUNCTION:
2740
                        case ACOSFUNCTION:
2741
                        case ATANFUNCTION:
2742
                        case ATAN2FUNCTION:
2743
                        case SINHFUNCTION:
2744
                        case COSHFUNCTION:
2745
                        case TANHFUNCTION:
2746
                        case ASINHFUNCTION:
2747
                        case ACOSHFUNCTION:
2748
                        case ATANHFUNCTION:
2749
                        case LI2FUNCTION:
2750
                        case LINFUNCTION:
2751
                        case AGMFUNCTION:
2752
                        case GAMMAFUN:
2753
/*
2754
                        At a later stage we can add more functions from mpfr here
2755
                                mpfr_(number,arg(s))
2756
*/
2757
                                Add3Com(TYPEEVALUATE,numfun+FUNCTION);
348✔
2758
                                break;
348✔
2759
                        default:
×
2760
                                MesPrint("&%s should be a built in function that can be evaluated numerically.",s);
×
2761
                                error = 1;
×
2762
                                break;
×
2763
                }
2764
          }
2765
          *s = c;
348✔
2766
          while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
366✔
2767
        }
2768
        return(error);
2769
}
2770

2771
/*
2772
                 #] CoEvaluate : 
2773
          #] Functions : 
2774
*/
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