4371 lines
82 KiB
C
4371 lines
82 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: mp.c /main/3 1995/11/01 12:42:08 rswiston $ */
|
|
/* *
|
|
* mp.c *
|
|
* Contains the actual math functions. *
|
|
* *
|
|
* (c) Copyright 1993, 1994 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994 Novell, Inc. *
|
|
*/
|
|
|
|
/* This maths library is based on the MP multi-precision floating-point
|
|
* arithmetic package originally written in FORTRAN by Richard Brent,
|
|
* Computer Centre, Australian National University in the 1970's.
|
|
*
|
|
* It has been converted from FORTRAN into C using the freely available
|
|
* f2c translator, available via netlib on research.att.com.
|
|
*
|
|
* The subsequently converted C code has then been tidied up, mainly to
|
|
* remove any dependencies on the libI77 and libF77 support libraries.
|
|
*
|
|
* FOR A GENERAL DESCRIPTION OF THE PHILOSOPHY AND DESIGN OF MP,
|
|
* SEE - R. P. BRENT, A FORTRAN MULTIPLE-PRECISION ARITHMETIC
|
|
* PACKAGE, ACM TRANS. MATH. SOFTWARE 4 (MARCH 1978), 57-70.
|
|
* SOME ADDITIONAL DETAILS ARE GIVEN IN THE SAME ISSUE, 71-81.
|
|
* FOR DETAILS OF THE IMPLEMENTATION, CALLING SEQUENCES ETC. SEE
|
|
* THE MP USERS GUIDE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include "calctool.h"
|
|
#include <Dt/Dt.h>
|
|
#include "text.h"
|
|
|
|
struct {
|
|
int b, t, m, mxr, r[MP_SIZE] ;
|
|
} MP ;
|
|
|
|
/* Table of constant values */
|
|
|
|
static int c__0 = 0 ;
|
|
static int c__1 = 1 ;
|
|
static int c__4 = 4 ;
|
|
static int c__2 = 2 ;
|
|
static int c__6 = 6 ;
|
|
static int c__5 = 5 ;
|
|
static int c__12 = 12 ;
|
|
static int c_n2 = -2 ;
|
|
static int c__10 = 10 ;
|
|
static int c__32 = 32 ;
|
|
static int c__3 = 3 ;
|
|
static int c__8 = 8 ;
|
|
static int c__14 = 14 ;
|
|
static int c_n1 = -1 ;
|
|
static int c__239 = 239 ;
|
|
static int c__7 = 7 ;
|
|
static int c__16 = 16 ;
|
|
|
|
void
|
|
mpabs(int *x, int *y)
|
|
{
|
|
|
|
/* SETS Y = ABS(X) FOR MP NUMBERS X AND Y */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpstr(&x[1], &y[1]) ;
|
|
y[1] = C_abs(y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpadd(int *x, int *y, int *z)
|
|
{
|
|
|
|
/* ADDS X AND Y, FORMING RESULT IN Z, WHERE X, Y AND Z ARE MP
|
|
* NUMBERS. FOUR GUARD DIGITS ARE USED, AND THEN R*-ROUNDING.
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--y ;
|
|
--x ;
|
|
|
|
mpadd2(&x[1], &y[1], &z[1], &y[1], &c__0) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpadd2(int *x, int *y, int *z, int *y1, int *trunc)
|
|
{
|
|
int i__1, i__2 ;
|
|
|
|
static int j, s ;
|
|
static int ed, re, rs, med ;
|
|
|
|
/* CALLED BY MPADD, MPSUB ETC.
|
|
* X, Y AND Z ARE MP NUMBERS, Y1 AND TRUNC ARE INTEGERS.
|
|
* TO FORCE CALL BY REFERENCE RATHER THAN VALUE/RESULT, Y1 IS
|
|
* DECLARED AS AN ARRAY, BUT ONLY Y1(1) IS EVER USED.
|
|
* SETS Z = X + Y1(1)*ABS(Y), WHERE Y1(1) = +- Y(1).
|
|
* IF TRUNC.EQ.0 R*-ROUNDING IS USED, OTHERWISE TRUNCATION.
|
|
* R*-ROUNDING IS DEFINED IN KUKI AND CODI, COMM. ACM
|
|
* 16(1973), 223. (SEE ALSO BRENT, IEEE TC-22(1973), 601.)
|
|
* CHECK FOR X OR Y ZERO
|
|
*/
|
|
|
|
--y1 ; /* Parameter adjustments */
|
|
--z ;
|
|
--y ;
|
|
--x ;
|
|
|
|
if (x[1] != 0) goto L20 ;
|
|
|
|
/* X = 0 OR NEGLIGIBLE, SO RESULT = +-Y */
|
|
|
|
L10:
|
|
mpstr(&y[1], &z[1]) ;
|
|
z[1] = y1[1] ;
|
|
return ;
|
|
|
|
L20:
|
|
if (y1[1] != 0) goto L40 ;
|
|
|
|
/* Y = 0 OR NEGLIGIBLE, SO RESULT = X */
|
|
|
|
L30:
|
|
mpstr(&x[1], &z[1]) ;
|
|
return ;
|
|
|
|
/* COMPARE SIGNS */
|
|
|
|
L40:
|
|
s = x[1] * y1[1] ;
|
|
if (C_abs(s) <= 1) goto L60 ;
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ADD2A]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ADD2B]) ;
|
|
}
|
|
|
|
mperr() ;
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* COMPARE EXPONENTS */
|
|
|
|
L60:
|
|
ed = x[2] - y[2] ;
|
|
med = C_abs(ed) ;
|
|
if (ed < 0) goto L90 ;
|
|
else if (ed == 0) goto L70 ;
|
|
else goto L120 ;
|
|
|
|
/* EXPONENTS EQUAL SO COMPARE SIGNS, THEN FRACTIONS IF NEC. */
|
|
|
|
L70:
|
|
if (s > 0) goto L100 ;
|
|
|
|
i__1 = MP.t ;
|
|
for (j = 1; j <= i__1; ++j)
|
|
{
|
|
if ((i__2 = x[j + 2] - y[j + 2]) < 0) goto L100 ;
|
|
else if (i__2 == 0) continue ;
|
|
else goto L130 ;
|
|
}
|
|
|
|
/* RESULT IS ZERO */
|
|
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* HERE EXPONENT(Y) .GE. EXPONENT(X) */
|
|
|
|
L90:
|
|
if (med > MP.t) goto L10 ;
|
|
|
|
L100:
|
|
rs = y1[1] ;
|
|
re = y[2] ;
|
|
mpadd3(&x[1], &y[1], &s, &med, &re) ;
|
|
|
|
/* NORMALIZE, ROUND OR TRUNCATE, AND RETURN */
|
|
|
|
L110:
|
|
mpnzr(&rs, &re, &z[1], trunc) ;
|
|
return ;
|
|
|
|
/* ABS(X) .GT. ABS(Y) */
|
|
|
|
L120:
|
|
if (med > MP.t) goto L30 ;
|
|
|
|
L130:
|
|
rs = x[1] ;
|
|
re = x[2] ;
|
|
mpadd3(&y[1], &x[1], &s, &med, &re) ;
|
|
goto L110 ;
|
|
}
|
|
|
|
|
|
void
|
|
mpadd3(int *x, int *y, int *s, int *med, int *re)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int c, i, j, i2, i2p, ted ;
|
|
|
|
/* CALLED BY MPADD2, DOES INNER LOOPS OF ADDITION */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
ted = MP.t + *med ;
|
|
i2 = MP.t + 4 ;
|
|
i = i2 ;
|
|
c = 0 ;
|
|
|
|
/* CLEAR GUARD DIGITS TO RIGHT OF X DIGITS */
|
|
|
|
L10:
|
|
if (i <= ted) goto L20 ;
|
|
|
|
MP.r[i - 1] = 0 ;
|
|
--i ;
|
|
goto L10 ;
|
|
|
|
L20:
|
|
if (*s < 0) goto L130 ;
|
|
|
|
/* HERE DO ADDITION, EXPONENT(Y) .GE. EXPONENT(X) */
|
|
|
|
if (i <= MP.t) goto L40 ;
|
|
|
|
L30:
|
|
j = i - *med ;
|
|
MP.r[i - 1] = x[j + 2] ;
|
|
--i ;
|
|
if (i > MP.t) goto L30 ;
|
|
|
|
L40:
|
|
if (i <= *med) goto L60 ;
|
|
|
|
j = i - *med ;
|
|
c = y[i + 2] + x[j + 2] + c ;
|
|
if (c < MP.b) goto L50 ;
|
|
|
|
/* CARRY GENERATED HERE */
|
|
|
|
MP.r[i - 1] = c - MP.b ;
|
|
c = 1 ;
|
|
--i ;
|
|
goto L40 ;
|
|
|
|
/* NO CARRY GENERATED HERE */
|
|
|
|
L50:
|
|
MP.r[i - 1] = c ;
|
|
c = 0 ;
|
|
--i ;
|
|
goto L40 ;
|
|
|
|
L60:
|
|
if (i <= 0) goto L90 ;
|
|
|
|
c = y[i + 2] + c ;
|
|
if (c < MP.b) goto L70 ;
|
|
|
|
MP.r[i - 1] = 0 ;
|
|
c = 1 ;
|
|
--i ;
|
|
goto L60 ;
|
|
|
|
L70:
|
|
MP.r[i - 1] = c ;
|
|
--i ;
|
|
|
|
/* NO CARRY POSSIBLE HERE */
|
|
|
|
L80:
|
|
if (i <= 0) return ;
|
|
|
|
MP.r[i - 1] = y[i + 2] ;
|
|
--i ;
|
|
goto L80 ;
|
|
|
|
L90:
|
|
if (c == 0) return ;
|
|
|
|
/* MUST SHIFT RIGHT HERE AS CARRY OFF END */
|
|
|
|
i2p = i2 + 1 ;
|
|
i__1 = i2 ;
|
|
for (j = 2 ; j <= i__1 ; ++j)
|
|
{
|
|
i = i2p - j ;
|
|
MP.r[i] = MP.r[i - 1] ;
|
|
}
|
|
MP.r[0] = 1 ;
|
|
++(*re) ;
|
|
return ;
|
|
|
|
/* HERE DO SUBTRACTION, ABS(Y) .GT. ABS(X) */
|
|
|
|
L110:
|
|
j = i - *med ;
|
|
MP.r[i - 1] = c - x[j + 2] ;
|
|
c = 0 ;
|
|
if (MP.r[i - 1] >= 0) goto L120 ;
|
|
|
|
/* BORROW GENERATED HERE */
|
|
|
|
c = -1 ;
|
|
MP.r[i - 1] += MP.b ;
|
|
|
|
L120:
|
|
--i ;
|
|
|
|
L130:
|
|
if (i > MP.t) goto L110 ;
|
|
|
|
L140:
|
|
if (i <= *med) goto L160 ;
|
|
|
|
j = i - *med ;
|
|
c = y[i + 2] + c - x[j + 2] ;
|
|
if (c >= 0) goto L150 ;
|
|
|
|
/* BORROW GENERATED HERE */
|
|
|
|
MP.r[i - 1] = c + MP.b ;
|
|
c = -1 ;
|
|
--i ;
|
|
goto L140 ;
|
|
|
|
/* NO BORROW GENERATED HERE */
|
|
|
|
L150:
|
|
MP.r[i - 1] = c ;
|
|
c = 0 ;
|
|
--i ;
|
|
goto L140 ;
|
|
|
|
L160:
|
|
if (i <= 0) return ;
|
|
|
|
c = y[i + 2] + c ;
|
|
if (c >= 0) goto L70 ;
|
|
|
|
MP.r[i - 1] = c + MP.b ;
|
|
c = -1 ;
|
|
--i ;
|
|
goto L160 ;
|
|
}
|
|
|
|
|
|
void
|
|
mpaddi(int *x, int *iy, int *z)
|
|
{
|
|
|
|
/* ADDS MULTIPLE-PRECISION X TO INTEGER IY
|
|
* GIVING MULTIPLE-PRECISION Z.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE
|
|
* AT LEAST 2T+6 (BUT Z(1) MAY BE R(T+5)).
|
|
* DIMENSION R(6) BECAUSE RALPH COMPILER ON UNIVAC 1100 COMPUTERS
|
|
* OBJECTS TO DIMENSION R(1).
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__2, &c__6) ;
|
|
mpcim(iy, &MP.r[MP.t + 4]) ;
|
|
mpadd(&x[1], &MP.r[MP.t + 4], &z[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpaddq(int *x, int *i, int *j, int *y)
|
|
{
|
|
|
|
/* ADDS THE RATIONAL NUMBER I/J TO MP NUMBER X, MP RESULT IN Y
|
|
* DIMENSION OF R MUST BE AT LEAST 2T+6
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__2, &c__6) ;
|
|
mpcqm(i, j, &MP.r[MP.t + 4]) ;
|
|
mpadd(&x[1], &MP.r[MP.t + 4], &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpart1(int *n, int *y)
|
|
{
|
|
int i__1, i__2 ;
|
|
|
|
static int i, b2, i2, id, ts ;
|
|
|
|
/* COMPUTES MP Y = ARCTAN(1/N), ASSUMING INTEGER N .GT. 1.
|
|
* USES SERIES ARCTAN(X) = X - X**3/3 + X**5/5 - ...
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE
|
|
* AT LEAST 2T+6
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__2, &c__6) ;
|
|
if (*n > 1) goto L20 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_PART1]) ;
|
|
|
|
mperr() ;
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
L20:
|
|
i2 = MP.t + 5 ;
|
|
ts = MP.t ;
|
|
|
|
/* SET SUM TO X = 1/N */
|
|
|
|
mpcqm(&c__1, n, &y[1]) ;
|
|
|
|
/* SET ADDITIVE TERM TO X */
|
|
|
|
mpstr(&y[1], &MP.r[i2 - 1]) ;
|
|
i = 1 ;
|
|
id = 0 ;
|
|
|
|
/* ASSUME AT LEAST 16-BIT WORD. */
|
|
|
|
b2 = max(MP.b, 64) ;
|
|
if (*n < b2) id = b2 * 7 * b2 / (*n * *n) ;
|
|
|
|
/* MAIN LOOP. FIRST REDUCE T IF POSSIBLE */
|
|
|
|
L30:
|
|
MP.t = ts + 2 + MP.r[i2] - y[2] ;
|
|
if (MP.t < 2) goto L60 ;
|
|
|
|
MP.t = min(MP.t,ts) ;
|
|
|
|
/* IF (I+2)*N**2 IS NOT REPRESENTABLE AS AN INTEGER THE DIVISION
|
|
* FOLLOWING HAS TO BE PERFORMED IN SEVERAL STEPS.
|
|
*/
|
|
|
|
if (i >= id) goto L40 ;
|
|
|
|
i__1 = -i ;
|
|
i__2 = (i + 2) * *n * *n ;
|
|
mpmulq(&MP.r[i2 - 1], &i__1, &i__2, &MP.r[i2 - 1]) ;
|
|
goto L50 ;
|
|
|
|
L40:
|
|
i__1 = -i ;
|
|
i__2 = i + 2 ;
|
|
mpmulq(&MP.r[i2 - 1], &i__1, &i__2, &MP.r[i2 - 1]) ;
|
|
mpdivi(&MP.r[i2 - 1], n, &MP.r[i2 - 1]) ;
|
|
mpdivi(&MP.r[i2 - 1], n, &MP.r[i2 - 1]) ;
|
|
|
|
L50:
|
|
i += 2 ;
|
|
|
|
/* RESTORE T */
|
|
|
|
MP.t = ts ;
|
|
|
|
/* ADD TO SUM, USING MPADD2 (FASTER THAN MPADD) */
|
|
|
|
mpadd2(&MP.r[i2 - 1], &y[1], &y[1], &y[1], &c__0) ;
|
|
if (MP.r[i2 - 1] != 0) goto L30 ;
|
|
|
|
L60:
|
|
MP.t = ts ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpasin(int *x, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i2, i3 ;
|
|
|
|
/* RETURNS Y = ARCSIN(X), ASSUMING ABS(X) .LE. 1,
|
|
* FOR MP NUMBERS X AND Y.
|
|
* Y IS IN THE RANGE -PI/2 TO +PI/2.
|
|
* METHOD IS TO USE MPATAN, SO TIME IS O(M(T)T).
|
|
* DIMENSION OF R MUST BE AT LEAST 5T+12
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__5, &c__12) ;
|
|
i3 = (MP.t << 2) + 11 ;
|
|
if (x[1] == 0) goto L30 ;
|
|
|
|
if (x[2] <= 0) goto L40 ;
|
|
|
|
/* HERE ABS(X) .GE. 1. SEE IF X = +-1 */
|
|
|
|
mpcim(&x[1], &MP.r[i3 - 1]) ;
|
|
if (mpcomp(&x[1], &MP.r[i3 - 1]) != 0) goto L10 ;
|
|
|
|
/* X = +-1 SO RETURN +-PI/2 */
|
|
|
|
mppi(&y[1]) ;
|
|
i__1 = MP.r[i3 - 1] << 1 ;
|
|
mpdivi(&y[1], &i__1, &y[1]) ;
|
|
return ;
|
|
|
|
L10:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ASIN]) ;
|
|
|
|
mperr() ;
|
|
|
|
L30:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* HERE ABS(X) .LT. 1 SO USE ARCTAN(X/SQRT(1 - X**2)) */
|
|
|
|
L40:
|
|
i2 = i3 - (MP.t + 2) ;
|
|
mpcim(&c__1, &MP.r[i2 - 1]) ;
|
|
mpstr(&MP.r[i2 - 1], &MP.r[i3 - 1]) ;
|
|
mpsub(&MP.r[i2 - 1], &x[1], &MP.r[i2 - 1]) ;
|
|
mpadd(&MP.r[i3 - 1], &x[1], &MP.r[i3 - 1]) ;
|
|
mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
mproot(&MP.r[i3 - 1], &c_n2, &MP.r[i3 - 1]) ;
|
|
mpmul(&x[1], &MP.r[i3 - 1], &y[1]) ;
|
|
mpatan(&y[1], &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpatan(int *x, int *y)
|
|
{
|
|
int i__1, i__2 ;
|
|
float r__1 ;
|
|
|
|
static int i, q, i2, i3, ie, ts ;
|
|
static float rx, ry ;
|
|
|
|
/* RETURNS Y = ARCTAN(X) FOR MP X AND Y, USING AN O(T.M(T)) METHOD
|
|
* WHICH COULD EASILY BE MODIFIED TO AN O(SQRT(T)M(T))
|
|
* METHOD (AS IN MPEXP1). Y IS IN THE RANGE -PI/2 TO +PI/2.
|
|
* FOR AN ASYMPTOTICALLY FASTER METHOD, SEE - FAST MULTIPLE-
|
|
* PRECISION EVALUATION OF ELEMENTARY FUNCTIONS
|
|
* (BY R. P. BRENT), J. ACM 23 (1976), 242-251,
|
|
* AND THE COMMENTS IN MPPIGL.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 5T+12
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__5, &c__12) ;
|
|
i2 = MP.t * 3 + 9 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
if (x[1] != 0) {
|
|
goto L10 ;
|
|
}
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
L10:
|
|
mpstr(&x[1], &MP.r[i3 - 1]) ;
|
|
ie = C_abs(x[2]) ;
|
|
if (ie <= 2) mpcmr(&x[1], &rx) ;
|
|
|
|
q = 1 ;
|
|
|
|
/* REDUCE ARGUMENT IF NECESSARY BEFORE USING SERIES */
|
|
|
|
L20:
|
|
if (MP.r[i3] < 0) goto L30 ;
|
|
|
|
if (MP.r[i3] == 0 && (MP.r[i3 + 1] + 1) << 1 <= MP.b)
|
|
goto L30 ;
|
|
|
|
q <<= 1 ;
|
|
mpmul(&MP.r[i3 - 1], &MP.r[i3 - 1], &y[1]) ;
|
|
mpaddi(&y[1], &c__1, &y[1]) ;
|
|
mpsqrt(&y[1], &y[1]) ;
|
|
mpaddi(&y[1], &c__1, &y[1]) ;
|
|
mpdiv(&MP.r[i3 - 1], &y[1], &MP.r[i3 - 1]) ;
|
|
goto L20 ;
|
|
|
|
/* USE POWER SERIES NOW ARGUMENT IN (-0.5, 0.5) */
|
|
|
|
L30:
|
|
mpstr(&MP.r[i3 - 1], &y[1]) ;
|
|
mpmul(&MP.r[i3 - 1], &MP.r[i3 - 1], &MP.r[i2 - 1]) ;
|
|
i = 1 ;
|
|
ts = MP.t ;
|
|
|
|
/* SERIES LOOP. REDUCE T IF POSSIBLE. */
|
|
|
|
L40:
|
|
MP.t = ts + 2 + MP.r[i3] ;
|
|
if (MP.t <= 2) goto L50 ;
|
|
|
|
MP.t = min(MP.t,ts) ;
|
|
mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i3 - 1]) ;
|
|
i__1 = -i ;
|
|
i__2 = i + 2 ;
|
|
mpmulq(&MP.r[i3 - 1], &i__1, &i__2, &MP.r[i3 - 1]) ;
|
|
i += 2 ;
|
|
MP.t = ts ;
|
|
mpadd(&y[1], &MP.r[i3 - 1], &y[1]) ;
|
|
if (MP.r[i3 - 1] != 0) goto L40 ;
|
|
|
|
/* RESTORE T, CORRECT FOR ARGUMENT REDUCTION, AND EXIT */
|
|
|
|
L50:
|
|
MP.t = ts ;
|
|
mpmuli(&y[1], &q, &y[1]) ;
|
|
|
|
/* CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS EXPONENT
|
|
* OF X IS LARGE (WHEN ATAN MIGHT NOT WORK)
|
|
*/
|
|
|
|
if (ie > 2) return ;
|
|
|
|
mpcmr(&y[1], &ry) ;
|
|
if ((r__1 = ry - atan(rx), dabs(r__1)) < dabs(ry) * (float).01)
|
|
return ;
|
|
|
|
/* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL. */
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ATAN]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcdm(double *dx, int *z)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, k, i2, ib, ie, re, tp, rs ;
|
|
static double db, dj ;
|
|
|
|
/* CONVERTS DOUBLE-PRECISION NUMBER DX TO MULTIPLE-PRECISION Z.
|
|
* SOME NUMBERS WILL NOT CONVERT EXACTLY ON MACHINES
|
|
* WITH BASE OTHER THAN TWO, FOUR OR SIXTEEN.
|
|
* THIS ROUTINE IS NOT CALLED BY ANY OTHER ROUTINE IN MP,
|
|
* SO MAY BE OMITTED IF DOUBLE-PRECISION IS NOT AVAILABLE.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
i2 = MP.t + 4 ;
|
|
|
|
/* CHECK SIGN */
|
|
|
|
if (*dx < 0.) goto L20 ;
|
|
else if (*dx == 0) goto L10 ;
|
|
else goto L30 ;
|
|
|
|
/* IF DX = 0D0 RETURN 0 */
|
|
|
|
L10:
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* DX .LT. 0D0 */
|
|
|
|
L20:
|
|
rs = -1 ;
|
|
dj = -(*dx) ;
|
|
goto L40 ;
|
|
|
|
/* DX .GT. 0D0 */
|
|
|
|
L30:
|
|
rs = 1 ;
|
|
dj = *dx ;
|
|
|
|
L40:
|
|
ie = 0 ;
|
|
|
|
L50:
|
|
if (dj < 1.) goto L60 ;
|
|
|
|
/* INCREASE IE AND DIVIDE DJ BY 16. */
|
|
|
|
++ie ;
|
|
dj *= .0625 ;
|
|
goto L50 ;
|
|
|
|
L60:
|
|
if (dj >= .0625) goto L70 ;
|
|
|
|
--ie ;
|
|
dj *= 16. ;
|
|
goto L60 ;
|
|
|
|
/* NOW DJ IS DY DIVIDED BY SUITABLE POWER OF 16
|
|
* SET EXPONENT TO 0
|
|
*/
|
|
|
|
L70:
|
|
re = 0 ;
|
|
|
|
/* DB = DFLOAT(B) IS NOT ANSI STANDARD SO USE FLOAT AND DBLE */
|
|
|
|
db = (double) ((float) MP.b) ;
|
|
|
|
/* CONVERSION LOOP (ASSUME DOUBLE-PRECISION OPS. EXACT) */
|
|
|
|
i__1 = i2 ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
dj = db * dj ;
|
|
MP.r[i - 1] = (int) dj ;
|
|
dj -= (double) ((float) MP.r[i - 1]) ;
|
|
}
|
|
|
|
/* NORMALIZE RESULT */
|
|
|
|
mpnzr(&rs, &re, &z[1], &c__0) ;
|
|
|
|
/* Computing MAX */
|
|
|
|
i__1 = MP.b * 7 * MP.b ;
|
|
ib = max(i__1, 32767) / 16 ;
|
|
tp = 1 ;
|
|
|
|
/* NOW MULTIPLY BY 16**IE */
|
|
|
|
if (ie < 0) goto L90 ;
|
|
else if (ie == 0) goto L130 ;
|
|
else goto L110 ;
|
|
|
|
L90:
|
|
k = -ie ;
|
|
i__1 = k ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
tp <<= 4 ;
|
|
if (tp <= ib && tp != MP.b && i < k) continue ;
|
|
mpdivi(&z[1], &tp, &z[1]) ;
|
|
tp = 1 ;
|
|
}
|
|
return ;
|
|
|
|
L110:
|
|
i__1 = ie ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
tp <<= 4 ;
|
|
if (tp <= ib && tp != MP.b && i < ie) continue ;
|
|
mpmuli(&z[1], &tp, &z[1]) ;
|
|
tp = 1 ;
|
|
}
|
|
|
|
L130:
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpchk(int *i, int *j)
|
|
{
|
|
static int ib, mx ;
|
|
|
|
/* CHECKS LEGALITY OF B, T, M AND MXR.
|
|
* THE CONDITION ON MXR (THE DIMENSION OF R IN COMMON) IS THAT
|
|
* MXR .GE. (I*T + J)
|
|
*/
|
|
|
|
/* CHECK LEGALITY OF B, T AND M */
|
|
|
|
if (MP.b > 1) goto L40 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKC]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKD]) ;
|
|
}
|
|
mperr() ;
|
|
|
|
L40:
|
|
if (MP.t > 1) goto L60 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKE]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKF]) ;
|
|
}
|
|
mperr() ;
|
|
|
|
L60:
|
|
if (MP.m > MP.t) goto L80 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKG]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKH]) ;
|
|
}
|
|
mperr() ;
|
|
|
|
/* 8*B*B-1 SHOULD BE REPRESENTABLE, IF NOT WILL OVERFLOW
|
|
* AND MAY BECOME NEGATIVE, SO CHECK FOR THIS
|
|
*/
|
|
|
|
L80:
|
|
ib = (MP.b << 2) * MP.b - 1 ;
|
|
if (ib > 0 && (ib << 1) + 1 > 0) goto L100 ;
|
|
|
|
if (v->MPerrors)
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKI]) ;
|
|
|
|
mperr() ;
|
|
|
|
/* CHECK THAT SPACE IN COMMON IS SUFFICIENT */
|
|
|
|
L100:
|
|
mx = *i * MP.t + *j ;
|
|
if (MP.mxr >= mx) return ;
|
|
|
|
/* HERE COMMON IS TOO SMALL, SO GIVE ERROR MESSAGE. */
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
char *msg;
|
|
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKJ]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CHKL]) ;
|
|
msg = (char *) XtMalloc(strlen( mpstrs[(int) MP_CHKM]) + 200);
|
|
sprintf(msg, mpstrs[(int) MP_CHKM], *i, *j, mx) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, msg);
|
|
sprintf(msg, mpstrs[(int) MP_CHKN], MP.mxr, MP.t) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, msg);
|
|
XtFree(msg);
|
|
}
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcim(int *ix, int *z)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, n ;
|
|
|
|
/* CONVERTS INTEGER IX TO MULTIPLE-PRECISION Z.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
n = *ix ;
|
|
if (n < 0) goto L20 ;
|
|
else if (n == 0) goto L10 ;
|
|
else goto L30 ;
|
|
|
|
L10:
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
L20:
|
|
n = -n ;
|
|
z[1] = -1 ;
|
|
goto L40 ;
|
|
|
|
L30:
|
|
z[1] = 1 ;
|
|
|
|
/* SET EXPONENT TO T */
|
|
|
|
L40:
|
|
z[2] = MP.t ;
|
|
|
|
/* CLEAR FRACTION */
|
|
|
|
i__1 = MP.t ;
|
|
for (i = 2; i <= i__1; ++i) z[i + 1] = 0 ;
|
|
|
|
/* INSERT N */
|
|
|
|
z[MP.t + 2] = n ;
|
|
|
|
/* NORMALIZE BY CALLING MPMUL2 */
|
|
|
|
mpmul2(&z[1], &c__1, &z[1], &c__1) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcmd(int *x, double *dz)
|
|
{
|
|
int i__1 ;
|
|
double d__1 ;
|
|
|
|
static int i, tm ;
|
|
static double db, dz2 ;
|
|
|
|
/* CONVERTS MULTIPLE-PRECISION X TO DOUBLE-PRECISION DZ.
|
|
* ASSUMES X IS IN ALLOWABLE RANGE FOR DOUBLE-PRECISION
|
|
* NUMBERS. THERE IS SOME LOSS OF ACCURACY IF THE
|
|
* EXPONENT IS LARGE.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
*dz = 0. ;
|
|
if (x[1] == 0) return ;
|
|
|
|
/* DB = DFLOAT(B) IS NOT ANSI STANDARD, SO USE FLOAT AND DBLE */
|
|
|
|
db = (double) ((float) MP.b) ;
|
|
i__1 = MP.t ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
*dz = db * *dz + (double) ((float) x[i + 2]) ;
|
|
tm = i ;
|
|
|
|
/* CHECK IF FULL DOUBLE-PRECISION ACCURACY ATTAINED */
|
|
|
|
dz2 = *dz + 1. ;
|
|
|
|
/* TEST BELOW NOT ALWAYS EQUIVALENT TO - IF (DZ2.LE.DZ) GO TO 20,
|
|
* FOR EXAMPLE ON CYBER 76.
|
|
*/
|
|
if (dz2 - *dz <= 0.) goto L20 ;
|
|
}
|
|
|
|
/* NOW ALLOW FOR EXPONENT */
|
|
|
|
L20:
|
|
i__1 = x[2] - tm ;
|
|
*dz *= mppow_di(&db, &i__1) ;
|
|
|
|
/* CHECK REASONABLENESS OF RESULT. */
|
|
|
|
if (*dz <= 0.) goto L30 ;
|
|
|
|
/* LHS SHOULD BE .LE. 0.5 BUT ALLOW FOR SOME ERROR IN DLOG */
|
|
|
|
if ((d__1 = (double) ((float) x[2]) - (log(*dz) / log((double)
|
|
((float) MP.b)) + .5), C_abs(d__1)) > .6)
|
|
goto L30 ;
|
|
|
|
if (x[1] < 0) *dz = -(*dz) ;
|
|
return ;
|
|
|
|
/* FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
|
|
* TRY USING MPCMDE INSTEAD.
|
|
*/
|
|
|
|
L30:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CMD]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcmf(int *x, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i ;
|
|
static int x2, il, ip, xs ;
|
|
|
|
/* FOR MP X AND Y, RETURNS FRACTIONAL PART OF X IN Y,
|
|
* I.E., Y = X - INTEGER PART OF X (TRUNCATED TOWARDS 0).
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
if (x[1] != 0) goto L20 ;
|
|
|
|
/* RETURN 0 IF X = 0 */
|
|
|
|
L10:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
L20:
|
|
x2 = x[2] ;
|
|
|
|
/* RETURN 0 IF EXPONENT SO LARGE THAT NO FRACTIONAL PART */
|
|
|
|
if (x2 >= MP.t) goto L10 ;
|
|
|
|
/* IF EXPONENT NOT POSITIVE CAN RETURN X */
|
|
|
|
if (x2 > 0) goto L30 ;
|
|
|
|
mpstr(&x[1], &y[1]) ;
|
|
return ;
|
|
|
|
/* CLEAR ACCUMULATOR */
|
|
|
|
L30:
|
|
i__1 = x2 ;
|
|
for (i = 1; i <= i__1; ++i) MP.r[i - 1] = 0 ;
|
|
|
|
il = x2 + 1 ;
|
|
|
|
/* MOVE FRACTIONAL PART OF X TO ACCUMULATOR */
|
|
|
|
i__1 = MP.t ;
|
|
for (i = il; i <= i__1; ++i) MP.r[i - 1] = x[i + 2] ;
|
|
|
|
for (i = 1; i <= 4; ++i)
|
|
{
|
|
ip = i + MP.t ;
|
|
MP.r[ip - 1] = 0 ;
|
|
}
|
|
xs = x[1] ;
|
|
|
|
/* NORMALIZE RESULT AND RETURN */
|
|
|
|
mpnzr(&xs, &x2, &y[1], &c__1) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcmi(int *x, int *iz)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, j, k, j1, x2, kx, xs, izs ;
|
|
|
|
/* CONVERTS MULTIPLE-PRECISION X TO INTEGER IZ,
|
|
* ASSUMING THAT X NOT TOO LARGE (ELSE USE MPCMIM).
|
|
* X IS TRUNCATED TOWARDS ZERO.
|
|
* IF INT(X)IS TOO LARGE TO BE REPRESENTED AS A SINGLE-
|
|
* PRECISION INTEGER, IZ IS RETURNED AS ZERO. THE USER
|
|
* MAY CHECK FOR THIS POSSIBILITY BY TESTING IF
|
|
* ((X(1).NE.0).AND.(X(2).GT.0).AND.(IZ.EQ.0)) IS TRUE ON
|
|
* RETURN FROM MPCMI.
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
xs = x[1] ;
|
|
*iz = 0 ;
|
|
if (xs == 0) return ;
|
|
|
|
if (x[2] <= 0) return ;
|
|
|
|
x2 = x[2] ;
|
|
i__1 = x2 ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
izs = *iz ;
|
|
*iz = MP.b * *iz ;
|
|
if (i <= MP.t) *iz += x[i + 2] ;
|
|
|
|
/* CHECK FOR SIGNS OF INTEGER OVERFLOW */
|
|
|
|
if (*iz <= 0 || *iz <= izs) goto L30 ;
|
|
}
|
|
|
|
/* CHECK THAT RESULT IS CORRECT (AN UNDETECTED OVERFLOW MAY
|
|
* HAVE OCCURRED).
|
|
*/
|
|
|
|
j = *iz ;
|
|
i__1 = x2 ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
j1 = j / MP.b ;
|
|
k = x2 + 1 - i ;
|
|
kx = 0 ;
|
|
if (k <= MP.t) kx = x[k + 2] ;
|
|
if (kx != j - MP.b * j1) goto L30 ;
|
|
j = j1 ;
|
|
}
|
|
if (j != 0) goto L30 ;
|
|
|
|
/* RESULT CORRECT SO RESTORE SIGN AND RETURN */
|
|
|
|
*iz = xs * *iz ;
|
|
return ;
|
|
|
|
/* HERE OVERFLOW OCCURRED (OR X WAS UNNORMALIZED), SO
|
|
* RETURN ZERO.
|
|
*/
|
|
|
|
L30:
|
|
*iz = 0 ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcmim(int *x, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, il ;
|
|
|
|
/* RETURNS Y = INTEGER PART OF X (TRUNCATED TOWARDS 0), FOR MP X AND Y.
|
|
* USE IF Y TOO LARGE TO BE REPRESENTABLE AS A SINGLE-PRECISION INTEGER.
|
|
* (ELSE COULD USE MPCMI).
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
mpstr(&x[1], &y[1]) ;
|
|
if (y[1] == 0) return ;
|
|
|
|
il = y[2] + 1 ;
|
|
|
|
/* IF EXPONENT LARGE ENOUGH RETURN Y = X */
|
|
|
|
if (il > MP.t) return ;
|
|
|
|
/* IF EXPONENT SMALL ENOUGH RETURN ZERO */
|
|
|
|
if (il > 1) goto L10 ;
|
|
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* SET FRACTION TO ZERO */
|
|
|
|
L10:
|
|
i__1 = MP.t ;
|
|
for (i = il; i <= i__1; ++i) y[i + 2] = 0 ;
|
|
return ;
|
|
}
|
|
|
|
|
|
int
|
|
mpcmpi(int *x, int *i)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* COMPARES MP NUMBER X WITH INTEGER I, RETURNING
|
|
* +1 IF X .GT. I,
|
|
* 0 IF X .EQ. I,
|
|
* -1 IF X .LT. I
|
|
* DIMENSION OF R IN COMMON AT LEAST 2T+6
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__2, &c__6) ;
|
|
|
|
/* CONVERT I TO MULTIPLE-PRECISION AND COMPARE */
|
|
|
|
mpcim(i, &MP.r[MP.t + 4]) ;
|
|
ret_val = mpcomp(&x[1], &MP.r[MP.t + 4]) ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
int
|
|
mpcmpr(int *x, float *ri)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* COMPARES MP NUMBER X WITH REAL NUMBER RI, RETURNING
|
|
* +1 IF X .GT. RI,
|
|
* 0 IF X .EQ. RI,
|
|
* -1 IF X .LT. RI
|
|
* DIMENSION OF R IN COMMON AT LEAST 2T+6
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__2, &c__6) ;
|
|
|
|
/* CONVERT RI TO MULTIPLE-PRECISION AND COMPARE */
|
|
|
|
mpcrm(ri, &MP.r[MP.t + 4]) ;
|
|
ret_val = mpcomp(&x[1], &MP.r[MP.t + 4]) ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcmr(int *x, float *rz)
|
|
{
|
|
int i__1 ;
|
|
float r__1 ;
|
|
|
|
static int i, tm ;
|
|
static float rb, rz2 ;
|
|
|
|
/* CONVERTS MULTIPLE-PRECISION X TO SINGLE-PRECISION RZ.
|
|
* ASSUMES X IN ALLOWABLE RANGE. THERE IS SOME LOSS OF
|
|
* ACCURACY IF THE EXPONENT IS LARGE.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
*rz = (float) 0.0 ;
|
|
if (x[1] == 0) return ;
|
|
|
|
rb = (float) MP.b ;
|
|
i__1 = MP.t ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
*rz = rb * *rz + (float) x[i + 2] ;
|
|
tm = i ;
|
|
|
|
/* CHECK IF FULL SINGLE-PRECISION ACCURACY ATTAINED */
|
|
|
|
rz2 = *rz + (float) 1.0 ;
|
|
if (rz2 <= *rz) goto L20 ;
|
|
}
|
|
|
|
/* NOW ALLOW FOR EXPONENT */
|
|
|
|
L20:
|
|
i__1 = x[2] - tm ;
|
|
*rz *= mppow_ri(&rb, &i__1) ;
|
|
|
|
/* CHECK REASONABLENESS OF RESULT */
|
|
|
|
if (*rz <= (float)0.) goto L30 ;
|
|
|
|
/* LHS SHOULD BE .LE. 0.5, BUT ALLOW FOR SOME ERROR IN ALOG */
|
|
|
|
if ((r__1 = (float) x[2] - (log(*rz) / log((float) MP.b) + (float).5),
|
|
dabs(r__1)) > (float).6)
|
|
goto L30 ;
|
|
|
|
if (x[1] < 0) *rz = -(double)(*rz) ;
|
|
return ;
|
|
|
|
/* FOLLOWING MESSAGE INDICATES THAT X IS TOO LARGE OR SMALL -
|
|
* TRY USING MPCMRE INSTEAD.
|
|
*/
|
|
|
|
L30:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CMR]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
int
|
|
mpcomp(int *x, int *y)
|
|
{
|
|
int ret_val, i__1, i__2 ;
|
|
|
|
static int i, t2 ;
|
|
|
|
/* COMPARES THE MULTIPLE-PRECISION NUMBERS X AND Y,
|
|
* RETURNING +1 IF X .GT. Y,
|
|
* -1 IF X .LT. Y,
|
|
* AND 0 IF X .EQ. Y.
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
if ((i__1 = x[1] - y[1]) < 0) goto L10 ;
|
|
else if (i__1 == 0) goto L30 ;
|
|
else goto L20 ;
|
|
|
|
/* X .LT. Y */
|
|
|
|
L10:
|
|
ret_val = -1 ;
|
|
return(ret_val) ;
|
|
|
|
/* X .GT. Y */
|
|
|
|
L20:
|
|
ret_val = 1 ;
|
|
return(ret_val) ;
|
|
|
|
/* SIGN(X) = SIGN(Y), SEE IF ZERO */
|
|
|
|
L30:
|
|
if (x[1] != 0) goto L40 ;
|
|
|
|
/* X = Y = 0 */
|
|
|
|
ret_val = 0 ;
|
|
return(ret_val) ;
|
|
|
|
/* HAVE TO COMPARE EXPONENTS AND FRACTIONS */
|
|
|
|
L40:
|
|
t2 = MP.t + 2 ;
|
|
i__1 = t2 ;
|
|
for (i = 2; i <= i__1; ++i)
|
|
{
|
|
if ((i__2 = x[i] - y[i]) < 0) goto L60 ;
|
|
else if (i__2 == 0) continue ;
|
|
else goto L70 ;
|
|
}
|
|
|
|
/* NUMBERS EQUAL */
|
|
|
|
ret_val = 0 ;
|
|
return(ret_val) ;
|
|
|
|
/* ABS(X) .LT. ABS(Y) */
|
|
|
|
L60:
|
|
ret_val = -x[1] ;
|
|
return(ret_val) ;
|
|
|
|
/* ABS(X) .GT. ABS(Y) */
|
|
|
|
L70:
|
|
ret_val = x[1] ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcos(int *x, int *y)
|
|
{
|
|
static int i2 ;
|
|
|
|
/* RETURNS Y = COS(X) FOR MP X AND Y, USING MPSIN AND MPSIN1.
|
|
* DIMENSION OF R IN COMMON AT LEAST 5T+12.
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
if (x[1] != 0) goto L10 ;
|
|
|
|
/* COS(0) = 1 */
|
|
|
|
mpcim(&c__1, &y[1]) ;
|
|
return ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR */
|
|
|
|
L10:
|
|
mpchk(&c__5, &c__12) ;
|
|
i2 = MP.t * 3 + 12 ;
|
|
|
|
/* SEE IF ABS(X) .LE. 1 */
|
|
|
|
mpabs(&x[1], &y[1]) ;
|
|
if (mpcmpi(&y[1], &c__1) <= 0) goto L20 ;
|
|
|
|
/* HERE ABS(X) .GT. 1 SO USE COS(X) = SIN(PI/2 - ABS(X)),
|
|
* COMPUTING PI/2 WITH ONE GUARD DIGIT.
|
|
*/
|
|
|
|
++MP.t ;
|
|
mppi(&MP.r[i2 - 1]) ;
|
|
mpdivi(&MP.r[i2 - 1], &c__2, &MP.r[i2 - 1]) ;
|
|
--MP.t ;
|
|
mpsub(&MP.r[i2 - 1], &y[1], &y[1]) ;
|
|
mpsin(&y[1], &y[1]) ;
|
|
return ;
|
|
|
|
/* HERE ABS(X) .LE. 1 SO USE POWER SERIES */
|
|
|
|
L20:
|
|
mpsin1(&y[1], &y[1], &c__0) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcosh(int *x, int *y)
|
|
{
|
|
static int i2 ;
|
|
|
|
/* RETURNS Y = COSH(X) FOR MP NUMBERS X AND Y, X NOT TOO LARGE.
|
|
* USES MPEXP, DIMENSION OF R IN COMMON AT LEAST 5T+12
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
if (x[1] != 0) goto L10 ;
|
|
|
|
/* COSH(0) = 1 */
|
|
|
|
mpcim(&c__1, &y[1]) ;
|
|
return ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR */
|
|
|
|
L10:
|
|
mpchk(&c__5, &c__12) ;
|
|
i2 = (MP.t << 2) + 11 ;
|
|
mpabs(&x[1], &MP.r[i2 - 1]) ;
|
|
|
|
/* IF ABS(X) TOO LARGE MPEXP WILL PRINT ERROR MESSAGE
|
|
* INCREASE M TO AVOID OVERFLOW WHEN COSH(X) REPRESENTABLE
|
|
*/
|
|
|
|
MP.m += 2 ;
|
|
mpexp(&MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
mprec(&MP.r[i2 - 1], &y[1]) ;
|
|
mpadd(&MP.r[i2 - 1], &y[1], &y[1]) ;
|
|
|
|
/* RESTORE M. IF RESULT OVERFLOWS OR UNDERFLOWS, MPDIVI WILL
|
|
* ACT ACCORDINGLY.
|
|
*/
|
|
|
|
MP.m += -2 ;
|
|
mpdivi(&y[1], &c__2, &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcqm(int *i, int *j, int *q)
|
|
{
|
|
static int i1, j1 ;
|
|
|
|
/* CONVERTS THE RATIONAL NUMBER I/J TO MULTIPLE PRECISION Q. */
|
|
|
|
--q ; /* Parameter adjustments */
|
|
|
|
i1 = *i ;
|
|
j1 = *j ;
|
|
mpgcd(&i1, &j1) ;
|
|
if (j1 < 0) goto L30 ;
|
|
else if (j1 == 0) goto L10 ;
|
|
else goto L40 ;
|
|
|
|
L10:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_CQM]) ;
|
|
|
|
mperr() ;
|
|
q[1] = 0 ;
|
|
return ;
|
|
|
|
L30:
|
|
i1 = -i1 ;
|
|
j1 = -j1 ;
|
|
|
|
L40:
|
|
mpcim(&i1, &q[1]) ;
|
|
if (j1 != 1) mpdivi(&q[1], &j1, &q[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpcrm(float *rx, int *z)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, k, i2, ib, ie, re, tp, rs ;
|
|
static float rb, rj ;
|
|
|
|
/* CONVERTS SINGLE-PRECISION NUMBER RX TO MULTIPLE-PRECISION Z.
|
|
* SOME NUMBERS WILL NOT CONVERT EXACTLY ON MACHINES
|
|
* WITH BASE OTHER THAN TWO, FOUR OR SIXTEEN.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
i2 = MP.t + 4 ;
|
|
|
|
/* CHECK SIGN */
|
|
|
|
if (*rx < (float) 0.0) goto L20 ;
|
|
else if (*rx == 0) goto L10 ;
|
|
else goto L30 ;
|
|
|
|
/* IF RX = 0E0 RETURN 0 */
|
|
|
|
L10:
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* RX .LT. 0E0 */
|
|
|
|
L20:
|
|
rs = -1 ;
|
|
rj = -(double)(*rx) ;
|
|
goto L40 ;
|
|
|
|
/* RX .GT. 0E0 */
|
|
|
|
L30:
|
|
rs = 1 ;
|
|
rj = *rx ;
|
|
|
|
L40:
|
|
ie = 0 ;
|
|
|
|
L50:
|
|
if (rj < (float)1.0) goto L60 ;
|
|
|
|
/* INCREASE IE AND DIVIDE RJ BY 16. */
|
|
|
|
++ie ;
|
|
rj *= (float) 0.0625 ;
|
|
goto L50 ;
|
|
|
|
L60:
|
|
if (rj >= (float).0625) goto L70 ;
|
|
|
|
--ie ;
|
|
rj *= (float)16.0 ;
|
|
goto L60 ;
|
|
|
|
/* NOW RJ IS DY DIVIDED BY SUITABLE POWER OF 16.
|
|
* SET EXPONENT TO 0
|
|
*/
|
|
|
|
L70:
|
|
re = 0 ;
|
|
rb = (float) MP.b ;
|
|
|
|
/* CONVERSION LOOP (ASSUME SINGLE-PRECISION OPS. EXACT) */
|
|
|
|
i__1 = i2 ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
rj = rb * rj ;
|
|
MP.r[i - 1] = (int) rj ;
|
|
rj -= (float) MP.r[i - 1] ;
|
|
}
|
|
|
|
/* NORMALIZE RESULT */
|
|
|
|
mpnzr(&rs, &re, &z[1], &c__0) ;
|
|
|
|
/* Computing MAX */
|
|
|
|
i__1 = MP.b * 7 * MP.b ;
|
|
ib = max(i__1, 32767) / 16 ;
|
|
tp = 1 ;
|
|
|
|
/* NOW MULTIPLY BY 16**IE */
|
|
|
|
if (ie < 0) goto L90 ;
|
|
else if (ie == 0) goto L130 ;
|
|
else goto L110 ;
|
|
|
|
L90:
|
|
k = -ie ;
|
|
i__1 = k ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
tp <<= 4 ;
|
|
if (tp <= ib && tp != MP.b && i < k) continue ;
|
|
mpdivi(&z[1], &tp, &z[1]) ;
|
|
tp = 1 ;
|
|
}
|
|
return ;
|
|
|
|
L110:
|
|
i__1 = ie ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
tp <<= 4 ;
|
|
if (tp <= ib && tp != MP.b && i < ie) continue ;
|
|
mpmuli(&z[1], &tp, &z[1]) ;
|
|
tp = 1 ;
|
|
}
|
|
|
|
L130:
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpdiv(int *x, int *y, int *z)
|
|
{
|
|
static int i, i2, ie, iz3 ;
|
|
|
|
/* SETS Z = X/Y, FOR MP X, Y AND Z.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 4T+10
|
|
* (BUT Z(1) MAY BE R(3T+9)).
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--y ;
|
|
--x ;
|
|
|
|
mpchk(&c__4, &c__10) ;
|
|
|
|
/* CHECK FOR DIVISION BY ZERO */
|
|
|
|
if (y[1] != 0) goto L20 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_DIVA]) ;
|
|
|
|
mperr() ;
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* SPACE USED BY MPREC IS 4T+10 WORDS, BUT CAN OVERLAP SLIGHTLY. */
|
|
|
|
L20:
|
|
i2 = MP.t * 3 + 9 ;
|
|
|
|
/* CHECK FOR X = 0 */
|
|
|
|
if (x[1] != 0) goto L30 ;
|
|
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* INCREASE M TO AVOID OVERFLOW IN MPREC */
|
|
|
|
L30:
|
|
MP.m += 2 ;
|
|
|
|
/* FORM RECIPROCAL OF Y */
|
|
|
|
mprec(&y[1], &MP.r[i2 - 1]) ;
|
|
|
|
/* SET EXPONENT OF R(I2) TO ZERO TO AVOID OVERFLOW IN MPMUL */
|
|
|
|
ie = MP.r[i2] ;
|
|
MP.r[i2] = 0 ;
|
|
i = MP.r[i2 + 1] ;
|
|
|
|
/* MULTIPLY BY X */
|
|
|
|
mpmul(&x[1], &MP.r[i2 - 1], &z[1]) ;
|
|
iz3 = z[3] ;
|
|
mpext(&i, &iz3, &z[1]) ;
|
|
|
|
/* RESTORE M, CORRECT EXPONENT AND RETURN */
|
|
|
|
MP.m += -2 ;
|
|
z[2] += ie ;
|
|
if (z[2] >= -MP.m) goto L40 ;
|
|
|
|
/* UNDERFLOW HERE */
|
|
|
|
mpunfl(&z[1]) ;
|
|
return ;
|
|
|
|
L40:
|
|
if (z[2] <= MP.m) return ;
|
|
|
|
/* OVERFLOW HERE */
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_DIVB]) ;
|
|
|
|
mpovfl(&z[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpdivi(int *x, int *iy, int*z)
|
|
{
|
|
int i__1, i__2 ;
|
|
|
|
static int c, i, j, k, b2, c2, i2, j1, j2, r1 ;
|
|
static int j11, kh, re, iq, ir, rs, iqj ;
|
|
|
|
/* DIVIDES MP X BY THE SINGLE-PRECISION INTEGER IY GIVING MP Z.
|
|
* THIS IS MUCH FASTER THAN DIVISION BY AN MP NUMBER.
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
rs = x[1] ;
|
|
j = *iy ;
|
|
if (j < 0) goto L30 ;
|
|
else if (j == 0) goto L10 ;
|
|
else goto L40 ;
|
|
|
|
L10:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_DIVIA]) ;
|
|
|
|
goto L230 ;
|
|
|
|
L30:
|
|
j = -j ;
|
|
rs = -rs ;
|
|
|
|
L40:
|
|
re = x[2] ;
|
|
|
|
/* CHECK FOR ZERO DIVIDEND */
|
|
|
|
if (rs == 0) goto L120 ;
|
|
|
|
/* CHECK FOR DIVISION BY B */
|
|
|
|
if (j != MP.b) goto L50 ;
|
|
mpstr(&x[1], &z[1]) ;
|
|
if (re <= -MP.m) goto L240 ;
|
|
z[1] = rs ;
|
|
z[2] = re - 1 ;
|
|
return ;
|
|
|
|
/* CHECK FOR DIVISION BY 1 OR -1 */
|
|
|
|
L50:
|
|
if (j != 1) goto L60 ;
|
|
mpstr(&x[1], &z[1]) ;
|
|
z[1] = rs ;
|
|
return ;
|
|
|
|
L60:
|
|
c = 0 ;
|
|
i2 = MP.t + 4 ;
|
|
i = 0 ;
|
|
|
|
/* IF J*B NOT REPRESENTABLE AS AN INTEGER HAVE TO SIMULATE
|
|
* LONG DIVISION. ASSUME AT LEAST 16-BIT WORD.
|
|
*/
|
|
|
|
/* Computing MAX */
|
|
|
|
i__1 = MP.b << 3, i__2 = 32767 / MP.b ;
|
|
b2 = max(i__1,i__2) ;
|
|
if (j >= b2) goto L130 ;
|
|
|
|
/* LOOK FOR FIRST NONZERO DIGIT IN QUOTIENT */
|
|
|
|
L70:
|
|
++i ;
|
|
c = MP.b * c ;
|
|
if (i <= MP.t) c += x[i + 2] ;
|
|
r1 = c / j ;
|
|
if (r1 < 0) goto L210 ;
|
|
else if (r1 == 0) goto L70 ;
|
|
else goto L80 ;
|
|
|
|
/* ADJUST EXPONENT AND GET T+4 DIGITS IN QUOTIENT */
|
|
|
|
L80:
|
|
re = re + 1 - i ;
|
|
MP.r[0] = r1 ;
|
|
c = MP.b * (c - j * r1) ;
|
|
kh = 2 ;
|
|
if (i >= MP.t) goto L100 ;
|
|
kh = MP.t + 1 - i ;
|
|
i__1 = kh ;
|
|
for (k = 2; k <= i__1; ++k)
|
|
{
|
|
++i ;
|
|
c += x[i + 2] ;
|
|
MP.r[k - 1] = c / j ;
|
|
c = MP.b * (c - j * MP.r[k - 1]) ;
|
|
}
|
|
if (c < 0) goto L210 ;
|
|
++kh ;
|
|
|
|
L100:
|
|
i__1 = i2 ;
|
|
for (k = kh; k <= i__1; ++k)
|
|
{
|
|
MP.r[k - 1] = c / j ;
|
|
c = MP.b * (c - j * MP.r[k - 1]) ;
|
|
}
|
|
if (c < 0) goto L210 ;
|
|
|
|
/* NORMALIZE AND ROUND RESULT */
|
|
|
|
L120:
|
|
mpnzr(&rs, &re, &z[1], &c__0) ;
|
|
return ;
|
|
|
|
/* HERE NEED SIMULATED DOUBLE-PRECISION DIVISION */
|
|
|
|
L130:
|
|
c2 = 0 ;
|
|
j1 = j / MP.b ;
|
|
j2 = j - j1 * MP.b ;
|
|
j11 = j1 + 1 ;
|
|
|
|
/* LOOK FOR FIRST NONZERO DIGIT */
|
|
|
|
L140:
|
|
++i ;
|
|
c = MP.b * c + c2 ;
|
|
c2 = 0 ;
|
|
if (i <= MP.t) c2 = x[i + 2] ;
|
|
if ((i__1 = c - j1) < 0) goto L140 ;
|
|
else if (i__1 == 0) goto L150 ;
|
|
else goto L160 ;
|
|
|
|
L150:
|
|
if (c2 < j2) goto L140 ;
|
|
|
|
/* COMPUTE T+4 QUOTIENT DIGITS */
|
|
|
|
L160:
|
|
re = re + 1 - i ;
|
|
k = 1 ;
|
|
goto L180 ;
|
|
|
|
/* MAIN LOOP FOR LARGE ABS(IY) CASE */
|
|
|
|
L170:
|
|
++k ;
|
|
if (k > i2) goto L120 ;
|
|
++i ;
|
|
|
|
/* GET APPROXIMATE QUOTIENT FIRST */
|
|
|
|
L180:
|
|
ir = c / j11 ;
|
|
|
|
/* NOW REDUCE SO OVERFLOW DOES NOT OCCUR */
|
|
|
|
iq = c - ir * j1 ;
|
|
if (iq < b2) goto L190 ;
|
|
|
|
/* HERE IQ*B WOULD POSSIBLY OVERFLOW SO INCREASE IR */
|
|
|
|
++ir ;
|
|
iq -= j1 ;
|
|
|
|
L190:
|
|
iq = iq * MP.b - ir * j2 ;
|
|
if (iq >= 0) goto L200 ;
|
|
|
|
/* HERE IQ NEGATIVE SO IR WAS TOO LARGE */
|
|
|
|
--ir ;
|
|
iq += j ;
|
|
|
|
L200:
|
|
if (i <= MP.t) iq += x[i + 2] ;
|
|
iqj = iq / j ;
|
|
|
|
/* R(K) = QUOTIENT, C = REMAINDER */
|
|
|
|
MP.r[k - 1] = iqj + ir ;
|
|
c = iq - j * iqj ;
|
|
if (c >= 0) goto L170 ;
|
|
|
|
/* CARRY NEGATIVE SO OVERFLOW MUST HAVE OCCURRED */
|
|
|
|
L210:
|
|
mpchk(&c__1, &c__4) ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_DIVIB]) ;
|
|
|
|
L230:
|
|
mperr() ;
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* UNDERFLOW HERE */
|
|
|
|
L240:
|
|
mpunfl(&z[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
int
|
|
mpeq(int *x, int *y)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* RETURNS LOGICAL VALUE OF (X .EQ. Y) FOR MP X AND Y. */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
ret_val = mpcomp(&x[1], &y[1]) == 0 ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
void
|
|
mperr(void)
|
|
{
|
|
|
|
/* THIS ROUTINE IS CALLED WHEN AN ERROR CONDITION IS ENCOUNTERED, AND
|
|
* AFTER A MESSAGE HAS BEEN WRITTEN TO STDERR.
|
|
*/
|
|
|
|
doerr(vstrs[(int) V_ERROR]) ;
|
|
}
|
|
|
|
|
|
void
|
|
mpexp(int *x, int *y)
|
|
{
|
|
int i__1, i__2 ;
|
|
float r__1 ;
|
|
|
|
static int i, i2, i3, ie, ix, ts, xs, tss ;
|
|
static float rx, ry, rlb ;
|
|
|
|
/* RETURNS Y = EXP(X) FOR MP X AND Y.
|
|
* EXP OF INTEGER AND FRACTIONAL PARTS OF X ARE COMPUTED
|
|
* SEPARATELY. SEE ALSO COMMENTS IN MPEXP1.
|
|
* TIME IS O(SQRT(T)M(T)).
|
|
* DIMENSION OF R MUST BE AT LEAST 4T+10 IN CALLING PROGRAM
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__4, &c__10) ;
|
|
i2 = (MP.t << 1) + 7 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
|
|
/* CHECK FOR X = 0 */
|
|
|
|
if (x[1] != 0) goto L10 ;
|
|
mpcim(&c__1, &y[1]) ;
|
|
return ;
|
|
|
|
/* CHECK IF ABS(X) .LT. 1 */
|
|
|
|
L10:
|
|
if (x[2] > 0) goto L20 ;
|
|
|
|
/* USE MPEXP1 HERE */
|
|
|
|
mpexp1(&x[1], &y[1]) ;
|
|
mpaddi(&y[1], &c__1, &y[1]) ;
|
|
return ;
|
|
|
|
/* SEE IF ABS(X) SO LARGE THAT EXP(X) WILL CERTAINLY OVERFLOW
|
|
* OR UNDERFLOW. 1.01 IS TO ALLOW FOR ERRORS IN ALOG.
|
|
*/
|
|
|
|
L20:
|
|
rlb = log((float) MP.b) * (float)1.01 ;
|
|
r__1 = -(double)((float) (MP.m + 1)) * rlb ;
|
|
if (mpcmpr(&x[1], &r__1) >= 0) goto L40 ;
|
|
|
|
/* UNDERFLOW SO CALL MPUNFL AND RETURN */
|
|
|
|
L30:
|
|
mpunfl(&y[1]) ;
|
|
return ;
|
|
|
|
L40:
|
|
r__1 = (float) MP.m * rlb ;
|
|
if (mpcmpr(&x[1], &r__1) <= 0) goto L70 ;
|
|
|
|
/* OVERFLOW HERE */
|
|
|
|
L50:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_EXPA]) ;
|
|
|
|
mpovfl(&y[1]) ;
|
|
return ;
|
|
|
|
/* NOW SAFE TO CONVERT X TO REAL */
|
|
|
|
L70:
|
|
mpcmr(&x[1], &rx) ;
|
|
|
|
/* SAVE SIGN AND WORK WITH ABS(X) */
|
|
|
|
xs = x[1] ;
|
|
mpabs(&x[1], &MP.r[i3 - 1]) ;
|
|
|
|
/* IF ABS(X) .GT. M POSSIBLE THAT INT(X) OVERFLOWS,
|
|
* SO DIVIDE BY 32.
|
|
*/
|
|
|
|
if (dabs(rx) > (float) MP.m)
|
|
mpdivi(&MP.r[i3 - 1], &c__32, &MP.r[i3 - 1]) ;
|
|
|
|
/* GET FRACTIONAL AND INTEGER PARTS OF ABS(X) */
|
|
|
|
mpcmi(&MP.r[i3 - 1], &ix) ;
|
|
mpcmf(&MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
|
|
/* ATTACH SIGN TO FRACTIONAL PART AND COMPUTE EXP OF IT */
|
|
|
|
MP.r[i3 - 1] = xs * MP.r[i3 - 1] ;
|
|
mpexp1(&MP.r[i3 - 1], &y[1]) ;
|
|
mpaddi(&y[1], &c__1, &y[1]) ;
|
|
|
|
/* COMPUTE E-2 OR 1/E USING TWO EXTRA DIGITS IN CASE ABS(X) LARGE
|
|
* (BUT ONLY ONE EXTRA DIGIT IF T .LT. 4)
|
|
*/
|
|
|
|
tss = MP.t ;
|
|
ts = MP.t + 2 ;
|
|
if (MP.t < 4) ts = MP.t + 1 ;
|
|
MP.t = ts ;
|
|
i2 = MP.t + 5 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
MP.r[i3 - 1] = 0 ;
|
|
mpcim(&xs, &MP.r[i2 - 1]) ;
|
|
i = 1 ;
|
|
|
|
/* LOOP FOR E COMPUTATION. DECREASE T IF POSSIBLE. */
|
|
|
|
L80:
|
|
|
|
/* Computing MIN */
|
|
|
|
i__1 = ts, i__2 = ts + 2 + MP.r[i2] ;
|
|
MP.t = min(i__1,i__2) ;
|
|
if (MP.t <= 2) goto L90 ;
|
|
++i ;
|
|
i__1 = i * xs ;
|
|
mpdivi(&MP.r[i2 - 1], &i__1, &MP.r[i2 - 1]) ;
|
|
MP.t = ts ;
|
|
mpadd2(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i3 - 1], &
|
|
MP.r[i2 - 1], &c__0) ;
|
|
if (MP.r[i2 - 1] != 0) goto L80 ;
|
|
|
|
/* RAISE E OR 1/E TO POWER IX */
|
|
|
|
L90:
|
|
MP.t = ts ;
|
|
if (xs > 0)
|
|
mpaddi(&MP.r[i3 - 1], &c__2, &MP.r[i3 - 1]) ;
|
|
mppwr(&MP.r[i3 - 1], &ix, &MP.r[i3 - 1]) ;
|
|
|
|
/* RESTORE T NOW */
|
|
|
|
MP.t = tss ;
|
|
|
|
/* MULTIPLY EXPS OF INTEGER AND FRACTIONAL PARTS */
|
|
|
|
mpmul(&y[1], &MP.r[i3 - 1], &y[1]) ;
|
|
|
|
/* MUST CORRECT RESULT IF DIVIDED BY 32 ABOVE. */
|
|
|
|
if (dabs(rx) <= (float) MP.m || y[1] == 0) goto L110 ;
|
|
|
|
for (i = 1; i <= 5; ++i)
|
|
{
|
|
|
|
/* SAVE EXPONENT TO AVOID OVERFLOW IN MPMUL */
|
|
|
|
ie = y[2] ;
|
|
y[2] = 0 ;
|
|
mpmul(&y[1], &y[1], &y[1]) ;
|
|
y[2] += ie << 1 ;
|
|
|
|
/* CHECK FOR UNDERFLOW AND OVERFLOW */
|
|
|
|
if (y[2] < -MP.m) goto L30 ;
|
|
if (y[2] > MP.m) goto L50 ;
|
|
}
|
|
|
|
/* CHECK THAT RELATIVE ERROR LESS THAN 0.01 UNLESS ABS(X) LARGE
|
|
* (WHEN EXP MIGHT OVERFLOW OR UNDERFLOW)
|
|
*/
|
|
|
|
L110:
|
|
if (dabs(rx) > (float)10.0) return ;
|
|
|
|
mpcmr(&y[1], &ry) ;
|
|
if ((r__1 = ry - exp(rx), dabs(r__1)) < ry * (float)0.01) return ;
|
|
|
|
/* THE FOLLOWING MESSAGE MAY INDICATE THAT
|
|
* B**(T-1) IS TOO SMALL, OR THAT M IS TOO SMALL SO THE
|
|
* RESULT UNDERFLOWED.
|
|
*/
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_EXPB]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpexp1(int *x, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, q, i2, i3, ib, ic, ts ;
|
|
static float rlb ;
|
|
|
|
/* ASSUMES THAT X AND Y ARE MP NUMBERS, -1 .LT. X .LT. 1.
|
|
* RETURNS Y = EXP(X) - 1 USING AN O(SQRT(T).M(T)) ALGORITHM
|
|
* DESCRIBED IN - R. P. BRENT, THE COMPLEXITY OF MULTIPLE-
|
|
* PRECISION ARITHMETIC (IN COMPLEXITY OF COMPUTATIONAL PROBLEM
|
|
* SOLVING, UNIV. OF QUEENSLAND PRESS, BRISBANE, 1976, 126-165).
|
|
* ASYMPTOTICALLY FASTER METHODS EXIST, BUT ARE NOT USEFUL
|
|
* UNLESS T IS VERY LARGE. SEE COMMENTS TO MPATAN AND MPPIGL.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 3T+8
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__3, &c__8) ;
|
|
i2 = MP.t + 5 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
|
|
/* CHECK FOR X = 0 */
|
|
|
|
if (x[1] != 0) goto L20 ;
|
|
|
|
L10:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* CHECK THAT ABS(X) .LT. 1 */
|
|
|
|
L20:
|
|
if (x[2] <= 0) goto L40 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_EXP1]) ;
|
|
|
|
mperr() ;
|
|
goto L10 ;
|
|
|
|
L40:
|
|
mpstr(&x[1], &MP.r[i2 - 1]) ;
|
|
rlb = log((float) MP.b) ;
|
|
|
|
/* COMPUTE APPROXIMATELY OPTIMAL Q (AND DIVIDE X BY 2**Q) */
|
|
|
|
q = (int) (sqrt((float) MP.t * (float).48 * rlb) + (float) x[2] *
|
|
(float)1.44 * rlb) ;
|
|
|
|
/* HALVE Q TIMES */
|
|
|
|
if (q <= 0) goto L60 ;
|
|
ib = MP.b << 2 ;
|
|
ic = 1 ;
|
|
i__1 = q ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
ic <<= 1 ;
|
|
if (ic < ib && ic != MP.b && i < q) continue ;
|
|
mpdivi(&MP.r[i2 - 1], &ic, &MP.r[i2 - 1]) ;
|
|
ic = 1 ;
|
|
}
|
|
|
|
L60:
|
|
if (MP.r[i2 - 1] == 0) goto L10 ;
|
|
mpstr(&MP.r[i2 - 1], &y[1]) ;
|
|
mpstr(&MP.r[i2 - 1], &MP.r[i3 - 1]) ;
|
|
i = 1 ;
|
|
ts = MP.t ;
|
|
|
|
/* SUM SERIES, REDUCING T WHERE POSSIBLE */
|
|
|
|
L70:
|
|
MP.t = ts + 2 + MP.r[i3] - y[2] ;
|
|
if (MP.t <= 2) goto L80 ;
|
|
|
|
MP.t = min(MP.t,ts) ;
|
|
mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
++i ;
|
|
mpdivi(&MP.r[i3 - 1], &i, &MP.r[i3 - 1]) ;
|
|
MP.t = ts ;
|
|
mpadd2(&MP.r[i3 - 1], &y[1], &y[1], &y[1], &c__0) ;
|
|
if (MP.r[i3 - 1] != 0) goto L70 ;
|
|
|
|
L80:
|
|
MP.t = ts ;
|
|
if (q <= 0) return ;
|
|
|
|
/* APPLY (X+1)**2 - 1 = X(2 + X) FOR Q ITERATIONS */
|
|
|
|
i__1 = q ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
mpaddi(&y[1], &c__2, &MP.r[i2 - 1]) ;
|
|
mpmul(&MP.r[i2 - 1], &y[1], &y[1]) ;
|
|
}
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpext(int *i, int *j, int *x)
|
|
{
|
|
static int q, s ;
|
|
|
|
/* ROUTINE CALLED BY MPDIV AND MPSQRT TO ENSURE THAT
|
|
* RESULTS ARE REPRESENTED EXACTLY IN T-2 DIGITS IF THEY
|
|
* CAN BE. X IS AN MP NUMBER, I AND J ARE INTEGERS.
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
if (x[1] == 0 || MP.t <= 2 || *i == 0) return ;
|
|
|
|
/* COMPUTE MAXIMUM POSSIBLE ERROR IN THE LAST PLACE */
|
|
|
|
q = (*j + 1) / *i + 1 ;
|
|
s = MP.b * x[MP.t + 1] + x[MP.t + 2] ;
|
|
if (s > q) goto L10 ;
|
|
|
|
/* SET LAST TWO DIGITS TO ZERO */
|
|
|
|
x[MP.t + 1] = 0 ;
|
|
x[MP.t + 2] = 0 ;
|
|
return ;
|
|
|
|
L10:
|
|
if (s + q < MP.b * MP.b) return ;
|
|
|
|
/* ROUND UP HERE */
|
|
|
|
x[MP.t + 1] = MP.b - 1 ;
|
|
x[MP.t + 2] = MP.b ;
|
|
|
|
/* NORMALIZE X (LAST DIGIT B IS OK IN MPMULI) */
|
|
|
|
mpmuli(&x[1], &c__1, &x[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpgcd(int *k, int *l)
|
|
{
|
|
static int i, j, is, js ;
|
|
|
|
/* RETURNS K = K/GCD AND L = L/GCD, WHERE GCD IS THE
|
|
* GREATEST COMMON DIVISOR OF K AND L.
|
|
* SAVE INPUT PARAMETERS IN LOCAL VARIABLES
|
|
*/
|
|
|
|
i = *k ;
|
|
j = *l ;
|
|
is = C_abs(i) ;
|
|
js = C_abs(j) ;
|
|
if (js == 0) goto L30 ;
|
|
|
|
/* EUCLIDEAN ALGORITHM LOOP */
|
|
|
|
L10:
|
|
is %= js ;
|
|
if (is == 0) goto L20 ;
|
|
js %= is ;
|
|
if (js != 0) goto L10 ;
|
|
js = is ;
|
|
|
|
/* HERE JS IS THE GCD OF I AND J */
|
|
|
|
L20:
|
|
*k = i / js ;
|
|
*l = j / js ;
|
|
return ;
|
|
|
|
/* IF J = 0 RETURN (1, 0) UNLESS I = 0, THEN (0, 0) */
|
|
|
|
L30:
|
|
*k = 1 ;
|
|
if (is == 0) *k = 0 ;
|
|
*l = 0 ;
|
|
return ;
|
|
}
|
|
|
|
|
|
int
|
|
mpge(int *x, int *y)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* RETURNS LOGICAL VALUE OF (X .GE. Y) FOR MP X AND Y. */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
ret_val = mpcomp(&x[1], &y[1]) >= 0 ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
int
|
|
mpgt(int *x, int *y)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* RETURNS LOGICAL VALUE OF (X .GT. Y) FOR MP X AND Y. */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
ret_val = mpcomp(&x[1], &y[1]) > 0 ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
int
|
|
mple(int *x, int *y)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* RETURNS LOGICAL VALUE OF (X .LE. Y) FOR MP X AND Y. */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
ret_val = mpcomp(&x[1], &y[1]) <= 0 ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
void
|
|
mpln(int *x, int *y)
|
|
{
|
|
float r__1 ;
|
|
|
|
static int e, k, i2, i3 ;
|
|
static float rx, rlx ;
|
|
|
|
/* RETURNS Y = LN(X), FOR MP X AND Y, USING MPLNS.
|
|
* RESTRICTION - INTEGER PART OF LN(X) MUST BE REPRESENTABLE
|
|
* AS A SINGLE-PRECISION INTEGER. TIME IS O(SQRT(T).M(T)).
|
|
* FOR SMALL INTEGER X, MPLNI IS FASTER.
|
|
* ASYMPTOTICALLY FASTER METHODS EXIST (EG THE GAUSS-SALAMIN
|
|
* METHOD, SEE MPLNGS), BUT ARE NOT USEFUL UNLESS T IS LARGE.
|
|
* SEE COMMENTS TO MPATAN, MPEXP1 AND MPPIGL.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 6T+14.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__6, &c__14) ;
|
|
i2 = (MP.t << 2) + 11 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
|
|
/* CHECK THAT X IS POSITIVE */
|
|
if (x[1] > 0) goto L20 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_LNA]) ;
|
|
|
|
mperr() ;
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* MOVE X TO LOCAL STORAGE */
|
|
|
|
L20:
|
|
mpstr(&x[1], &MP.r[i2 - 1]) ;
|
|
y[1] = 0 ;
|
|
k = 0 ;
|
|
|
|
/* LOOP TO GET APPROXIMATE LN(X) USING SINGLE-PRECISION */
|
|
|
|
L30:
|
|
mpaddi(&MP.r[i2 - 1], &c_n1, &MP.r[i3 - 1]) ;
|
|
|
|
/* IF POSSIBLE GO TO CALL MPLNS */
|
|
|
|
if (MP.r[i3 - 1] == 0 || MP.r[i3] + 1 <= 0) goto L50 ;
|
|
|
|
/* REMOVE EXPONENT TO AVOID FLOATING-POINT OVERFLOW */
|
|
|
|
e = MP.r[i2] ;
|
|
MP.r[i2] = 0 ;
|
|
mpcmr(&MP.r[i2 - 1], &rx) ;
|
|
|
|
/* RESTORE EXPONENT AND COMPUTE SINGLE-PRECISION LOG */
|
|
|
|
MP.r[i2] = e ;
|
|
rlx = log(rx) + (float) e * log((float) MP.b) ;
|
|
r__1 = -(double)rlx ;
|
|
mpcrm(&r__1, &MP.r[i3 - 1]) ;
|
|
|
|
/* UPDATE Y AND COMPUTE ACCURATE EXP OF APPROXIMATE LOG */
|
|
|
|
mpsub(&y[1], &MP.r[i3 - 1], &y[1]) ;
|
|
mpexp(&MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
|
|
/* COMPUTE RESIDUAL WHOSE LOG IS STILL TO BE FOUND */
|
|
|
|
mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i2 - 1]) ;
|
|
|
|
/* MAKE SURE NOT LOOPING INDEFINITELY */
|
|
++k ;
|
|
if (k < 10) goto L30 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_LNB]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
|
|
/* COMPUTE FINAL CORRECTION ACCURATELY USING MPLNS */
|
|
|
|
L50:
|
|
mplns(&MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
mpadd(&y[1], &MP.r[i3 - 1], &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mplns(int *x, int *y)
|
|
{
|
|
int i__1, i__2 ;
|
|
|
|
static int i2, i3, i4, ts, it0, ts2, ts3 ;
|
|
|
|
/* RETURNS MP Y = LN(1+X) IF X IS AN MP NUMBER SATISFYING THE
|
|
* CONDITION ABS(X) .LT. 1/B, ERROR OTHERWISE.
|
|
* USES NEWTONS METHOD TO SOLVE THE EQUATION
|
|
* EXP1(-Y) = X, THEN REVERSES SIGN OF Y.
|
|
* (HERE EXP1(Y) = EXP(Y) - 1 IS COMPUTED USING MPEXP1).
|
|
* TIME IS O(SQRT(T).M(T)) AS FOR MPEXP1, SPACE = 5T+12.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__5, &c__12) ;
|
|
i2 = (MP.t << 1) + 7 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
i4 = i3 + MP.t + 2 ;
|
|
|
|
/* CHECK FOR X = 0 EXACTLY */
|
|
|
|
if (x[1] != 0) goto L10 ;
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* CHECK THAT ABS(X) .LT. 1/B */
|
|
|
|
L10:
|
|
if (x[2] + 1 <= 0) goto L30 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_LNSA]) ;
|
|
|
|
mperr() ;
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* SAVE T AND GET STARTING APPROXIMATION TO -LN(1+X) */
|
|
|
|
L30:
|
|
ts = MP.t ;
|
|
mpstr(&x[1], &MP.r[i3 - 1]) ;
|
|
mpdivi(&x[1], &c__4, &MP.r[i2 - 1]) ;
|
|
mpaddq(&MP.r[i2 - 1], &c_n1, &c__3, &MP.r[i2 - 1]) ;
|
|
mpmul(&x[1], &MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
mpaddq(&MP.r[i2 - 1], &c__1, &c__2, &MP.r[i2 - 1]) ;
|
|
mpmul(&x[1], &MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
mpaddi(&MP.r[i2 - 1], &c_n1, &MP.r[i2 - 1]) ;
|
|
mpmul(&x[1], &MP.r[i2 - 1], &y[1]) ;
|
|
|
|
/* START NEWTON ITERATION USING SMALL T, LATER INCREASE */
|
|
|
|
/* Computing MAX */
|
|
|
|
i__1 = 5, i__2 = 13 - (MP.b << 1) ;
|
|
MP.t = max(i__1,i__2) ;
|
|
if (MP.t > ts) goto L80 ;
|
|
|
|
it0 = (MP.t + 5) / 2 ;
|
|
|
|
L40:
|
|
mpexp1(&y[1], &MP.r[i4 - 1]) ;
|
|
mpmul(&MP.r[i3 - 1], &MP.r[i4 - 1], &MP.r[i2 - 1]) ;
|
|
mpadd(&MP.r[i4 - 1], &MP.r[i2 - 1], &MP.r[i4 - 1]) ;
|
|
mpadd(&MP.r[i3 - 1], &MP.r[i4 - 1], &MP.r[i4 - 1]) ;
|
|
mpsub(&y[1], &MP.r[i4 - 1], &y[1]) ;
|
|
if (MP.t >= ts) goto L60 ;
|
|
|
|
/* FOLLOWING LOOP COMPUTES NEXT VALUE OF T TO USE.
|
|
* BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE,
|
|
* WE CAN ALMOST DOUBLE T EACH TIME.
|
|
*/
|
|
|
|
ts3 = MP.t ;
|
|
MP.t = ts ;
|
|
|
|
L50:
|
|
ts2 = MP.t ;
|
|
MP.t = (MP.t + it0) / 2 ;
|
|
if (MP.t > ts3) goto L50 ;
|
|
|
|
MP.t = ts2 ;
|
|
goto L40 ;
|
|
|
|
/* CHECK THAT NEWTON ITERATION WAS CONVERGING AS EXPECTED */
|
|
|
|
L60:
|
|
if (MP.r[i4 - 1] == 0 || MP.r[i4] << 1 <= it0 - MP.t)
|
|
goto L80 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_LNSB]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_LNSC]) ;
|
|
}
|
|
|
|
mperr() ;
|
|
|
|
/* REVERSE SIGN OF Y AND RETURN */
|
|
|
|
L80:
|
|
y[1] = -y[1] ;
|
|
MP.t = ts ;
|
|
return ;
|
|
}
|
|
|
|
|
|
int
|
|
mplt(int *x, int *y)
|
|
{
|
|
int ret_val ;
|
|
|
|
/* RETURNS LOGICAL VALUE OF (X .LT. Y) FOR MP X AND Y. */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
ret_val = mpcomp(&x[1], &y[1]) < 0 ;
|
|
return(ret_val) ;
|
|
}
|
|
|
|
|
|
void
|
|
mpmaxr(int *x)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, it ;
|
|
|
|
/* SETS X TO THE LARGEST POSSIBLE POSITIVE MP NUMBER
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
it = MP.b - 1 ;
|
|
|
|
/* SET FRACTION DIGITS TO B-1 */
|
|
|
|
i__1 = MP.t ;
|
|
for (i = 1; i <= i__1; ++i) x[i + 2] = it ;
|
|
|
|
/* SET SIGN AND EXPONENT */
|
|
|
|
x[1] = 1 ;
|
|
x[2] = MP.m ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpmlp(int *u, int *v, int *w, int *j)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i ;
|
|
|
|
/* PERFORMS INNER MULTIPLICATION LOOP FOR MPMUL
|
|
* NOTE THAT CARRIES ARE NOT PROPAGATED IN INNER LOOP,
|
|
* WHICH SAVES TIME AT THE EXPENSE OF SPACE.
|
|
*/
|
|
|
|
--v ; /* Parameter adjustments */
|
|
--u ;
|
|
|
|
i__1 = *j ;
|
|
for (i = 1; i <= i__1; ++i) u[i] += *w * v[i] ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpmul(int *x, int *y, int *z)
|
|
{
|
|
int i__1, i__2, i__3, i__4 ;
|
|
|
|
static int c, i, j, i2, j1, re, ri, xi, rs, i2p ;
|
|
|
|
/* MULTIPLIES X AND Y, RETURNING RESULT IN Z, FOR MP X, Y AND Z.
|
|
* THE SIMPLE O(T**2) ALGORITHM IS USED, WITH
|
|
* FOUR GUARD DIGITS AND R*-ROUNDING.
|
|
* ADVANTAGE IS TAKEN OF ZERO DIGITS IN X, BUT NOT IN Y.
|
|
* ASYMPTOTICALLY FASTER ALGORITHMS ARE KNOWN (SEE KNUTH,
|
|
* VOL. 2), BUT ARE DIFFICULT TO IMPLEMENT IN FORTRAN IN AN
|
|
* EFFICIENT AND MACHINE-INDEPENDENT MANNER.
|
|
* IN COMMENTS TO OTHER MP ROUTINES, M(T) IS THE TIME
|
|
* TO PERFORM T-DIGIT MP MULTIPLICATION. THUS
|
|
* M(T) = O(T**2) WITH THE PRESENT VERSION OF MPMUL,
|
|
* BUT M(T) = O(T.LOG(T).LOG(LOG(T))) IS THEORETICALLY POSSIBLE.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--y ;
|
|
--x ;
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
i2 = MP.t + 4 ;
|
|
i2p = i2 + 1 ;
|
|
|
|
/* FORM SIGN OF PRODUCT */
|
|
|
|
rs = x[1] * y[1] ;
|
|
if (rs != 0) goto L10 ;
|
|
|
|
/* SET RESULT TO ZERO */
|
|
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* FORM EXPONENT OF PRODUCT */
|
|
|
|
L10:
|
|
re = x[2] + y[2] ;
|
|
|
|
/* CLEAR ACCUMULATOR */
|
|
|
|
i__1 = i2 ;
|
|
for (i = 1; i <= i__1; ++i) MP.r[i - 1] = 0 ;
|
|
|
|
/* PERFORM MULTIPLICATION */
|
|
|
|
c = 8 ;
|
|
i__1 = MP.t ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
xi = x[i + 2] ;
|
|
|
|
/* FOR SPEED, PUT THE NUMBER WITH MANY ZEROS FIRST */
|
|
|
|
if (xi == 0) continue ;
|
|
|
|
/* Computing MIN */
|
|
|
|
i__3 = MP.t, i__4 = i2 - i ;
|
|
i__2 = min(i__3,i__4) ;
|
|
mpmlp(&MP.r[i], &y[3], &xi, &i__2) ;
|
|
--c ;
|
|
if (c > 0) continue ;
|
|
|
|
/* CHECK FOR LEGAL BASE B DIGIT */
|
|
|
|
if (xi < 0 || xi >= MP.b) goto L90 ;
|
|
|
|
/* PROPAGATE CARRIES AT END AND EVERY EIGHTH TIME,
|
|
* FASTER THAN DOING IT EVERY TIME.
|
|
*/
|
|
|
|
i__2 = i2 ;
|
|
for (j = 1; j <= i__2; ++j)
|
|
{
|
|
j1 = i2p - j ;
|
|
ri = MP.r[j1 - 1] + c ;
|
|
if (ri < 0) goto L70 ;
|
|
c = ri / MP.b ;
|
|
MP.r[j1 - 1] = ri - MP.b * c ;
|
|
}
|
|
if (c != 0) goto L90 ;
|
|
c = 8 ;
|
|
}
|
|
|
|
if (c == 8) goto L60 ;
|
|
if (xi < 0 || xi >= MP.b) goto L90 ;
|
|
c = 0 ;
|
|
i__1 = i2 ;
|
|
for (j = 1; j <= i__1; ++j)
|
|
{
|
|
j1 = i2p - j ;
|
|
ri = MP.r[j1 - 1] + c ;
|
|
if (ri < 0) goto L70 ;
|
|
c = ri / MP.b ;
|
|
MP.r[j1 - 1] = ri - MP.b * c ;
|
|
}
|
|
if (c != 0) goto L90 ;
|
|
|
|
/* NORMALIZE AND ROUND RESULT */
|
|
|
|
L60:
|
|
mpnzr(&rs, &re, &z[1], &c__0) ;
|
|
return ;
|
|
|
|
L70:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_MULA]) ;
|
|
|
|
goto L110 ;
|
|
|
|
L90:
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_MULB]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_MULC]) ;
|
|
}
|
|
|
|
L110:
|
|
mperr() ;
|
|
z[1] = 0 ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpmul2(int *x, int *iy, int *z, int *trunc)
|
|
{
|
|
int i__1, i__2 ;
|
|
|
|
static int c, i, j, c1, c2, j1, j2 ;
|
|
static int t1, t3, t4, ij, re, ri, is, ix, rs ;
|
|
|
|
/* MULTIPLIES MP X BY SINGLE-PRECISION INTEGER IY GIVING MP Z.
|
|
* MULTIPLICATION BY 1 MAY BE USED TO NORMALIZE A NUMBER
|
|
* EVEN IF SOME DIGITS ARE GREATER THAN B-1.
|
|
* RESULT IS ROUNDED IF TRUNC.EQ.0, OTHERWISE TRUNCATED.
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
rs = x[1] ;
|
|
if (rs == 0) goto L10 ;
|
|
j = *iy ;
|
|
if (j < 0) goto L20 ;
|
|
else if (j == 0) goto L10 ;
|
|
else goto L50 ;
|
|
|
|
/* RESULT ZERO */
|
|
|
|
L10:
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
L20:
|
|
j = -j ;
|
|
rs = -rs ;
|
|
|
|
/* CHECK FOR MULTIPLICATION BY B */
|
|
|
|
if (j != MP.b) goto L50 ;
|
|
if (x[2] < MP.m) goto L40 ;
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_MUL2A]) ;
|
|
|
|
mpovfl(&z[1]) ;
|
|
return ;
|
|
|
|
L40:
|
|
mpstr(&x[1], &z[1]) ;
|
|
z[1] = rs ;
|
|
z[2] = x[2] + 1 ;
|
|
return ;
|
|
|
|
/* SET EXPONENT TO EXPONENT(X) + 4 */
|
|
|
|
L50:
|
|
re = x[2] + 4 ;
|
|
|
|
/* FORM PRODUCT IN ACCUMULATOR */
|
|
|
|
c = 0 ;
|
|
t1 = MP.t + 1 ;
|
|
t3 = MP.t + 3 ;
|
|
t4 = MP.t + 4 ;
|
|
|
|
/* IF J*B NOT REPRESENTABLE AS AN INTEGER WE HAVE TO SIMULATE
|
|
* DOUBLE-PRECISION MULTIPLICATION.
|
|
*/
|
|
|
|
/* Computing MAX */
|
|
|
|
i__1 = MP.b << 3, i__2 = 32767 / MP.b ;
|
|
if (j >= max(i__1,i__2)) goto L110 ;
|
|
|
|
i__1 = MP.t ;
|
|
for (ij = 1; ij <= i__1; ++ij)
|
|
{
|
|
i = t1 - ij ;
|
|
ri = j * x[i + 2] + c ;
|
|
c = ri / MP.b ;
|
|
MP.r[i + 3] = ri - MP.b * c ;
|
|
}
|
|
|
|
/* CHECK FOR INTEGER OVERFLOW */
|
|
|
|
if (ri < 0) goto L130 ;
|
|
|
|
/* HAVE TO TREAT FIRST FOUR WORDS OF R SEPARATELY */
|
|
|
|
for (ij = 1; ij <= 4; ++ij)
|
|
{
|
|
i = 5 - ij ;
|
|
ri = c ;
|
|
c = ri / MP.b ;
|
|
MP.r[i - 1] = ri - MP.b * c ;
|
|
}
|
|
if (c == 0) goto L100 ;
|
|
|
|
/* HAVE TO SHIFT RIGHT HERE AS CARRY OFF END */
|
|
|
|
L80:
|
|
i__1 = t3 ;
|
|
for (ij = 1; ij <= i__1; ++ij)
|
|
{
|
|
i = t4 - ij ;
|
|
MP.r[i] = MP.r[i - 1] ;
|
|
}
|
|
ri = c ;
|
|
c = ri / MP.b ;
|
|
MP.r[0] = ri - MP.b * c ;
|
|
++re ;
|
|
if (c < 0) goto L130 ;
|
|
else if (c == 0) goto L100 ;
|
|
else goto L80 ;
|
|
|
|
/* NORMALIZE AND ROUND OR TRUNCATE RESULT */
|
|
|
|
L100:
|
|
mpnzr(&rs, &re, &z[1], trunc) ;
|
|
return ;
|
|
|
|
/* HERE J IS TOO LARGE FOR SINGLE-PRECISION MULTIPLICATION */
|
|
|
|
L110:
|
|
j1 = j / MP.b ;
|
|
j2 = j - j1 * MP.b ;
|
|
|
|
/* FORM PRODUCT */
|
|
|
|
i__1 = t4 ;
|
|
for (ij = 1; ij <= i__1; ++ij)
|
|
{
|
|
c1 = c / MP.b ;
|
|
c2 = c - MP.b * c1 ;
|
|
i = t1 - ij ;
|
|
ix = 0 ;
|
|
if (i > 0) ix = x[i + 2] ;
|
|
ri = j2 * ix + c2 ;
|
|
is = ri / MP.b ;
|
|
c = j1 * ix + c1 + is ;
|
|
MP.r[i + 3] = ri - MP.b * is ;
|
|
}
|
|
|
|
if (c < 0) goto L130 ;
|
|
else if (c == 0) goto L100 ;
|
|
else goto L80 ;
|
|
|
|
/* CAN ONLY GET HERE IF INTEGER OVERFLOW OCCURRED */
|
|
|
|
L130:
|
|
mpchk(&c__1, &c__4) ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_MUL2B]) ;
|
|
|
|
mperr() ;
|
|
goto L10 ;
|
|
}
|
|
|
|
|
|
void
|
|
mpmuli(int *x, int *iy, int *z)
|
|
{
|
|
|
|
/* MULTIPLIES MP X BY SINGLE-PRECISION INTEGER IY GIVING MP Z.
|
|
* THIS IS FASTER THAN USING MPMUL. RESULT IS ROUNDED.
|
|
* MULTIPLICATION BY 1 MAY BE USED TO NORMALIZE A NUMBER
|
|
* EVEN IF THE LAST DIGIT IS B.
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpmul2(&x[1], iy, &z[1], &c__0) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpmulq(int *x, int *i, int *j, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int is, js ;
|
|
|
|
/* MULTIPLIES MP X BY I/J, GIVING MP Y */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
if (*j != 0) goto L20 ;
|
|
mpchk(&c__1, &c__4) ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_MULQ]) ;
|
|
|
|
mperr() ;
|
|
goto L30 ;
|
|
|
|
L20:
|
|
if (*i != 0) goto L40 ;
|
|
|
|
L30:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* REDUCE TO LOWEST TERMS */
|
|
|
|
L40:
|
|
is = *i ;
|
|
js = *j ;
|
|
mpgcd(&is, &js) ;
|
|
if (C_abs(is) == 1) goto L50 ;
|
|
|
|
mpdivi(&x[1], &js, &y[1]) ;
|
|
mpmul2(&y[1], &is, &y[1], &c__0) ;
|
|
return ;
|
|
|
|
/* HERE IS = +-1 */
|
|
|
|
L50:
|
|
i__1 = is * js ;
|
|
mpdivi(&x[1], &i__1, &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpneg(int *x, int *y)
|
|
{
|
|
|
|
/* SETS Y = -X FOR MP NUMBERS X AND Y */
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpstr(&x[1], &y[1]) ;
|
|
y[1] = -y[1] ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpnzr(int *rs, int *re, int *z, int *trunc)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, j, k, b2, i2, is, it, i2m, i2p ;
|
|
|
|
/* ASSUMES LONG (I.E. (T+4)-DIGIT) FRACTION IN
|
|
* R, SIGN = RS, EXPONENT = RE. NORMALIZES,
|
|
* AND RETURNS MP RESULT IN Z. INTEGER ARGUMENTS RS AND RE
|
|
* ARE NOT PRESERVED. R*-ROUNDING IS USED IF TRUNC.EQ.0
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
|
|
i2 = MP.t + 4 ;
|
|
if (*rs != 0) goto L20 ;
|
|
|
|
/* STORE ZERO IN Z */
|
|
|
|
L10:
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* CHECK THAT SIGN = +-1 */
|
|
|
|
L20:
|
|
if (C_abs(*rs) <= 1) goto L40 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_NZRA]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_NZRB]) ;
|
|
}
|
|
|
|
mperr() ;
|
|
goto L10 ;
|
|
|
|
/* LOOK FOR FIRST NONZERO DIGIT */
|
|
|
|
L40:
|
|
i__1 = i2 ;
|
|
for (i = 1; i <= i__1; ++i)
|
|
{
|
|
is = i - 1 ;
|
|
if (MP.r[i - 1] > 0) goto L60 ;
|
|
}
|
|
|
|
/* FRACTION ZERO */
|
|
|
|
goto L10 ;
|
|
|
|
L60:
|
|
if (is == 0) goto L90 ;
|
|
|
|
/* NORMALIZE */
|
|
|
|
*re -= is ;
|
|
i2m = i2 - is ;
|
|
i__1 = i2m ;
|
|
for (j = 1; j <= i__1; ++j)
|
|
{
|
|
k = j + is ;
|
|
MP.r[j - 1] = MP.r[k - 1] ;
|
|
}
|
|
i2p = i2m + 1 ;
|
|
i__1 = i2 ;
|
|
for (j = i2p; j <= i__1; ++j) MP.r[j - 1] = 0 ;
|
|
|
|
/* CHECK TO SEE IF TRUNCATION IS DESIRED */
|
|
|
|
L90:
|
|
if (*trunc != 0) goto L150 ;
|
|
|
|
/* SEE IF ROUNDING NECESSARY
|
|
* TREAT EVEN AND ODD BASES DIFFERENTLY
|
|
*/
|
|
|
|
b2 = MP.b / 2 ;
|
|
if (b2 << 1 != MP.b) goto L130 ;
|
|
|
|
/* B EVEN. ROUND IF R(T+1).GE.B2 UNLESS R(T) ODD AND ALL ZEROS
|
|
* AFTER R(T+2).
|
|
*/
|
|
|
|
if ((i__1 = MP.r[MP.t] - b2) < 0) goto L150 ;
|
|
else if (i__1 == 0) goto L100 ;
|
|
else goto L110 ;
|
|
|
|
L100:
|
|
if (MP.r[MP.t - 1] % 2 == 0) goto L110 ;
|
|
|
|
if (MP.r[MP.t + 1] + MP.r[MP.t + 2] +
|
|
MP.r[MP.t + 3] == 0)
|
|
goto L150 ;
|
|
|
|
/* ROUND */
|
|
|
|
L110:
|
|
i__1 = MP.t ;
|
|
for (j = 1; j <= i__1; ++j)
|
|
{
|
|
i = MP.t + 1 - j ;
|
|
++MP.r[i - 1] ;
|
|
if (MP.r[i - 1] < MP.b) goto L150 ;
|
|
MP.r[i - 1] = 0 ;
|
|
}
|
|
|
|
/* EXCEPTIONAL CASE, ROUNDED UP TO .10000... */
|
|
|
|
++(*re) ;
|
|
MP.r[0] = 1 ;
|
|
goto L150 ;
|
|
|
|
/* ODD BASE, ROUND IF R(T+1)... .GT. 1/2 */
|
|
|
|
L130:
|
|
for (i = 1; i <= 4; ++i)
|
|
{
|
|
it = MP.t + i ;
|
|
if ((i__1 = MP.r[it - 1] - b2) < 0) goto L150 ;
|
|
else if (i__1 == 0) continue ;
|
|
else goto L110 ;
|
|
}
|
|
|
|
/* CHECK FOR OVERFLOW */
|
|
|
|
L150:
|
|
if (*re <= MP.m) goto L170 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_NZRC]) ;
|
|
|
|
mpovfl(&z[1]) ;
|
|
return ;
|
|
|
|
/* CHECK FOR UNDERFLOW */
|
|
|
|
L170:
|
|
if (*re < -MP.m) goto L190 ;
|
|
|
|
/* STORE RESULT IN Z */
|
|
|
|
z[1] = *rs ;
|
|
z[2] = *re ;
|
|
i__1 = MP.t ;
|
|
for (i = 1; i <= i__1; ++i) z[i + 2] = MP.r[i - 1] ;
|
|
return ;
|
|
|
|
/* UNDERFLOW HERE */
|
|
|
|
L190:
|
|
mpunfl(&z[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpovfl(int *x)
|
|
{
|
|
|
|
/* CALLED ON MULTIPLE-PRECISION OVERFLOW, IE WHEN THE
|
|
* EXPONENT OF MP NUMBER X WOULD EXCEED M.
|
|
* AT PRESENT EXECUTION IS TERMINATED WITH AN ERROR MESSAGE
|
|
* AFTER CALLING MPMAXR(X), BUT IT WOULD BE POSSIBLE TO RETURN,
|
|
* POSSIBLY UPDATING A COUNTER AND TERMINATING EXECUTION AFTER
|
|
* A PRESET NUMBER OF OVERFLOWS. ACTION COULD EASILY BE DETERMINED
|
|
* BY A FLAG IN LABELLED COMMON.
|
|
* M MAY HAVE BEEN OVERWRITTEN, SO CHECK B, T, M ETC.
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
|
|
/* SET X TO LARGEST POSSIBLE POSITIVE NUMBER */
|
|
|
|
mpmaxr(&x[1]) ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_OVFL]) ;
|
|
|
|
/* TERMINATE EXECUTION BY CALLING MPERR */
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mppi(int *x)
|
|
{
|
|
float r__1 ;
|
|
|
|
static int i2 ;
|
|
static float rx ;
|
|
|
|
/* SETS MP X = PI TO THE AVAILABLE PRECISION.
|
|
* USES PI/4 = 4.ARCTAN(1/5) - ARCTAN(1/239).
|
|
* TIME IS O(T**2).
|
|
* DIMENSION OF R MUST BE AT LEAST 3T+8
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__3, &c__8) ;
|
|
|
|
/* ALLOW SPACE FOR MPART1 */
|
|
|
|
i2 = (MP.t << 1) + 7 ;
|
|
mpart1(&c__5, &MP.r[i2 - 1]) ;
|
|
mpmuli(&MP.r[i2 - 1], &c__4, &MP.r[i2 - 1]) ;
|
|
mpart1(&c__239, &x[1]) ;
|
|
mpsub(&MP.r[i2 - 1], &x[1], &x[1]) ;
|
|
mpmuli(&x[1], &c__4, &x[1]) ;
|
|
|
|
/* RETURN IF ERROR IS LESS THAN 0.01 */
|
|
|
|
mpcmr(&x[1], &rx) ;
|
|
if ((r__1 = rx - (float)3.1416, dabs(r__1)) < (float) 0.01) return ;
|
|
|
|
/* FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL */
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_PI]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mppwr(int *x, int *n, int *y)
|
|
{
|
|
static int i2, n2, ns ;
|
|
|
|
/* RETURNS Y = X**N, FOR MP X AND Y, INTEGER N, WITH 0**0 = 1.
|
|
* R MUST BE DIMENSIONED AT LEAST 4T+10 IN CALLING PROGRAM
|
|
* (2T+6 IS ENOUGH IF N NONNEGATIVE).
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
i2 = MP.t + 5 ;
|
|
n2 = *n ;
|
|
if (n2 < 0) goto L20 ;
|
|
else if (n2 == 0) goto L10 ;
|
|
else goto L40 ;
|
|
|
|
/* N = 0, RETURN Y = 1. */
|
|
|
|
L10:
|
|
mpcim(&c__1, &y[1]) ;
|
|
return ;
|
|
|
|
/* N .LT. 0 */
|
|
|
|
L20:
|
|
mpchk(&c__4, &c__10) ;
|
|
n2 = -n2 ;
|
|
if (x[1] != 0) goto L60 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_PWRA]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_PWRB]) ;
|
|
}
|
|
|
|
mperr() ;
|
|
goto L50 ;
|
|
|
|
/* N .GT. 0 */
|
|
|
|
L40:
|
|
mpchk(&c__2, &c__6) ;
|
|
if (x[1] != 0) goto L60 ;
|
|
|
|
/* X = 0, N .GT. 0, SO Y = 0 */
|
|
|
|
L50:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* MOVE X */
|
|
|
|
L60:
|
|
mpstr(&x[1], &y[1]) ;
|
|
|
|
/* IF N .LT. 0 FORM RECIPROCAL */
|
|
|
|
if (*n < 0) mprec(&y[1], &y[1]) ;
|
|
mpstr(&y[1], &MP.r[i2 - 1]) ;
|
|
|
|
/* SET PRODUCT TERM TO ONE */
|
|
|
|
mpcim(&c__1, &y[1]) ;
|
|
|
|
/* MAIN LOOP, LOOK AT BITS OF N2 FROM RIGHT */
|
|
|
|
L70:
|
|
ns = n2 ;
|
|
n2 /= 2 ;
|
|
if (n2 << 1 != ns) mpmul(&y[1], &MP.r[i2 - 1], &y[1]) ;
|
|
if (n2 <= 0) return ;
|
|
|
|
mpmul(&MP.r[i2 - 1], &MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
goto L70 ;
|
|
}
|
|
|
|
|
|
void
|
|
mppwr2(int *x, int *y, int *z)
|
|
{
|
|
static int i2 ;
|
|
|
|
/* RETURNS Z = X**Y FOR MP NUMBERS X, Y AND Z, WHERE X IS
|
|
* POSITIVE (X .EQ. 0 ALLOWED IF Y .GT. 0). SLOWER THAN
|
|
* MPPWR AND MPQPWR, SO USE THEM IF POSSIBLE.
|
|
* DIMENSION OF R IN COMMON AT LEAST 7T+16
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--y ;
|
|
--x ;
|
|
|
|
mpchk(&c__7, &c__16) ;
|
|
if (x[1] < 0) goto L10 ;
|
|
else if (x[1] == 0) goto L30 ;
|
|
else goto L70 ;
|
|
|
|
L10:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_PWR2A]) ;
|
|
|
|
goto L50 ;
|
|
|
|
/* HERE X IS ZERO, RETURN ZERO IF Y POSITIVE, OTHERWISE ERROR */
|
|
|
|
L30:
|
|
if (y[1] > 0) goto L60 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_PWR2B]) ;
|
|
|
|
L50:
|
|
mperr() ;
|
|
|
|
/* RETURN ZERO HERE */
|
|
|
|
L60:
|
|
z[1] = 0 ;
|
|
return ;
|
|
|
|
/* USUAL CASE HERE, X POSITIVE
|
|
* USE MPLN AND MPEXP TO COMPUTE POWER
|
|
*/
|
|
|
|
L70:
|
|
i2 = MP.t * 6 + 15 ;
|
|
mpln(&x[1], &MP.r[i2 - 1]) ;
|
|
mpmul(&y[1], &MP.r[i2 - 1], &z[1]) ;
|
|
|
|
/* IF X**Y IS TOO LARGE, MPEXP WILL PRINT ERROR MESSAGE */
|
|
|
|
mpexp(&z[1], &z[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mprec(int *x, int *y)
|
|
{
|
|
|
|
/* Initialized data */
|
|
|
|
static int it[9] = { 0, 8, 6, 5, 4, 4, 4, 4, 4 } ;
|
|
|
|
float r__1 ;
|
|
|
|
static int i2, i3, ex, ts, it0, ts2, ts3 ;
|
|
static float rx ;
|
|
|
|
/* RETURNS Y = 1/X, FOR MP X AND Y.
|
|
* MPROOT (X, -1, Y) HAS THE SAME EFFECT.
|
|
* DIMENSION OF R MUST BE AT LEAST 4*T+10 IN CALLING PROGRAM
|
|
* (BUT Y(1) MAY BE R(3T+9)).
|
|
* NEWTONS METHOD IS USED, SO FINAL ONE OR TWO DIGITS MAY
|
|
* NOT BE CORRECT.
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR */
|
|
|
|
mpchk(&c__4, &c__10) ;
|
|
|
|
/* MPADDI REQUIRES 2T+6 WORDS. */
|
|
|
|
i2 = (MP.t << 1) + 7 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
if (x[1] != 0) goto L20 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_RECA]) ;
|
|
|
|
mperr() ;
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
L20:
|
|
ex = x[2] ;
|
|
|
|
/* TEMPORARILY INCREASE M TO AVOID OVERFLOW */
|
|
|
|
MP.m += 2 ;
|
|
|
|
/* SET EXPONENT TO ZERO SO RX NOT TOO LARGE OR SMALL. */
|
|
|
|
x[2] = 0 ;
|
|
mpcmr(&x[1], &rx) ;
|
|
|
|
/* USE SINGLE-PRECISION RECIPROCAL AS FIRST APPROXIMATION */
|
|
|
|
r__1 = (float)1. / rx ;
|
|
mpcrm(&r__1, &MP.r[i2 - 1]) ;
|
|
|
|
/* RESTORE EXPONENT */
|
|
|
|
x[2] = ex ;
|
|
|
|
/* CORRECT EXPONENT OF FIRST APPROXIMATION */
|
|
|
|
MP.r[i2] -= ex ;
|
|
|
|
/* SAVE T (NUMBER OF DIGITS) */
|
|
|
|
ts = MP.t ;
|
|
|
|
/* START WITH SMALL T TO SAVE TIME. ENSURE THAT B**(T-1) .GE. 100 */
|
|
|
|
MP.t = 3 ;
|
|
if (MP.b < 10) MP.t = it[MP.b - 1] ;
|
|
it0 = (MP.t + 4) / 2 ;
|
|
if (MP.t > ts) goto L70 ;
|
|
|
|
/* MAIN ITERATION LOOP */
|
|
|
|
L30:
|
|
mpmul(&x[1], &MP.r[i2 - 1], &MP.r[i3 - 1]) ;
|
|
mpaddi(&MP.r[i3 - 1], &c_n1, &MP.r[i3 - 1]) ;
|
|
|
|
/* TEMPORARILY REDUCE T */
|
|
|
|
ts3 = MP.t ;
|
|
MP.t = (MP.t + it0) / 2 ;
|
|
mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
|
|
/* RESTORE T */
|
|
|
|
MP.t = ts3 ;
|
|
mpsub(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i2 - 1]) ;
|
|
if (MP.t >= ts) goto L50 ;
|
|
|
|
/* FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE
|
|
* BECAUSE NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
|
|
*/
|
|
|
|
MP.t = ts ;
|
|
|
|
L40:
|
|
ts2 = MP.t ;
|
|
MP.t = (MP.t + it0) / 2 ;
|
|
if (MP.t > ts3) goto L40 ;
|
|
|
|
MP.t = min(ts,ts2) ;
|
|
goto L30 ;
|
|
|
|
/* RETURN IF NEWTON ITERATION WAS CONVERGING */
|
|
|
|
L50:
|
|
if (MP.r[i3 - 1] == 0 || (MP.r[i2] - MP.r[i3]) << 1 >=
|
|
MP.t - it0)
|
|
goto L70 ;
|
|
|
|
/* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
|
|
* OR THAT THE STARTING APPROXIMATION IS NOT ACCURATE ENOUGH.
|
|
*/
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_RECB]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_RECC]) ;
|
|
}
|
|
|
|
mperr() ;
|
|
|
|
/* MOVE RESULT TO Y AND RETURN AFTER RESTORING T */
|
|
|
|
L70:
|
|
MP.t = ts ;
|
|
mpstr(&MP.r[i2 - 1], &y[1]) ;
|
|
|
|
/* RESTORE M AND CHECK FOR OVERFLOW (UNDERFLOW IMPOSSIBLE) */
|
|
|
|
MP.m += -2 ;
|
|
if (y[2] <= MP.m) return ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_RECD]) ;
|
|
|
|
mpovfl(&y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mproot(int *x, int *n, int *y)
|
|
{
|
|
|
|
/* Initialized data */
|
|
|
|
static int it[9] = { 0, 8, 6, 5, 4, 4, 4, 4, 4 } ;
|
|
|
|
int i__1 ;
|
|
float r__1 ;
|
|
|
|
static int i2, i3, ex, np, ts, it0, ts2, ts3, xes ;
|
|
static float rx ;
|
|
|
|
/* RETURNS Y = X**(1/N) FOR INTEGER N, ABS(N) .LE. MAX (B, 64).
|
|
* AND MP NUMBERS X AND Y,
|
|
* USING NEWTONS METHOD WITHOUT DIVISIONS. SPACE = 4T+10
|
|
* (BUT Y(1) MAY BE R(3T+9))
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR */
|
|
|
|
mpchk(&c__4, &c__10) ;
|
|
if (*n != 1) goto L10 ;
|
|
mpstr(&x[1], &y[1]) ;
|
|
return ;
|
|
|
|
L10:
|
|
i2 = (MP.t << 1) + 7 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
if (*n != 0) goto L30 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ROOTA]) ;
|
|
|
|
goto L50 ;
|
|
|
|
L30:
|
|
np = C_abs(*n) ;
|
|
|
|
/* LOSS OF ACCURACY IF NP LARGE, SO ONLY ALLOW NP .LE. MAX (B, 64) */
|
|
|
|
if (np <= max(MP.b,64)) goto L60 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ROOTB]) ;
|
|
|
|
L50:
|
|
mperr() ;
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* LOOK AT SIGN OF X */
|
|
|
|
L60:
|
|
if (x[1] < 0) goto L90 ;
|
|
else if (x[1] == 0) goto L70 ;
|
|
else goto L110 ;
|
|
|
|
/* X = 0 HERE, RETURN 0 IF N POSITIVE, ERROR IF NEGATIVE */
|
|
|
|
L70:
|
|
y[1] = 0 ;
|
|
if (*n > 0) return ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ROOTC]) ;
|
|
|
|
goto L50 ;
|
|
|
|
/* X NEGATIVE HERE, SO ERROR IF N IS EVEN */
|
|
|
|
L90:
|
|
if (np % 2 != 0) goto L110 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ROOTD]) ;
|
|
|
|
goto L50 ;
|
|
|
|
/* GET EXPONENT AND DIVIDE BY NP */
|
|
|
|
L110:
|
|
xes = x[2] ;
|
|
ex = xes / np ;
|
|
|
|
/* REDUCE EXPONENT SO RX NOT TOO LARGE OR SMALL. */
|
|
|
|
x[2] = 0 ;
|
|
mpcmr(&x[1], &rx) ;
|
|
|
|
/* USE SINGLE-PRECISION ROOT FOR FIRST APPROXIMATION */
|
|
|
|
r__1 = exp(((float) (np * ex - xes) * log((float) MP.b) - log((dabs(
|
|
rx)))) / (float) np) ;
|
|
mpcrm(&r__1, &MP.r[i2 - 1]) ;
|
|
|
|
/* SIGN OF APPROXIMATION SAME AS THAT OF X */
|
|
|
|
MP.r[i2 - 1] = x[1] ;
|
|
|
|
/* RESTORE EXPONENT */
|
|
|
|
x[2] = xes ;
|
|
|
|
/* CORRECT EXPONENT OF FIRST APPROXIMATION */
|
|
|
|
MP.r[i2] -= ex ;
|
|
|
|
/* SAVE T (NUMBER OF DIGITS) */
|
|
|
|
ts = MP.t ;
|
|
|
|
/* START WITH SMALL T TO SAVE TIME */
|
|
|
|
MP.t = 3 ;
|
|
|
|
/* ENSURE THAT B**(T-1) .GE. 100 */
|
|
|
|
if (MP.b < 10) MP.t = it[MP.b - 1] ;
|
|
if (MP.t > ts) goto L160 ;
|
|
|
|
/* IT0 IS A NECESSARY SAFETY FACTOR */
|
|
|
|
it0 = (MP.t + 4) / 2 ;
|
|
|
|
/* MAIN ITERATION LOOP */
|
|
|
|
L120:
|
|
mppwr(&MP.r[i2 - 1], &np, &MP.r[i3 - 1]) ;
|
|
mpmul(&x[1], &MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
mpaddi(&MP.r[i3 - 1], &c_n1, &MP.r[i3 - 1]) ;
|
|
|
|
/* TEMPORARILY REDUCE T */
|
|
|
|
ts3 = MP.t ;
|
|
MP.t = (MP.t + it0) / 2 ;
|
|
mpmul(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
mpdivi(&MP.r[i3 - 1], &np, &MP.r[i3 - 1]) ;
|
|
|
|
/* RESTORE T */
|
|
|
|
MP.t = ts3 ;
|
|
mpsub(&MP.r[i2 - 1], &MP.r[i3 - 1], &MP.r[i2 - 1]) ;
|
|
|
|
/* FOLLOWING LOOP ALMOST DOUBLES T (POSSIBLE BECAUSE
|
|
* NEWTONS METHOD HAS 2ND ORDER CONVERGENCE).
|
|
*/
|
|
|
|
if (MP.t >= ts) goto L140 ;
|
|
MP.t = ts ;
|
|
|
|
L130:
|
|
ts2 = MP.t ;
|
|
MP.t = (MP.t + it0) / 2 ;
|
|
if (MP.t > ts3) goto L130 ;
|
|
|
|
MP.t = min(ts,ts2) ;
|
|
goto L120 ;
|
|
|
|
/* NOW R(I2) IS X**(-1/NP)
|
|
* CHECK THAT NEWTON ITERATION WAS CONVERGING
|
|
*/
|
|
|
|
L140:
|
|
if (MP.r[i3 - 1] == 0 || (MP.r[i2] - MP.r[i3]) << 1 >=
|
|
MP.t - it0)
|
|
goto L160 ;
|
|
|
|
/* THE FOLLOWING MESSAGE MAY INDICATE THAT B**(T-1) IS TOO SMALL,
|
|
* OR THAT THE INITIAL APPROXIMATION OBTAINED USING ALOG AND EXP
|
|
* IS NOT ACCURATE ENOUGH.
|
|
*/
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ROOTE]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_ROOTF]) ;
|
|
}
|
|
|
|
mperr() ;
|
|
|
|
/* RESTORE T */
|
|
|
|
L160:
|
|
MP.t = ts ;
|
|
if (*n < 0) goto L170 ;
|
|
|
|
i__1 = *n - 1 ;
|
|
mppwr(&MP.r[i2 - 1], &i__1, &MP.r[i2 - 1]) ;
|
|
mpmul(&x[1], &MP.r[i2 - 1], &y[1]) ;
|
|
return ;
|
|
|
|
L170:
|
|
mpstr(&MP.r[i2 - 1], &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpset(int *idecpl, int *itmax2, int *maxdr)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, k, w, i2, w2, wn ;
|
|
|
|
/* SETS BASE (B) AND NUMBER OF DIGITS (T) TO GIVE THE
|
|
* EQUIVALENT OF AT LEAST IDECPL DECIMAL DIGITS.
|
|
* IDECPL SHOULD BE POSITIVE.
|
|
* ITMAX2 IS THE DIMENSION OF ARRAYS USED FOR MP NUMBERS,
|
|
* SO AN ERROR OCCURS IF THE COMPUTED T EXCEEDS ITMAX2 - 2.
|
|
* MPSET ALSO SETS
|
|
* MXR = MAXDR (DIMENSION OF R IN COMMON, .GE. T+4), AND
|
|
* M = (W-1)/4 (MAXIMUM ALLOWABLE EXPONENT),
|
|
* WHERE W IS THE LARGEST INTEGER OF THE FORM 2**K-1 WHICH IS
|
|
* REPRESENTABLE IN THE MACHINE, K .LE. 47
|
|
* THE COMPUTED B AND T SATISFY THE CONDITIONS
|
|
* (T-1)*LN(B)/LN(10) .GE. IDECPL AND 8*B*B-1 .LE. W .
|
|
* APPROXIMATELY MINIMAL T AND MAXIMAL B SATISFYING
|
|
* THESE CONDITIONS ARE CHOSEN.
|
|
* PARAMETERS IDECPL, ITMAX2 AND MAXDR ARE INTEGERS.
|
|
* BEWARE - MPSET WILL CAUSE AN INTEGER OVERFLOW TO OCCUR
|
|
* ****** IF WORDLENGTH IS LESS THAN 48 BITS.
|
|
* IF THIS IS NOT ALLOWABLE, CHANGE THE DETERMINATION
|
|
* OF W (DO 30 ... TO 30 W = WN) OR SET B, T, M,
|
|
* AND MXR WITHOUT CALLING MPSET.
|
|
* FIRST SET MXR
|
|
*/
|
|
|
|
MP.mxr = *maxdr ;
|
|
|
|
/* DETERMINE LARGE REPRESENTABLE INTEGER W OF FORM 2**K - 1 */
|
|
|
|
w = 0 ;
|
|
k = 0 ;
|
|
|
|
/* ON CYBER 76 HAVE TO FIND K .LE. 47, SO ONLY LOOP
|
|
* 47 TIMES AT MOST. IF GENUINE INTEGER WORDLENGTH
|
|
* EXCEEDS 47 BITS THIS RESTRICTION CAN BE RELAXED.
|
|
*/
|
|
|
|
for (i = 1; i <= 47; ++i)
|
|
{
|
|
|
|
/* INTEGER OVERFLOW WILL EVENTUALLY OCCUR HERE
|
|
* IF WORDLENGTH .LT. 48 BITS
|
|
*/
|
|
|
|
w2 = w + w ;
|
|
wn = w2 + 1 ;
|
|
|
|
/* APPARENTLY REDUNDANT TESTS MAY BE NECESSARY ON SOME
|
|
* MACHINES, DEPENDING ON HOW INTEGER OVERFLOW IS HANDLED
|
|
*/
|
|
|
|
if (wn <= w || wn <= w2 || wn <= 0) goto L40 ;
|
|
k = i ;
|
|
w = wn ;
|
|
}
|
|
|
|
/* SET MAXIMUM EXPONENT TO (W-1)/4 */
|
|
|
|
L40:
|
|
MP.m = w / 4 ;
|
|
if (*idecpl > 0) goto L60 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_SETB]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
|
|
/* B IS THE LARGEST POWER OF 2 SUCH THAT (8*B*B-1) .LE. W */
|
|
|
|
L60:
|
|
i__1 = (k - 3) / 2 ;
|
|
MP.b = pow_ii(&c__2, &i__1) ;
|
|
|
|
/* 2E0 BELOW ENSURES AT LEAST ONE GUARD DIGIT */
|
|
|
|
MP.t = (int) ((float) (*idecpl) * log((float)10.) / log((float)
|
|
MP.b) + (float)2.0) ;
|
|
|
|
/* SEE IF T TOO LARGE FOR DIMENSION STATEMENTS */
|
|
|
|
i2 = MP.t + 2 ;
|
|
if (i2 <= *itmax2) goto L80 ;
|
|
|
|
if (v->MPerrors)
|
|
{
|
|
char *msg;
|
|
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_SETC]) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_SETD]) ;
|
|
msg = (char *) XtMalloc(strlen( mpstrs[(int) MP_SETE]) + 200);
|
|
sprintf(msg, mpstrs[(int) MP_SETE], i2) ;
|
|
_DtSimpleError (v->appname, DtWarning, NULL, msg);
|
|
XtFree(msg);
|
|
}
|
|
|
|
mperr() ;
|
|
|
|
/* REDUCE TO MAXIMUM ALLOWED BY DIMENSION STATEMENTS */
|
|
|
|
MP.t = *itmax2 - 2 ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR (AT LEAST T+4) */
|
|
|
|
L80:
|
|
mpchk(&c__1, &c__4) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpsin(int *x, int *y)
|
|
{
|
|
float r__1 ;
|
|
|
|
static int i2, i3, ie, xs ;
|
|
static float rx, ry ;
|
|
|
|
/* RETURNS Y = SIN(X) FOR MP X AND Y,
|
|
* METHOD IS TO REDUCE X TO (-1, 1) AND USE MPSIN1, SO
|
|
* TIME IS O(M(T)T/LOG(T)).
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 5T+12
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__5, &c__12) ;
|
|
i2 = (MP.t << 2) + 11 ;
|
|
if (x[1] != 0) goto L20 ;
|
|
|
|
L10:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
L20:
|
|
xs = x[1] ;
|
|
ie = C_abs(x[2]) ;
|
|
if (ie <= 2) mpcmr(&x[1], &rx) ;
|
|
|
|
mpabs(&x[1], &MP.r[i2 - 1]) ;
|
|
|
|
/* USE MPSIN1 IF ABS(X) .LE. 1 */
|
|
|
|
if (mpcmpi(&MP.r[i2 - 1], &c__1) > 0) goto L30 ;
|
|
|
|
mpsin1(&MP.r[i2 - 1], &y[1], &c__1) ;
|
|
goto L50 ;
|
|
|
|
/* FIND ABS(X) MODULO 2PI (IT WOULD SAVE TIME IF PI WERE
|
|
* PRECOMPUTED AND SAVED IN COMMON).
|
|
* FOR INCREASED ACCURACY COMPUTE PI/4 USING MPART1
|
|
*/
|
|
|
|
L30:
|
|
i3 = (MP.t << 1) + 7 ;
|
|
mpart1(&c__5, &MP.r[i3 - 1]) ;
|
|
mpmuli(&MP.r[i3 - 1], &c__4, &MP.r[i3 - 1]) ;
|
|
mpart1(&c__239, &y[1]) ;
|
|
mpsub(&MP.r[i3 - 1], &y[1], &y[1]) ;
|
|
mpdiv(&MP.r[i2 - 1], &y[1], &MP.r[i2 - 1]) ;
|
|
mpdivi(&MP.r[i2 - 1], &c__8, &MP.r[i2 - 1]) ;
|
|
mpcmf(&MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
|
|
/* SUBTRACT 1/2, SAVE SIGN AND TAKE ABS */
|
|
|
|
mpaddq(&MP.r[i2 - 1], &c_n1, &c__2, &MP.r[i2 - 1]) ;
|
|
xs = -xs * MP.r[i2 - 1] ;
|
|
if (xs == 0) goto L10 ;
|
|
|
|
MP.r[i2 - 1] = 1 ;
|
|
mpmuli(&MP.r[i2 - 1], &c__4, &MP.r[i2 - 1]) ;
|
|
|
|
/* IF NOT LESS THAN 1, SUBTRACT FROM 2 */
|
|
|
|
if (MP.r[i2] > 0)
|
|
mpaddi(&MP.r[i2 - 1], &c_n2, &MP.r[i2 - 1]) ;
|
|
|
|
if (MP.r[i2 - 1] == 0) goto L10 ;
|
|
|
|
MP.r[i2 - 1] = 1 ;
|
|
mpmuli(&MP.r[i2 - 1], &c__2, &MP.r[i2 - 1]) ;
|
|
|
|
/* NOW REDUCED TO FIRST QUADRANT, IF LESS THAN PI/4 USE
|
|
* POWER SERIES, ELSE COMPUTE COS OF COMPLEMENT
|
|
*/
|
|
|
|
if (MP.r[i2] > 0) goto L40 ;
|
|
|
|
mpmul(&MP.r[i2 - 1], &y[1], &MP.r[i2 - 1]) ;
|
|
mpsin1(&MP.r[i2 - 1], &y[1], &c__1) ;
|
|
goto L50 ;
|
|
|
|
L40:
|
|
mpaddi(&MP.r[i2 - 1], &c_n2, &MP.r[i2 - 1]) ;
|
|
mpmul(&MP.r[i2 - 1], &y[1], &MP.r[i2 - 1]) ;
|
|
mpsin1(&MP.r[i2 - 1], &y[1], &c__0) ;
|
|
|
|
L50:
|
|
y[1] = xs ;
|
|
if (ie > 2) return ;
|
|
|
|
/* CHECK THAT ABSOLUTE ERROR LESS THAN 0.01 IF ABS(X) .LE. 100
|
|
* (IF ABS(X) IS LARGE THEN SINGLE-PRECISION SIN INACCURATE)
|
|
*/
|
|
|
|
if (dabs(rx) > (float)100.) return ;
|
|
|
|
mpcmr(&y[1], &ry) ;
|
|
if ((r__1 = ry - sin(rx), dabs(r__1)) < (float) 0.01) return ;
|
|
|
|
/* THE FOLLOWING MESSAGE MAY INDICATE THAT
|
|
* B**(T-1) IS TOO SMALL.
|
|
*/
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_SIN]) ;
|
|
|
|
mperr() ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpsin1(int *x, int *y, int *is)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, b2, i2, i3, ts ;
|
|
|
|
/* COMPUTES Y = SIN(X) IF IS.NE.0, Y = COS(X) IF IS.EQ.0,
|
|
* USING TAYLOR SERIES. ASSUMES ABS(X) .LE. 1.
|
|
* X AND Y ARE MP NUMBERS, IS AN INTEGER.
|
|
* TIME IS O(M(T)T/LOG(T)). THIS COULD BE REDUCED TO
|
|
* O(SQRT(T)M(T)) AS IN MPEXP1, BUT NOT WORTHWHILE UNLESS
|
|
* T IS VERY LARGE. ASYMPTOTICALLY FASTER METHODS ARE
|
|
* DESCRIBED IN THE REFERENCES GIVEN IN COMMENTS
|
|
* TO MPATAN AND MPPIGL.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 3T+8
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__3, &c__8) ;
|
|
if (x[1] != 0) goto L20 ;
|
|
|
|
/* SIN(0) = 0, COS(0) = 1 */
|
|
|
|
L10:
|
|
y[1] = 0 ;
|
|
if (*is == 0) mpcim(&c__1, &y[1]) ;
|
|
return ;
|
|
|
|
L20:
|
|
i2 = MP.t + 5 ;
|
|
i3 = i2 + MP.t + 2 ;
|
|
b2 = max(MP.b,64) << 1 ;
|
|
mpmul(&x[1], &x[1], &MP.r[i3 - 1]) ;
|
|
if (mpcmpi(&MP.r[i3 - 1], &c__1) <= 0) goto L40 ;
|
|
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_SIN1]) ;
|
|
|
|
mperr() ;
|
|
goto L10 ;
|
|
|
|
L40:
|
|
if (*is == 0) mpcim(&c__1, &MP.r[i2 - 1]) ;
|
|
if (*is != 0) mpstr(&x[1], &MP.r[i2 - 1]) ;
|
|
|
|
y[1] = 0 ;
|
|
i = 1 ;
|
|
ts = MP.t ;
|
|
if (*is == 0) goto L50 ;
|
|
|
|
mpstr(&MP.r[i2 - 1], &y[1]) ;
|
|
i = 2 ;
|
|
|
|
/* POWER SERIES LOOP. REDUCE T IF POSSIBLE */
|
|
|
|
L50:
|
|
MP.t = MP.r[i2] + ts + 2 ;
|
|
if (MP.t <= 2) goto L80 ;
|
|
|
|
MP.t = min(MP.t,ts) ;
|
|
|
|
/* PUT R(I3) FIRST IN CASE ITS DIGITS ARE MAINLY ZERO */
|
|
|
|
mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
|
|
/* IF I*(I+1) IS NOT REPRESENTABLE AS AN INTEGER, THE FOLLOWING
|
|
* DIVISION BY I*(I+1) HAS TO BE SPLIT UP.
|
|
*/
|
|
|
|
if (i > b2) goto L60 ;
|
|
|
|
i__1 = -i * (i + 1) ;
|
|
mpdivi(&MP.r[i2 - 1], &i__1, &MP.r[i2 - 1]) ;
|
|
goto L70 ;
|
|
|
|
L60:
|
|
i__1 = -i ;
|
|
mpdivi(&MP.r[i2 - 1], &i__1, &MP.r[i2 - 1]) ;
|
|
i__1 = i + 1 ;
|
|
mpdivi(&MP.r[i2 - 1], &i__1, &MP.r[i2 - 1]) ;
|
|
|
|
L70:
|
|
i += 2 ;
|
|
MP.t = ts ;
|
|
mpadd2(&MP.r[i2 - 1], &y[1], &y[1], &y[1], &c__0) ;
|
|
if (MP.r[i2 - 1] != 0) goto L50 ;
|
|
|
|
L80:
|
|
MP.t = ts ;
|
|
if (*is == 0) mpaddi(&y[1], &c__1, &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpsinh(int *x, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i2, i3, xs ;
|
|
|
|
/* RETURNS Y = SINH(X) FOR MP NUMBERS X AND Y, X NOT TOO LARGE.
|
|
* METHOD IS TO USE MPEXP OR MPEXP1, SPACE = 5T+12
|
|
* SAVE SIGN OF X AND CHECK FOR ZERO, SINH(0) = 0
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
xs = x[1] ;
|
|
if (xs != 0) goto L10 ;
|
|
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR */
|
|
|
|
L10:
|
|
mpchk(&c__5, &c__12) ;
|
|
i3 = (MP.t << 2) + 11 ;
|
|
|
|
/* WORK WITH ABS(X) */
|
|
|
|
mpabs(&x[1], &MP.r[i3 - 1]) ;
|
|
if (MP.r[i3] <= 0) goto L20 ;
|
|
|
|
/* HERE ABS(X) .GE. 1, IF TOO LARGE MPEXP GIVES ERROR MESSAGE
|
|
* INCREASE M TO AVOID OVERFLOW IF SINH(X) REPRESENTABLE
|
|
*/
|
|
|
|
MP.m += 2 ;
|
|
mpexp(&MP.r[i3 - 1], &MP.r[i3 - 1]) ;
|
|
mprec(&MP.r[i3 - 1], &y[1]) ;
|
|
mpsub(&MP.r[i3 - 1], &y[1], &y[1]) ;
|
|
|
|
/* RESTORE M. IF RESULT OVERFLOWS OR UNDERFLOWS, MPDIVI AT
|
|
* STATEMENT 30 WILL ACT ACCORDINGLY.
|
|
*/
|
|
|
|
MP.m += -2 ;
|
|
goto L30 ;
|
|
|
|
/* HERE ABS(X) .LT. 1 SO USE MPEXP1 TO AVOID CANCELLATION */
|
|
|
|
L20:
|
|
i2 = i3 - (MP.t + 2) ;
|
|
mpexp1(&MP.r[i3 - 1], &MP.r[i2 - 1]) ;
|
|
mpaddi(&MP.r[i2 - 1], &c__2, &MP.r[i3 - 1]) ;
|
|
mpmul(&MP.r[i3 - 1], &MP.r[i2 - 1], &y[1]) ;
|
|
mpaddi(&MP.r[i2 - 1], &c__1, &MP.r[i3 - 1]) ;
|
|
mpdiv(&y[1], &MP.r[i3 - 1], &y[1]) ;
|
|
|
|
/* DIVIDE BY TWO AND RESTORE SIGN */
|
|
|
|
L30:
|
|
i__1 = xs << 1 ;
|
|
mpdivi(&y[1], &i__1, &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpsqrt(int *x, int *y)
|
|
{
|
|
static int i, i2, iy3 ;
|
|
|
|
/* RETURNS Y = SQRT(X), USING SUBROUTINE MPROOT IF X .GT. 0.
|
|
* DIMENSION OF R IN CALLING PROGRAM MUST BE AT LEAST 4T+10
|
|
* (BUT Y(1) MAY BE R(3T+9)). X AND Y ARE MP NUMBERS.
|
|
* CHECK LEGALITY OF B, T, M AND MXR
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
mpchk(&c__4, &c__10) ;
|
|
|
|
/* MPROOT NEEDS 4T+10 WORDS, BUT CAN OVERLAP SLIGHTLY. */
|
|
|
|
i2 = MP.t * 3 + 9 ;
|
|
if (x[1] < 0) goto L10 ;
|
|
else if (x[1] == 0) goto L30 ;
|
|
else goto L40 ;
|
|
|
|
L10:
|
|
if (v->MPerrors) _DtSimpleError (v->appname, DtWarning, NULL, mpstrs[(int) MP_SQRT]) ;
|
|
|
|
mperr() ;
|
|
|
|
L30:
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
L40:
|
|
mproot(&x[1], &c_n2, &MP.r[i2 - 1]) ;
|
|
i = MP.r[i2 + 1] ;
|
|
mpmul(&x[1], &MP.r[i2 - 1], &y[1]) ;
|
|
iy3 = y[3] ;
|
|
mpext(&i, &iy3, &y[1]) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpstr(int *x, int *y)
|
|
{
|
|
int i__1 ;
|
|
|
|
static int i, j, t2 ;
|
|
|
|
/* SETS Y = X FOR MP X AND Y.
|
|
* SEE IF X AND Y HAVE THE SAME ADDRESS (THEY OFTEN DO)
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
j = x[1] ;
|
|
y[1] = j + 1 ;
|
|
if (j == x[1]) goto L10 ;
|
|
|
|
/* HERE X(1) AND Y(1) MUST HAVE THE SAME ADDRESS */
|
|
|
|
x[1] = j ;
|
|
return ;
|
|
|
|
/* HERE X(1) AND Y(1) HAVE DIFFERENT ADDRESSES */
|
|
|
|
L10:
|
|
y[1] = j ;
|
|
|
|
/* NO NEED TO MOVE X(2), ... IF X(1) = 0 */
|
|
|
|
if (j == 0) return ;
|
|
|
|
t2 = MP.t + 2 ;
|
|
i__1 = t2 ;
|
|
for (i = 2; i <= i__1; ++i) y[i] = x[i] ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpsub(int *x, int *y, int *z)
|
|
{
|
|
static int y1[1] ;
|
|
|
|
/* SUBTRACTS Y FROM X, FORMING RESULT IN Z, FOR MP X, Y AND Z.
|
|
* FOUR GUARD DIGITS ARE USED, AND THEN R*-ROUNDING
|
|
*/
|
|
|
|
--z ; /* Parameter adjustments */
|
|
--y ;
|
|
--x ;
|
|
|
|
y1[0] = -y[1] ;
|
|
mpadd2(&x[1], &y[1], &z[1], y1, &c__0) ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mptanh(int *x, int *y)
|
|
{
|
|
float r__1 ;
|
|
|
|
static int i2, xs ;
|
|
|
|
/* RETURNS Y = TANH(X) FOR MP NUMBERS X AND Y,
|
|
* USING MPEXP OR MPEXP1, SPACE = 5T+12
|
|
*/
|
|
|
|
--y ; /* Parameter adjustments */
|
|
--x ;
|
|
|
|
if (x[1] != 0) goto L10 ;
|
|
|
|
/* TANH(0) = 0 */
|
|
|
|
y[1] = 0 ;
|
|
return ;
|
|
|
|
/* CHECK LEGALITY OF B, T, M AND MXR */
|
|
|
|
L10:
|
|
mpchk(&c__5, &c__12) ;
|
|
i2 = (MP.t << 2) + 11 ;
|
|
|
|
/* SAVE SIGN AND WORK WITH ABS(X) */
|
|
|
|
xs = x[1] ;
|
|
mpabs(&x[1], &MP.r[i2 - 1]) ;
|
|
|
|
/* SEE IF ABS(X) SO LARGE THAT RESULT IS +-1 */
|
|
|
|
r__1 = (float) MP.t * (float).5 * log((float) MP.b) ;
|
|
mpcrm(&r__1, &y[1]) ;
|
|
if (mpcomp(&MP.r[i2 - 1], &y[1]) <= 0) goto L20 ;
|
|
|
|
/* HERE ABS(X) IS VERY LARGE */
|
|
|
|
mpcim(&xs, &y[1]) ;
|
|
return ;
|
|
|
|
/* HERE ABS(X) NOT SO LARGE */
|
|
|
|
L20:
|
|
mpmuli(&MP.r[i2 - 1], &c__2, &MP.r[i2 - 1]) ;
|
|
if (MP.r[i2] <= 0) goto L30 ;
|
|
|
|
/* HERE ABS(X) .GE. 1/2 SO USE MPEXP */
|
|
|
|
mpexp(&MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
mpaddi(&MP.r[i2 - 1], &c_n1, &y[1]) ;
|
|
mpaddi(&MP.r[i2 - 1], &c__1, &MP.r[i2 - 1]) ;
|
|
mpdiv(&y[1], &MP.r[i2 - 1], &y[1]) ;
|
|
goto L40 ;
|
|
|
|
/* HERE ABS(X) .LT. 1/2, SO USE MPEXP1 TO AVOID CANCELLATION */
|
|
|
|
L30:
|
|
mpexp1(&MP.r[i2 - 1], &MP.r[i2 - 1]) ;
|
|
mpaddi(&MP.r[i2 - 1], &c__2, &y[1]) ;
|
|
mpdiv(&MP.r[i2 - 1], &y[1], &y[1]) ;
|
|
|
|
/* RESTORE SIGN */
|
|
|
|
L40:
|
|
y[1] = xs * y[1] ;
|
|
return ;
|
|
}
|
|
|
|
|
|
void
|
|
mpunfl(int *x)
|
|
{
|
|
|
|
/* CALLED ON MULTIPLE-PRECISION UNDERFLOW, IE WHEN THE
|
|
* EXPONENT OF MP NUMBER X WOULD BE LESS THAN -M.
|
|
* SINCE M MAY HAVE BEEN OVERWRITTEN, CHECK B, T, M ETC.
|
|
*/
|
|
|
|
--x ; /* Parameter adjustments */
|
|
|
|
mpchk(&c__1, &c__4) ;
|
|
|
|
/* THE UNDERFLOWING NUMBER IS SET TO ZERO
|
|
* AN ALTERNATIVE WOULD BE TO CALL MPMINR (X) AND RETURN,
|
|
* POSSIBLY UPDATING A COUNTER AND TERMINATING EXECUTION
|
|
* AFTER A PRESET NUMBER OF UNDERFLOWS. ACTION COULD EASILY
|
|
* BE DETERMINED BY A FLAG IN LABELLED COMMON.
|
|
*/
|
|
|
|
x[1] = 0 ;
|
|
return ;
|
|
}
|
|
|
|
|
|
double
|
|
mppow_di(double *ap, int *bp)
|
|
{
|
|
double pow, x ;
|
|
int n ;
|
|
|
|
pow = 1 ;
|
|
x = *ap ;
|
|
n = *bp ;
|
|
|
|
if (n != 0)
|
|
{
|
|
if (n < 0)
|
|
{
|
|
if (x == 0) return(pow) ;
|
|
n = -n;
|
|
x = 1/x;
|
|
}
|
|
for (;;)
|
|
{
|
|
if (n & 01) pow *= x;
|
|
if (n >>= 1) x *= x ;
|
|
else break ;
|
|
}
|
|
}
|
|
return(pow) ;
|
|
}
|
|
|
|
|
|
int
|
|
pow_ii(int *ap, int *bp)
|
|
{
|
|
int pow, x, n ;
|
|
|
|
pow = 1 ;
|
|
x = *ap ;
|
|
n = *bp ;
|
|
|
|
if (n > 0)
|
|
for (;;)
|
|
{
|
|
if (n & 01) pow *= x ;
|
|
if (n >>= 1) x *= x ;
|
|
else break ;
|
|
}
|
|
return(pow) ;
|
|
}
|
|
|
|
|
|
double
|
|
mppow_ri(float *ap, int *bp)
|
|
{
|
|
double pow, x ;
|
|
int n ;
|
|
|
|
pow = 1 ;
|
|
x = *ap ;
|
|
n = *bp ;
|
|
|
|
if (n != 0)
|
|
{
|
|
if (n < 0)
|
|
{
|
|
if (x == 0) return(pow) ;
|
|
n = -n ;
|
|
x = 1/x ;
|
|
}
|
|
for (;;)
|
|
{
|
|
if (n & 01) pow *= x ;
|
|
if (n >>= 1) x *= x ;
|
|
else break ;
|
|
}
|
|
}
|
|
return(pow) ;
|
|
}
|