pgadmin3/pgscript/utilities/m_apm/mapm_add.cpp
levinsv 4af765213c support PG11
Поддержка PostgreSQL 11 только для Windows
2018-10-10 22:59:25 +05:00

329 lines
6 KiB
C++

/*
* M_APM - mapm_add.c
*
* Copyright (C) 1999 - 2007 Michael C. Ring
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted. Permission to distribute
* the modified code is granted. Modifications are to be distributed by
* using the file 'license.txt' as a template to modify the file header.
* 'license.txt' is available in the official MAPM distribution.
*
* This software is provided "as is" without express or implied warranty.
*/
/*
*
* This file contains the functions that implement the sin (5x)
* and cos (4x) multiple angle relations
*
*/
#include "pgAdmin3.h"
#include "pgscript/utilities/mapm-lib/m_apm_lc.h"
static M_APM M_work1 = NULL;
static M_APM M_work2 = NULL;
static int M_add_firsttime = TRUE;
/****************************************************************************/
void M_free_all_add()
{
if (M_add_firsttime == FALSE)
{
m_apm_free(M_work1);
m_apm_free(M_work2);
M_add_firsttime = TRUE;
}
}
/****************************************************************************/
void m_apm_add(M_APM r, M_APM a, M_APM b)
{
int j, carry, sign, aexp, bexp, adigits, bdigits;
if (M_add_firsttime)
{
M_add_firsttime = FALSE;
M_work1 = m_apm_init();
M_work2 = m_apm_init();
}
if (a->m_apm_sign == 0)
{
m_apm_copy(r, b);
return;
}
if (b->m_apm_sign == 0)
{
m_apm_copy(r, a);
return;
}
if (a->m_apm_sign == 1 && b->m_apm_sign == -1)
{
b->m_apm_sign = 1;
m_apm_subtract(r, a, b);
b->m_apm_sign = -1;
return;
}
if (a->m_apm_sign == -1 && b->m_apm_sign == 1)
{
a->m_apm_sign = 1;
m_apm_subtract(r, b, a);
a->m_apm_sign = -1;
return;
}
sign = a->m_apm_sign; /* signs are the same, result will be same */
aexp = a->m_apm_exponent;
bexp = b->m_apm_exponent;
m_apm_copy(M_work1, a);
m_apm_copy(M_work2, b);
/*
* scale by at least 1 factor of 10 in case the MSB carrys
*/
if (aexp == bexp)
{
M_apm_scale(M_work1, 2); /* shift 2 digits == 1 byte for efficiency */
M_apm_scale(M_work2, 2);
}
else
{
if (aexp > bexp)
{
M_apm_scale(M_work1, 2);
M_apm_scale(M_work2, (aexp + 2 - bexp));
}
else /* aexp < bexp */
{
M_apm_scale(M_work2, 2);
M_apm_scale(M_work1, (bexp + 2 - aexp));
}
}
adigits = M_work1->m_apm_datalength;
bdigits = M_work2->m_apm_datalength;
if (adigits >= bdigits)
{
m_apm_copy(r, M_work1);
j = (bdigits + 1) >> 1;
carry = 0;
while (TRUE)
{
j--;
r->m_apm_data[j] += carry + M_work2->m_apm_data[j];
if (r->m_apm_data[j] >= 100)
{
r->m_apm_data[j] -= 100;
carry = 1;
}
else
carry = 0;
if (j == 0)
break;
}
}
else
{
m_apm_copy(r, M_work2);
j = (adigits + 1) >> 1;
carry = 0;
while (TRUE)
{
j--;
r->m_apm_data[j] += carry + M_work1->m_apm_data[j];
if (r->m_apm_data[j] >= 100)
{
r->m_apm_data[j] -= 100;
carry = 1;
}
else
carry = 0;
if (j == 0)
break;
}
}
r->m_apm_sign = sign;
M_apm_normalize(r);
}
/****************************************************************************/
void m_apm_subtract(M_APM r, M_APM a, M_APM b)
{
int itmp, j, flag, icompare, sign, aexp, bexp,
borrow, adigits, bdigits;
if (M_add_firsttime)
{
M_add_firsttime = FALSE;
M_work1 = m_apm_init();
M_work2 = m_apm_init();
}
if (b->m_apm_sign == 0)
{
m_apm_copy(r, a);
return;
}
if (a->m_apm_sign == 0)
{
m_apm_copy(r, b);
r->m_apm_sign = -(r->m_apm_sign);
return;
}
if (a->m_apm_sign == 1 && b->m_apm_sign == -1)
{
b->m_apm_sign = 1;
m_apm_add(r, a, b);
b->m_apm_sign = -1;
return;
}
if (a->m_apm_sign == -1 && b->m_apm_sign == 1)
{
b->m_apm_sign = -1;
m_apm_add(r, a, b);
b->m_apm_sign = 1;
return;
}
/* now, the signs are the same */
/* make a positive working copy */
m_apm_absolute_value(M_work1, a);
m_apm_absolute_value(M_work2, b);
/* are they the same?? if so, the result is zero */
if ((icompare = m_apm_compare(M_work1, M_work2)) == 0)
{
M_set_to_zero(r);
return;
}
if (icompare == 1) /* |a| > |b| (do A-B) */
{
flag = TRUE;
sign = a->m_apm_sign;
}
else /* |b| > |a| (do B-A) */
{
flag = FALSE;
sign = -(a->m_apm_sign);
}
aexp = M_work1->m_apm_exponent;
bexp = M_work2->m_apm_exponent;
if (aexp > bexp)
M_apm_scale(M_work2, (aexp - bexp));
if (aexp < bexp)
M_apm_scale(M_work1, (bexp - aexp));
adigits = M_work1->m_apm_datalength;
bdigits = M_work2->m_apm_datalength;
if (adigits > bdigits)
M_apm_pad(M_work2, adigits);
if (adigits < bdigits)
M_apm_pad(M_work1, bdigits);
if (flag) /* perform A-B, M_work1 - M_work2 */
{
m_apm_copy(r, M_work1);
j = (r->m_apm_datalength + 1) >> 1;
borrow = 0;
while (TRUE)
{
j--;
itmp = (int)r->m_apm_data[j] - ((int)M_work2->m_apm_data[j] + borrow);
if (itmp >= 0)
{
r->m_apm_data[j] = (UCHAR)itmp;
borrow = 0;
}
else
{
r->m_apm_data[j] = (UCHAR)(100 + itmp);
borrow = 1;
}
if (j == 0)
break;
}
}
else /* perform B-A, M_work2 - M_work1 */
{
m_apm_copy(r, M_work2);
j = (r->m_apm_datalength + 1) >> 1;
borrow = 0;
while (TRUE)
{
j--;
itmp = (int)r->m_apm_data[j] - ((int)M_work1->m_apm_data[j] + borrow);
if (itmp >= 0)
{
r->m_apm_data[j] = (UCHAR)itmp;
borrow = 0;
}
else
{
r->m_apm_data[j] = (UCHAR)(100 + itmp);
borrow = 1;
}
if (j == 0)
break;
}
}
r->m_apm_sign = sign;
M_apm_normalize(r);
}
/****************************************************************************/
#ifdef __cplusplus
MAPM operator+(const MAPM &a, const MAPM &b)
{
MAPM ret;
m_apm_add(ret.val(), a.cval(), b.cval());
return ret;
}
MAPM operator-(const MAPM &a, const MAPM &b)
{
MAPM ret;
m_apm_subtract(ret.val(), a.cval(), b.cval());
return ret;
}
#endif