4528 lines
99 KiB
C
4528 lines
99 KiB
C
|
/* nl-math.c
|
||
|
|
||
|
|
||
|
Copyright (C) 2016 Lutz Mueller
|
||
|
|
||
|
This program is free software: you cann redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "newlisp.h"
|
||
|
#include "protos.h"
|
||
|
|
||
|
/* turn on for extra debugging output */
|
||
|
/* #define BAYES_DEBUG */
|
||
|
/* #define DEBUG */
|
||
|
|
||
|
#define OP_ADD 1
|
||
|
#define OP_SUBTRACT 2
|
||
|
#define OP_MULTIPLY 3
|
||
|
#define OP_DIVIDE 4
|
||
|
#define OP_BIT_OR 5
|
||
|
#define OP_BIT_AND 6
|
||
|
#define OP_BIT_XOR 7
|
||
|
#define OP_SHIFTL 8
|
||
|
#define OP_SHIFTR 9
|
||
|
#define OP_POW 10
|
||
|
#define OP_MODULO 11
|
||
|
#define OP_SIN 12
|
||
|
#define OP_COS 13
|
||
|
#define OP_TAN 14
|
||
|
#define OP_ASIN 15
|
||
|
#define OP_ACOS 16
|
||
|
#define OP_ATAN 17
|
||
|
#define OP_SINH 18
|
||
|
#define OP_COSH 19
|
||
|
#define OP_TANH 20
|
||
|
#define OP_ASINH 21
|
||
|
#define OP_ACOSH 22
|
||
|
#define OP_ATANH 23
|
||
|
#define OP_SQRT 24
|
||
|
#define OP_LOG 25
|
||
|
#define OP_EXP 26
|
||
|
#define OP_MIN 27
|
||
|
#define OP_MAX 28
|
||
|
#define OP_CEIL 30
|
||
|
#define OP_FLOOR 31
|
||
|
#define OP_NAN 32
|
||
|
#define OP_ERRORFUNC 33
|
||
|
#define OP_SIGNUM 34
|
||
|
#define OP_ISNAN 35
|
||
|
#define OP_ISINF 36
|
||
|
|
||
|
#ifdef BIGINT
|
||
|
#define BIGINT_BASE 1000000000 /* 9 zeros */
|
||
|
#define BIGINT_BASE2 1000000000000000000LL /* 18 zeros */
|
||
|
#endif
|
||
|
|
||
|
extern uint32_t my_random();
|
||
|
void my_srandom(uint32_t seed);
|
||
|
uint32_t max_rand = MY_RAND_MAX;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
void debug(int * x, int n, char * txt)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
printf("%s ", txt);
|
||
|
for(i = 0; i <= n; i++)
|
||
|
printf("%d_", x[i]);
|
||
|
printf("\n");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
CELL * p_abs(CELL * params)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
INT64 intValue;
|
||
|
double floatValue;
|
||
|
#ifdef BIGINT
|
||
|
int * numPtr;
|
||
|
#endif
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
#ifdef BIGINT
|
||
|
if(cell->type == CELL_BIGINT)
|
||
|
{
|
||
|
cell = copyCell(cell);
|
||
|
numPtr = (int *)cell->contents;
|
||
|
if(*numPtr == -1) *numPtr = 1;
|
||
|
return(cell);
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
if(cell->type == CELL_FLOAT)
|
||
|
{
|
||
|
floatValue = getDirectFloat(cell);
|
||
|
if(floatValue < 0.0) floatValue = floatValue * -1.0;
|
||
|
return(stuffFloat(floatValue));
|
||
|
}
|
||
|
|
||
|
getInteger64Ext(cell, &intValue, FALSE);
|
||
|
if(intValue < 0) intValue = intValue * -1;
|
||
|
|
||
|
return(stuffInteger64(intValue));
|
||
|
}
|
||
|
|
||
|
CELL * incDecI(CELL * params, int type)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
INT64 adjust = 1;
|
||
|
INT64 lValue = 0;
|
||
|
#ifdef BIGINT
|
||
|
int * lvaluePtr;
|
||
|
int * adjustPtr;
|
||
|
int * resultPtr;
|
||
|
int * freePtr = NULL;
|
||
|
int lvlen, adjlen, reslen;
|
||
|
#endif
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
|
||
|
if(symbolCheck != NULL)
|
||
|
{
|
||
|
if(isProtected(symbolCheck->flags))
|
||
|
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbolCheck)));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(cell == nilCell)
|
||
|
errorProc(ERR_INVALID_PARAMETER);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(!isNil(cell))
|
||
|
#ifdef BIGINT
|
||
|
{
|
||
|
if(cell->type == CELL_BIGINT)
|
||
|
{
|
||
|
lvaluePtr = (int *)cell->contents;
|
||
|
lvlen = cell->aux - 1;
|
||
|
|
||
|
if(params->next != nilCell)
|
||
|
freePtr = getBigintSizeDirect(evaluateExpression(params->next) , &adjustPtr, &adjlen);
|
||
|
else
|
||
|
freePtr = adjustPtr = intToBigint(1, &adjlen);
|
||
|
|
||
|
reslen = (lvlen > adjlen) ? lvlen + 2 : adjlen + 2;
|
||
|
resultPtr = calloc(reslen, sizeof(int));
|
||
|
if(type < 0)
|
||
|
subBigint(lvaluePtr, lvlen, adjustPtr, adjlen, resultPtr, &reslen);
|
||
|
else
|
||
|
addBigint(lvaluePtr, lvlen, adjustPtr, adjlen, resultPtr, &reslen);
|
||
|
if(freePtr) freeMemory(freePtr);
|
||
|
/* update old cell */
|
||
|
freeMemory((void *)cell->contents);
|
||
|
cell->contents = (UINT)resultPtr;
|
||
|
cell->aux = reslen + 1;
|
||
|
return(copyCell(cell));
|
||
|
}
|
||
|
getInteger64Ext(cell, &lValue, FALSE);
|
||
|
}
|
||
|
#else
|
||
|
getInteger64Ext(cell, &lValue, FALSE);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
if(params->next != nilCell)
|
||
|
getInteger64Ext(params->next, &adjust, TRUE);
|
||
|
|
||
|
#ifndef NEWLISP64
|
||
|
cell->type = CELL_INT64;
|
||
|
*(INT64 *)&cell->aux = lValue + adjust * type;
|
||
|
#else
|
||
|
cell->type = CELL_LONG;
|
||
|
cell->contents = lValue + adjust * type;
|
||
|
#endif
|
||
|
|
||
|
return(copyCell(cell));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * incDecF(CELL * params, int type)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
double adjust = 1.0;
|
||
|
double lValue = 0.0;
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
|
||
|
if(symbolCheck != NULL)
|
||
|
{
|
||
|
if(isProtected(symbolCheck->flags))
|
||
|
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(symbolCheck)));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(cell == nilCell)
|
||
|
errorProc(ERR_INVALID_PARAMETER);
|
||
|
}
|
||
|
|
||
|
if(!isNil(cell)) getFloat(cell, &lValue);
|
||
|
|
||
|
if(params->next != nilCell)
|
||
|
getFloat(params->next, &adjust);
|
||
|
|
||
|
cell->type = CELL_FLOAT;
|
||
|
#ifndef NEWLISP64
|
||
|
*(double *)&cell->aux = lValue + adjust * type;
|
||
|
#else
|
||
|
*(double *)&cell->contents = lValue + adjust * type;
|
||
|
#endif
|
||
|
|
||
|
return(copyCell(cell));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_incrementI(CELL * params) { return(incDecI(params, 1)); }
|
||
|
CELL * p_decrementI(CELL * params) { return(incDecI(params, -1)); }
|
||
|
CELL * p_incrementF(CELL * params) { return(incDecF(params, 1)); }
|
||
|
CELL * p_decrementF(CELL * params) { return(incDecF(params, -1)); }
|
||
|
|
||
|
CELL * arithmetikOp(CELL * params, int op)
|
||
|
{
|
||
|
INT64 number;
|
||
|
INT64 result;
|
||
|
#ifdef BIGINT
|
||
|
int sizex = 0;
|
||
|
int sizey = 0;
|
||
|
int n;
|
||
|
int * num = NULL;
|
||
|
int * numx;
|
||
|
int * numy;
|
||
|
int * freePtr = NULL;
|
||
|
CELL * next;
|
||
|
#endif
|
||
|
CELL * cell;
|
||
|
|
||
|
if(params == nilCell)
|
||
|
{
|
||
|
if(op == OP_ADD)
|
||
|
return(stuffInteger64(0));
|
||
|
if(op == OP_MULTIPLY)
|
||
|
return(stuffInteger64(1));
|
||
|
}
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
params = params->next;
|
||
|
#ifdef BIGINT
|
||
|
if(cell->type == CELL_BIGINT)
|
||
|
{
|
||
|
if(params == nilCell)
|
||
|
{
|
||
|
cell = copyCell(cell);
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_SUBTRACT:
|
||
|
*(int *)cell->contents *= -1; break;
|
||
|
case OP_ADD:
|
||
|
case OP_MULTIPLY:
|
||
|
case OP_DIVIDE:
|
||
|
case OP_MODULO:
|
||
|
break;
|
||
|
default:
|
||
|
return(errorProc(ERR_BIGINT_NOT_ALLOWED));
|
||
|
}
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
NEXT_FIRST_BIGINT:
|
||
|
/* first OP is CELL_BIGINT */
|
||
|
numx = (int*)cell->contents;
|
||
|
sizex = cell->aux - 1;
|
||
|
|
||
|
/* if 2nd OP is not CELL_BIGINT memory is allocated */
|
||
|
next = evaluateExpression(params);
|
||
|
if(next->type == CELL_BIGINT) /* speedup */
|
||
|
{
|
||
|
numy = (int*)next->contents;
|
||
|
sizey = next->aux - 1;
|
||
|
}
|
||
|
else
|
||
|
freePtr = getBigintSizeDirect(next, &numy, &sizey);
|
||
|
|
||
|
if(op == OP_MULTIPLY)
|
||
|
n = sizex + sizey + 2;
|
||
|
else
|
||
|
n = sizex > sizey ? sizex + 2: sizey + 2;
|
||
|
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_ADD:
|
||
|
num = addBigint(numx, sizex, numy, sizey, malloc(n * sizeof(int)), &n);
|
||
|
break;
|
||
|
case OP_SUBTRACT:
|
||
|
num = subBigint(numx, sizex, numy, sizey, malloc(n * sizeof(int)), &n);
|
||
|
break;
|
||
|
case OP_MULTIPLY:
|
||
|
num = mulBigint(numx, sizex, numy, sizey, malloc(n * sizeof(int)), &n);
|
||
|
break;
|
||
|
case OP_DIVIDE:
|
||
|
num = divModBigint(numx, sizex, numy, sizey, FALSE, &n);
|
||
|
break;
|
||
|
case OP_MODULO:
|
||
|
num = divModBigint(numx, sizex, numy, sizey, TRUE, &n);
|
||
|
break;
|
||
|
default:
|
||
|
return(errorProc(ERR_BIGINT_NOT_ALLOWED));
|
||
|
}
|
||
|
|
||
|
if(freePtr)
|
||
|
{
|
||
|
freeMemory(freePtr);
|
||
|
freePtr = NULL;
|
||
|
}
|
||
|
cell = getCell(CELL_BIGINT);
|
||
|
cell->contents = (UINT)num;
|
||
|
cell->aux = n + 1;
|
||
|
if(params->next != nilCell)
|
||
|
{
|
||
|
pushResult(cell);
|
||
|
params = params->next;
|
||
|
goto NEXT_FIRST_BIGINT;
|
||
|
}
|
||
|
return(cell);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
getInteger64Ext(cell, &result, FALSE);
|
||
|
if(params == nilCell)
|
||
|
{
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_SUBTRACT:
|
||
|
result = - result;
|
||
|
break;
|
||
|
case OP_SHIFTL:
|
||
|
result <<= 1;
|
||
|
break;
|
||
|
case OP_SHIFTR:
|
||
|
result >>= 1;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else while(params != nilCell)
|
||
|
{
|
||
|
params = getInteger64Ext(params, &number, TRUE);
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_ADD: result += number; break;
|
||
|
case OP_SUBTRACT: result -= number; break;
|
||
|
case OP_MULTIPLY: result *= number; break;
|
||
|
case OP_DIVIDE:
|
||
|
if(number == 0) return(errorProc(ERR_MATH));
|
||
|
result /= number; break;
|
||
|
case OP_BIT_OR: result |= number; break;
|
||
|
case OP_BIT_AND: result &= number; break;
|
||
|
case OP_BIT_XOR: result ^= number; break;
|
||
|
case OP_SHIFTL: result <<= number; break;
|
||
|
case OP_SHIFTR: result >>= number; break;
|
||
|
case OP_MODULO:
|
||
|
if(number == 0) return(errorProc(ERR_MATH));
|
||
|
result %= number; break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(stuffInteger64(result));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_add(CELL * params) { return(arithmetikOp(params, OP_ADD)); }
|
||
|
CELL * p_subtract(CELL * params) { return(arithmetikOp(params, OP_SUBTRACT)); }
|
||
|
CELL * p_multiply(CELL * params) { return(arithmetikOp(params, OP_MULTIPLY)); }
|
||
|
CELL * p_divide(CELL * params) { return(arithmetikOp(params, OP_DIVIDE)); }
|
||
|
|
||
|
CELL * p_bitOr(CELL * params) { return(arithmetikOp(params, OP_BIT_OR)); }
|
||
|
CELL * p_bitAnd(CELL * params) { return(arithmetikOp(params, OP_BIT_AND)); }
|
||
|
CELL * p_bitXor(CELL * params) { return(arithmetikOp(params, OP_BIT_XOR)); }
|
||
|
CELL * p_shiftLeft(CELL * params) { return(arithmetikOp(params, OP_SHIFTL)); }
|
||
|
CELL * p_shiftRight(CELL * params) { return(arithmetikOp(params, OP_SHIFTR)); }
|
||
|
CELL * p_modulo(CELL * params) { return(arithmetikOp(params, OP_MODULO)); }
|
||
|
|
||
|
|
||
|
CELL * p_bitNot(CELL * params)
|
||
|
{
|
||
|
INT64 number;
|
||
|
getInteger64Ext(params, &number, TRUE);
|
||
|
return(stuffInteger64(~number));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----------------------- float arithmetik ----------------------------- */
|
||
|
|
||
|
CELL * getFloat(CELL * params, double *);
|
||
|
CELL * floatOp(CELL * params, int op);
|
||
|
int compareFloats(CELL * left, CELL * right);
|
||
|
int compareInts(CELL * left, CELL * right);
|
||
|
|
||
|
CELL * p_addFloat(CELL * params) { return(floatOp(params, OP_ADD)); }
|
||
|
CELL * p_subFloat(CELL * params) { return(floatOp(params, OP_SUBTRACT)); }
|
||
|
CELL * p_mulFloat(CELL * params) { return(floatOp(params, OP_MULTIPLY)); }
|
||
|
CELL * p_divFloat(CELL * params) { return(floatOp(params, OP_DIVIDE)); }
|
||
|
CELL * p_minFloat(CELL * params) { return(floatOp(params, OP_MIN)); }
|
||
|
CELL * p_maxFloat(CELL * params) { return(floatOp(params, OP_MAX)); }
|
||
|
CELL * p_powFloat(CELL * params) { return(floatOp(params, OP_POW)); }
|
||
|
CELL * p_modFloat(CELL * params) { return(floatOp(params, OP_MODULO)); }
|
||
|
|
||
|
CELL * floatOp(CELL * params, int op)
|
||
|
{
|
||
|
double number;
|
||
|
double result;
|
||
|
|
||
|
if(params == nilCell)
|
||
|
{
|
||
|
if(op == OP_ADD)
|
||
|
{
|
||
|
result = 0.0;
|
||
|
goto END_FLOAT_ARITHMETIK;
|
||
|
}
|
||
|
if(op == OP_MULTIPLY)
|
||
|
{
|
||
|
result = 1.0;
|
||
|
goto END_FLOAT_ARITHMETIK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
params = getFloat(params, &result);
|
||
|
|
||
|
if(params == nilCell)
|
||
|
{
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_SUBTRACT:
|
||
|
result = - result; break;
|
||
|
case OP_DIVIDE:
|
||
|
result = 1.0 / result; break;
|
||
|
case OP_POW:
|
||
|
result = result * result; break;
|
||
|
case OP_MODULO:
|
||
|
result = result - (int)result; break;
|
||
|
default: break;
|
||
|
}
|
||
|
goto END_FLOAT_ARITHMETIK;
|
||
|
}
|
||
|
|
||
|
else while(params != nilCell)
|
||
|
{
|
||
|
params = getFloat(params, &number);
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_ADD: result += number; break;
|
||
|
case OP_SUBTRACT: result -= number; break;
|
||
|
case OP_MULTIPLY: result *= number; break;
|
||
|
case OP_DIVIDE: result /= number; break;
|
||
|
case OP_MIN: if(number < result) result = number; break;
|
||
|
case OP_MAX: if(number > result) result = number; break;
|
||
|
case OP_POW: result = pow(result, number); break;
|
||
|
case OP_MODULO:
|
||
|
result = fmod(result, number);
|
||
|
default: break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
END_FLOAT_ARITHMETIK:
|
||
|
params = getCell(CELL_FLOAT);
|
||
|
#ifndef NEWLISP64
|
||
|
memcpy((void *)¶ms->aux, (void *)&result, sizeof(double));
|
||
|
#else
|
||
|
*(double *)¶ms->contents = result;
|
||
|
#endif
|
||
|
return(params);
|
||
|
}
|
||
|
|
||
|
|
||
|
int compareFloats(CELL * left, CELL * right)
|
||
|
{
|
||
|
double leftFloat, rightFloat;
|
||
|
|
||
|
leftFloat = getDirectFloat(left);
|
||
|
rightFloat = getDirectFloat(right);
|
||
|
|
||
|
/* if(isnan(leftFloat) && isnan(rightFloat)) return(0); */
|
||
|
if(isnan(leftFloat) || isnan(rightFloat)) return(9);
|
||
|
|
||
|
if(leftFloat < rightFloat) return(-1);
|
||
|
if(leftFloat > rightFloat) return(1);
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
/* should only be called when left and right type are different
|
||
|
and only called from compareCells()
|
||
|
*/
|
||
|
int compareInts(CELL * left, CELL * right)
|
||
|
{
|
||
|
INT64 leftnum;
|
||
|
INT64 rightnum;
|
||
|
|
||
|
#ifdef BIGINT
|
||
|
int * leftnumPtr;
|
||
|
int leftlen;
|
||
|
int * rightnumPtr;
|
||
|
int rightlen;
|
||
|
int cmp;
|
||
|
|
||
|
if(left->type == CELL_BIGINT)
|
||
|
{
|
||
|
leftnumPtr = (int *)left->contents;
|
||
|
leftlen = left->aux - 1;
|
||
|
/* would never get here when right->type == CELL_BIGINT */
|
||
|
getBigintSizeDirect(right , &rightnumPtr, &rightlen);
|
||
|
cmp = cmpBigint(leftnumPtr, leftlen, rightnumPtr, rightlen);
|
||
|
freeMemory(rightnumPtr);
|
||
|
return(cmp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifndef NEWLISP64
|
||
|
if(left->type == CELL_LONG)
|
||
|
leftnum = (int)left->contents;
|
||
|
else
|
||
|
leftnum = *(INT64 *)&left->aux;
|
||
|
|
||
|
if(right->type == CELL_LONG)
|
||
|
rightnum = (int)right->contents;
|
||
|
#ifdef CELL_BIGINT
|
||
|
else if(right->type == CELL_BIGINT)
|
||
|
getInteger64Ext(right, &rightnum, FALSE);
|
||
|
#endif
|
||
|
else
|
||
|
rightnum = *(INT64 *)&right->aux;
|
||
|
#else /* NEWLISP64 */
|
||
|
leftnum = (UINT)left->contents;
|
||
|
#ifdef CELL_BIGINT
|
||
|
if(right->type == CELL_BIGINT)
|
||
|
getInteger64Ext(right, &rightnum, FALSE);
|
||
|
else
|
||
|
#endif
|
||
|
rightnum = (UINT)right->contents;
|
||
|
#endif /* NEWLISP64 */
|
||
|
|
||
|
if(leftnum < rightnum) return(-1);
|
||
|
if(leftnum > rightnum) return(1);
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
double getDirectFloat(CELL * param)
|
||
|
{
|
||
|
double floatNum = 0.0;
|
||
|
|
||
|
#ifndef NEWLISP64
|
||
|
if(param->type == CELL_FLOAT)
|
||
|
return(*(double *)¶m->aux);
|
||
|
else if(param->type == CELL_LONG)
|
||
|
floatNum = (INT)param->contents;
|
||
|
else if(param->type == CELL_INT64)
|
||
|
floatNum = *(INT64 *)¶m->aux;
|
||
|
#ifdef BIGINT
|
||
|
else if(param->type == CELL_BIGINT)
|
||
|
floatNum = bigintCellToFloat(param);
|
||
|
#endif
|
||
|
|
||
|
#else /* NEWLISP64 */
|
||
|
if(param->type == CELL_FLOAT)
|
||
|
return(*(double *)¶m->contents);
|
||
|
else if(param->type == CELL_LONG)
|
||
|
floatNum = (INT)param->contents;
|
||
|
|
||
|
#ifdef BIGINT
|
||
|
else if(param->type == CELL_BIGINT)
|
||
|
floatNum = bigintCellToFloat(param);
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return(floatNum);
|
||
|
}
|
||
|
|
||
|
/* ----------------------------- float functions ----------------------- */
|
||
|
|
||
|
|
||
|
CELL * functionFloat(CELL *, int);
|
||
|
|
||
|
CELL * p_sin(CELL * params) { return(functionFloat(params, OP_SIN)); }
|
||
|
CELL * p_cos(CELL * params) { return(functionFloat(params, OP_COS)); }
|
||
|
CELL * p_tan(CELL * params) { return(functionFloat(params, OP_TAN)); }
|
||
|
CELL * p_asin(CELL * params) { return(functionFloat(params, OP_ASIN)); }
|
||
|
CELL * p_acos(CELL * params) { return(functionFloat(params, OP_ACOS)); }
|
||
|
CELL * p_atan(CELL * params) { return(functionFloat(params, OP_ATAN)); }
|
||
|
CELL * p_sinh(CELL * params) { return(functionFloat(params, OP_SINH)); }
|
||
|
CELL * p_cosh(CELL * params) { return(functionFloat(params, OP_COSH)); }
|
||
|
CELL * p_tanh(CELL * params) { return(functionFloat(params, OP_TANH)); }
|
||
|
CELL * p_asinh(CELL * params) { return(functionFloat(params, OP_ASINH)); }
|
||
|
CELL * p_acosh(CELL * params) { return(functionFloat(params, OP_ACOSH)); }
|
||
|
CELL * p_atanh(CELL * params) { return(functionFloat(params, OP_ATANH)); }
|
||
|
CELL * p_sqrt(CELL * params) { return(functionFloat(params, OP_SQRT)); }
|
||
|
CELL * p_log(CELL * params) { return(functionFloat(params, OP_LOG)); }
|
||
|
CELL * p_exp(CELL * params) { return(functionFloat(params, OP_EXP)); }
|
||
|
CELL * p_ceil(CELL * params) { return(functionFloat(params, OP_CEIL)); }
|
||
|
CELL * p_floor(CELL * params) { return(functionFloat(params, OP_FLOOR)); }
|
||
|
CELL * p_erf(CELL * params) { return(functionFloat(params, OP_ERRORFUNC)); }
|
||
|
CELL * p_sgn(CELL * params) { return(functionFloat(params, OP_SIGNUM)); }
|
||
|
CELL * p_isnan(CELL * params) { return(functionFloat(params, OP_ISNAN)); }
|
||
|
CELL * p_isinf(CELL * params) { return(functionFloat(params, OP_ISINF)); }
|
||
|
|
||
|
CELL * functionFloat(CELL * params, int op)
|
||
|
{
|
||
|
double floatN;
|
||
|
double base;
|
||
|
CELL * cell;
|
||
|
|
||
|
getFloat(params, &floatN);
|
||
|
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_SIN: floatN = sin(floatN); break;
|
||
|
case OP_COS: floatN = cos(floatN); break;
|
||
|
case OP_TAN: floatN = tan(floatN); break;
|
||
|
|
||
|
case OP_ASIN: floatN = asin(floatN); break;
|
||
|
case OP_ACOS: floatN = acos(floatN); break;
|
||
|
case OP_ATAN: floatN = atan(floatN); break;
|
||
|
|
||
|
case OP_SINH: floatN = sinh(floatN); break;
|
||
|
case OP_COSH: floatN = cosh(floatN); break;
|
||
|
case OP_TANH: floatN = tanh(floatN); break;
|
||
|
|
||
|
case OP_ASINH: floatN = asinh(floatN); break;
|
||
|
case OP_ACOSH: floatN = acosh(floatN); break;
|
||
|
case OP_ATANH: floatN = atanh(floatN); break;
|
||
|
|
||
|
case OP_SQRT: floatN = sqrt(floatN); break;
|
||
|
case OP_LOG:
|
||
|
if(params->next != nilCell)
|
||
|
{
|
||
|
getFloat(params->next, &base);
|
||
|
floatN = log(floatN) / log(base);
|
||
|
}
|
||
|
else
|
||
|
floatN = log(floatN);
|
||
|
break;
|
||
|
case OP_EXP: floatN = exp(floatN); break;
|
||
|
case OP_CEIL: floatN = ceil(floatN); break;
|
||
|
case OP_FLOOR: floatN = floor(floatN); break;
|
||
|
case OP_ERRORFUNC: floatN = erf(floatN); break;
|
||
|
case OP_SIGNUM:
|
||
|
if(params->next == nilCell)
|
||
|
{
|
||
|
if(floatN > 0.0) floatN = 1.0;
|
||
|
else if(floatN < 0.0) floatN = -1.0;
|
||
|
else floatN = 0.0;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(floatN < 0.0) cell = params->next;
|
||
|
else
|
||
|
{
|
||
|
params = params->next;
|
||
|
if(floatN == 0.0) cell = params->next;
|
||
|
else {
|
||
|
params = params->next;
|
||
|
cell = params->next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(copyCell(evaluateExpression(cell)));
|
||
|
case OP_ISNAN:
|
||
|
return (isnan(floatN) ? trueCell : nilCell);
|
||
|
case OP_ISINF:
|
||
|
#ifdef SOLARIS
|
||
|
return((isnan(floatN - floatN)) ? trueCell : nilCell);
|
||
|
#else
|
||
|
return(isinf(floatN) ? trueCell : nilCell);
|
||
|
#endif
|
||
|
default: break;
|
||
|
}
|
||
|
|
||
|
cell = getCell(CELL_FLOAT);
|
||
|
#ifndef NEWLISP64
|
||
|
*(double *)&cell->aux = floatN;
|
||
|
#else
|
||
|
*(double *)&cell->contents = floatN;
|
||
|
#endif
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
CELL * p_ssq(CELL * params)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
double floatNum = 0.0;
|
||
|
double sqSum = 0.0;
|
||
|
CELL * * addr;
|
||
|
UINT idx, n;
|
||
|
|
||
|
getEvalDefault(params, &cell);
|
||
|
if(cell->type == CELL_EXPRESSION)
|
||
|
{
|
||
|
cell = (CELL *)cell->contents;
|
||
|
while(cell != nilCell)
|
||
|
{
|
||
|
floatNum = getDirectFloat(cell);
|
||
|
sqSum += floatNum * floatNum;
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
}
|
||
|
else if(cell->type == CELL_ARRAY)
|
||
|
{
|
||
|
addr = (CELL * *)cell->contents;
|
||
|
n = (cell->aux - 1) / sizeof(CELL *);
|
||
|
for (idx = 0; idx < n; idx++)
|
||
|
{
|
||
|
cell = *(addr + idx);
|
||
|
floatNum = getDirectFloat(cell);
|
||
|
sqSum += floatNum * floatNum;
|
||
|
}
|
||
|
}
|
||
|
else return(errorProcExt(ERR_LIST_OR_ARRAY_EXPECTED, params));
|
||
|
|
||
|
return(stuffFloat(sqSum));
|
||
|
}
|
||
|
|
||
|
CELL * p_atan2(CELL * params)
|
||
|
{
|
||
|
double floatX, floatY;
|
||
|
CELL * cell;
|
||
|
|
||
|
params = getFloat(params, &floatX);
|
||
|
getFloat(params, &floatY);
|
||
|
|
||
|
cell = getCell(CELL_FLOAT);
|
||
|
#ifndef NEWLISP64
|
||
|
*(double *)&cell->aux = atan2(floatX, floatY);
|
||
|
#else
|
||
|
*(double *)&cell->contents = atan2(floatX, floatY);
|
||
|
#endif
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
CELL * p_round(CELL * params)
|
||
|
{
|
||
|
double fNum;
|
||
|
double precision = 1.0;
|
||
|
INT digits = 0;
|
||
|
char * fmt;
|
||
|
char * result;
|
||
|
|
||
|
|
||
|
params = getFloat(params, &fNum);
|
||
|
if(params != nilCell)
|
||
|
getInteger(params, (UINT*)&digits);
|
||
|
|
||
|
if(digits >= 0)
|
||
|
{
|
||
|
precision = pow(10.0, (double)(digits > 20 ? 20 : digits));
|
||
|
fNum = precision * floor(fNum/precision + 0.5);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fmt = alloca(16);
|
||
|
result = alloca(32);
|
||
|
snprintf(fmt, 15, "%%.%df", (int)((digits < -16) ? 16 : -digits));
|
||
|
snprintf(result, 31, fmt, fNum);
|
||
|
fNum = atof(result);
|
||
|
}
|
||
|
|
||
|
return(stuffFloat(fNum));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_rand(CELL * params)
|
||
|
{
|
||
|
INT range;
|
||
|
INT n;
|
||
|
CELL * dist, * cell;
|
||
|
INT rnum;
|
||
|
double scale;
|
||
|
|
||
|
params = getInteger(params, (UINT *)&range);
|
||
|
scale = range;
|
||
|
if(range == 0)
|
||
|
{
|
||
|
srandom((unsigned)time(NULL));
|
||
|
return(trueCell);
|
||
|
}
|
||
|
|
||
|
while((rnum = my_random()) == max_rand);
|
||
|
rnum = (scale * rnum)/max_rand;
|
||
|
|
||
|
if(params->type == CELL_NIL)
|
||
|
return(stuffInteger((UINT)rnum));
|
||
|
|
||
|
getInteger(params, (UINT *)&n);
|
||
|
|
||
|
|
||
|
cell = stuffInteger((UINT)rnum);
|
||
|
dist = makeCell(CELL_EXPRESSION, (UINT)cell);
|
||
|
|
||
|
--n;
|
||
|
while(n-- > 0)
|
||
|
{
|
||
|
while((rnum = my_random()) == max_rand);
|
||
|
rnum = (scale * rnum)/max_rand;
|
||
|
cell->next = stuffInteger((UINT)rnum);
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
|
||
|
return(dist);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_amb(CELL * params)
|
||
|
{
|
||
|
INT len;
|
||
|
CELL * cell;
|
||
|
|
||
|
if((len = listlen(params)) == 0) return(nilCell);
|
||
|
|
||
|
len = my_random() % len;
|
||
|
|
||
|
while(len--) params = params->next;
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
if(symbolCheck)
|
||
|
{
|
||
|
pushResultFlag = FALSE;
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
return(copyCell(cell));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* from my_srandom() */
|
||
|
extern int my_random_flag;
|
||
|
extern UINT nshuff;
|
||
|
extern uint32_t randseed;
|
||
|
|
||
|
CELL * p_seed(CELL * params)
|
||
|
{
|
||
|
static INT64 seedNum = 0;
|
||
|
|
||
|
if(params == nilCell)
|
||
|
return(stuffInteger(my_random_flag ? randseed : seedNum));
|
||
|
|
||
|
params = getInteger64Ext(params, &seedNum, TRUE);
|
||
|
|
||
|
my_random_flag = getFlag(params);
|
||
|
max_rand = my_random_flag ? 0x7FFFFFFF : MY_RAND_MAX;
|
||
|
|
||
|
if(my_random_flag && params->next != nilCell)
|
||
|
getInteger(params->next, &nshuff);
|
||
|
|
||
|
my_srandom((UINT)(seedNum & 0xFFFFFFFF));
|
||
|
|
||
|
return(stuffInteger(seedNum));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----------------------- compare ops --------------------------- */
|
||
|
|
||
|
#define OP_LESS 1
|
||
|
#define OP_GREATER 2
|
||
|
#define OP_LESS_EQUAL 3
|
||
|
#define OP_GREATER_EQUAL 4
|
||
|
#define OP_EQUAL 5
|
||
|
#define OP_NOTEQUAL 6
|
||
|
|
||
|
CELL * p_less(CELL * params) { return(compareOp(params, OP_LESS)); }
|
||
|
CELL * p_greater(CELL * params) { return(compareOp(params, OP_GREATER)); }
|
||
|
CELL * p_lessEqual(CELL * params) { return(compareOp(params, OP_LESS_EQUAL)); }
|
||
|
CELL * p_greaterEqual(CELL * params) { return(compareOp(params, OP_GREATER_EQUAL)); }
|
||
|
CELL * p_equal(CELL * params) { return(compareOp(params, OP_EQUAL)); }
|
||
|
CELL * p_notEqual(CELL * params) { return(compareOp(params, OP_NOTEQUAL)); }
|
||
|
|
||
|
CELL * compareOp(CELL * params, int op)
|
||
|
{
|
||
|
CELL * left;
|
||
|
CELL * right;
|
||
|
INT cnt = 0;
|
||
|
int comp;
|
||
|
|
||
|
left = evaluateExpression(params);
|
||
|
|
||
|
while(TRUE)
|
||
|
{
|
||
|
if((params = params->next) == nilCell && cnt == 0)
|
||
|
{
|
||
|
if(isNumber(left->type))
|
||
|
right = stuffInteger64(0);
|
||
|
else if(left->type == CELL_STRING)
|
||
|
right = stuffString("");
|
||
|
else if(isList(left->type))
|
||
|
right = getCell(CELL_EXPRESSION);
|
||
|
else break;
|
||
|
pushResult(right);
|
||
|
}
|
||
|
else
|
||
|
right = evaluateExpression(params);
|
||
|
++cnt;
|
||
|
if((comp = compareCells(left, right)) == 9)
|
||
|
return( (op == OP_NOTEQUAL) ? trueCell : nilCell);
|
||
|
|
||
|
switch(op)
|
||
|
{
|
||
|
case OP_LESS:
|
||
|
if(comp >= 0) return(nilCell);
|
||
|
break;
|
||
|
case OP_GREATER:
|
||
|
if(comp <= 0) return(nilCell);
|
||
|
break;
|
||
|
case OP_LESS_EQUAL:
|
||
|
if(comp > 0) return(nilCell);
|
||
|
break;
|
||
|
case OP_GREATER_EQUAL:
|
||
|
if(comp < 0) return(nilCell);
|
||
|
break;
|
||
|
case OP_EQUAL:
|
||
|
if(comp != 0) return(nilCell);
|
||
|
break;
|
||
|
case OP_NOTEQUAL:
|
||
|
if(comp == 0) return(nilCell);
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(params->next == nilCell) break;
|
||
|
left = right;
|
||
|
}
|
||
|
|
||
|
return(trueCell);
|
||
|
}
|
||
|
|
||
|
int compareSymbols(CELL * left, CELL * right)
|
||
|
{
|
||
|
SYMBOL * leftS;
|
||
|
SYMBOL * rightS;
|
||
|
char * lcName;
|
||
|
char * rcName;
|
||
|
char * lsName;
|
||
|
char * rsName;
|
||
|
int comp;
|
||
|
|
||
|
if(left->contents == (UINT)nilSymbol)
|
||
|
{
|
||
|
if(right->contents == left->contents)return(0);
|
||
|
else return(-1);
|
||
|
}
|
||
|
|
||
|
if(left->contents == (UINT)trueSymbol)
|
||
|
{
|
||
|
if(left->contents == right->contents) return(0);
|
||
|
if(right->contents == (UINT)nilSymbol) return(1);
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
if(right->contents == (UINT)nilSymbol || right->contents == (UINT)trueSymbol)
|
||
|
return(1);
|
||
|
|
||
|
if(left->contents == right->contents) return(0);
|
||
|
|
||
|
/* else compare context- and symbol- names */
|
||
|
|
||
|
if(left->type == CELL_SYMBOL)
|
||
|
{
|
||
|
leftS = (SYMBOL *)left->contents;
|
||
|
lcName = ((SYMBOL *)leftS->context)->name;
|
||
|
lsName = leftS->name;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lcName = ((SYMBOL *)left->aux)->name;
|
||
|
lsName = (char *)left->contents;
|
||
|
}
|
||
|
|
||
|
if(right->type == CELL_SYMBOL)
|
||
|
{
|
||
|
rightS = (SYMBOL *)right->contents;
|
||
|
rcName = ((SYMBOL *)rightS->context)->name;
|
||
|
rsName = rightS->name;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rcName = ((SYMBOL *)right->aux)->name;
|
||
|
rsName = (char *)right->contents;
|
||
|
}
|
||
|
|
||
|
if((comp = strcmp(lcName, rcName)) == 0)
|
||
|
{
|
||
|
if((comp = strcmp(lsName, rsName)) == 0) return(0);
|
||
|
}
|
||
|
|
||
|
return (comp > 0 ? 1 : -1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* returns equal: 0 less: -1 greater: 1 or 9 if NaN or Inf equal comparison */
|
||
|
int compareCells(CELL * left, CELL * right)
|
||
|
{
|
||
|
int comp;
|
||
|
if(left->type != right->type)
|
||
|
{
|
||
|
if(left->type == CELL_FLOAT && ((right->type & COMPARE_TYPE_MASK) == CELL_INT))
|
||
|
return(compareFloats(left, right));
|
||
|
if(((left->type & COMPARE_TYPE_MASK) == CELL_INT) && right->type == CELL_FLOAT)
|
||
|
return(compareFloats(left, right));
|
||
|
|
||
|
if((left->type & COMPARE_TYPE_MASK) == CELL_INT && (right->type & COMPARE_TYPE_MASK) == CELL_INT)
|
||
|
return(compareInts(left, right));
|
||
|
|
||
|
if(isNil(left))
|
||
|
{
|
||
|
if(isNil(right)) return(0);
|
||
|
else return(-1);
|
||
|
}
|
||
|
|
||
|
if(isTrue(left))
|
||
|
{
|
||
|
if(isTrue(right)) return(0);
|
||
|
if(isNil(right)) return(1);
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
if(isNil(right) || isTrue(right))
|
||
|
return(1);
|
||
|
|
||
|
if(isSymbol(left->type) && isSymbol(right->type))
|
||
|
return(compareSymbols(left, right));
|
||
|
|
||
|
if( (left->type == CELL_SYMBOL && right->type == CELL_CONTEXT) ||
|
||
|
(left->type == CELL_CONTEXT && right->type == CELL_SYMBOL) )
|
||
|
{
|
||
|
if((comp = strcmp( ((SYMBOL *)left->contents)->name,
|
||
|
((SYMBOL *)right->contents)->name)) == 0) return(0);
|
||
|
return (comp > 0 ? 1 : -1);
|
||
|
}
|
||
|
|
||
|
comp = (left->type & COMPARE_TYPE_MASK) - (right->type & COMPARE_TYPE_MASK);
|
||
|
if(comp == 0) return(0);
|
||
|
|
||
|
return( comp > 0 ? 1 : -1);
|
||
|
}
|
||
|
|
||
|
/* left type and right type are the same */
|
||
|
switch(left->type)
|
||
|
{
|
||
|
case CELL_STRING:
|
||
|
comp = left->aux - right->aux;
|
||
|
if(comp == 0)
|
||
|
{
|
||
|
if((comp = memcmp((char *)left->contents,
|
||
|
(char *)right->contents,
|
||
|
left->aux)) == 0) return(0);
|
||
|
}
|
||
|
else if(comp > 0)
|
||
|
{
|
||
|
if((comp = memcmp((char *)left->contents,
|
||
|
(char *)right->contents,
|
||
|
right->aux - 1)) == 0)
|
||
|
return(1);
|
||
|
}
|
||
|
else if(comp < 0)
|
||
|
{
|
||
|
if((comp = memcmp((char *)left->contents,
|
||
|
(char *)right->contents,
|
||
|
left->aux - 1)) == 0)
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
return (comp > 0 ? 1 : -1);
|
||
|
|
||
|
case CELL_SYMBOL:
|
||
|
case CELL_DYN_SYMBOL:
|
||
|
return(compareSymbols(left, right));
|
||
|
|
||
|
case CELL_QUOTE:
|
||
|
case CELL_EXPRESSION:
|
||
|
case CELL_LAMBDA:
|
||
|
case CELL_FEXPR:
|
||
|
return(compareLists((CELL*)left->contents, (CELL*)right->contents));
|
||
|
case CELL_ARRAY:
|
||
|
return(compareArrays((CELL*)left, (CELL*)right));
|
||
|
case CELL_FLOAT:
|
||
|
return(compareFloats(left, right));
|
||
|
#ifndef NEWLISP64
|
||
|
case CELL_INT64:
|
||
|
if(*(INT64 *)&left->aux > *(INT64 *)&right->aux) return(1);
|
||
|
if(*(INT64 *)&left->aux < *(INT64 *)&right->aux) return(-1);
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef BIGINT
|
||
|
case CELL_BIGINT:
|
||
|
comp = cmpBigint((int *)(UINT)left->contents,
|
||
|
left->aux - 1, (int *)(UINT)right->contents, right->aux - 1);
|
||
|
return(comp);
|
||
|
#endif
|
||
|
case CELL_LONG:
|
||
|
default:
|
||
|
if((INT)left->contents > (INT)right->contents) return(1);
|
||
|
if((INT)left->contents < (INT)right->contents) return(-1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
int compareLists(CELL * left, CELL * right)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
while(left != nilCell)
|
||
|
{
|
||
|
if( (result = compareCells(left, right)) != 0)
|
||
|
return(result);
|
||
|
left = left->next;
|
||
|
right = right->next;
|
||
|
}
|
||
|
if(right == nilCell) return(0);
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
/* ---------------------------- encryption -----------------------------
|
||
|
|
||
|
XOR one-pad enryption
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
void encryptPad(char *encrypted, char *data, char * key, size_t dataLen, size_t keyLen)
|
||
|
{
|
||
|
size_t i;
|
||
|
for(i = 0; i < dataLen; i++)
|
||
|
*(encrypted + i) = *(data + i) ^ *(key + i % keyLen);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_encrypt(CELL * params)
|
||
|
{
|
||
|
char * data;
|
||
|
char * key;
|
||
|
char * dataEncrypted;
|
||
|
CELL * encrypted;
|
||
|
size_t dataLen, keyLen;
|
||
|
|
||
|
getStringSize(params, &data, &dataLen, TRUE);
|
||
|
getStringSize(params->next, &key, &keyLen, TRUE);
|
||
|
|
||
|
if(!keyLen) return(errorProcExt(ERR_STRING_EXPECTED, params->next));
|
||
|
|
||
|
dataEncrypted = (char *)allocMemory(dataLen + 1);
|
||
|
*(dataEncrypted + dataLen) = 0;
|
||
|
|
||
|
encryptPad(dataEncrypted, data, key, dataLen, keyLen);
|
||
|
|
||
|
encrypted = getCell(CELL_STRING);
|
||
|
encrypted->contents = (UINT)dataEncrypted;
|
||
|
encrypted->aux = dataLen + 1;
|
||
|
|
||
|
return(encrypted);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* ============================= Fast Fourier Transform ======================== */
|
||
|
|
||
|
CELL * fft(CELL * params, int isign);
|
||
|
CELL * makeListFromFloats(double num1, double num2);
|
||
|
void fastFourierTransform(double data[], unsigned int nn, int isign);
|
||
|
|
||
|
CELL * p_fft(CELL * params)
|
||
|
{
|
||
|
return fft(params, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_ifft(CELL * params)
|
||
|
{
|
||
|
return fft(params, -1);
|
||
|
}
|
||
|
|
||
|
CELL * fft(CELL * params, int isign)
|
||
|
{
|
||
|
CELL * listData;
|
||
|
CELL * list;
|
||
|
CELL * cell;
|
||
|
double * data;
|
||
|
unsigned int i, n, N;
|
||
|
|
||
|
getListHead(params, &listData);
|
||
|
|
||
|
n = listlen(listData);
|
||
|
|
||
|
N = 1;
|
||
|
while(N < n) N <<= 1;
|
||
|
|
||
|
data = (double *)allocMemory(N * 2 * sizeof(double));
|
||
|
list = listData;
|
||
|
for(i = 0; i < n*2; i+=2)
|
||
|
{
|
||
|
if(isNumber(list->type))
|
||
|
{
|
||
|
data[i] = getDirectFloat(list);
|
||
|
data[i+1] = (double)0.0;
|
||
|
list = list->next;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(list->type != CELL_EXPRESSION)
|
||
|
{
|
||
|
freeMemory(data);
|
||
|
return(errorProcExt(ERR_LIST_OR_NUMBER_EXPECTED, list));
|
||
|
}
|
||
|
|
||
|
cell = (CELL *)list->contents;
|
||
|
data[i] = getDirectFloat(cell);
|
||
|
data[i+1] = getDirectFloat(cell->next);
|
||
|
list= list->next;
|
||
|
}
|
||
|
|
||
|
|
||
|
for(i = n * 2; i < N * 2; i++)
|
||
|
data[i] = 0.0;
|
||
|
|
||
|
fastFourierTransform(data, N, isign);
|
||
|
|
||
|
list = listData = getCell(CELL_EXPRESSION);
|
||
|
if(isign == -1)
|
||
|
for(i = 0; i < n * 2; i++) data[i] = data[i]/N;
|
||
|
|
||
|
list->contents = (UINT)makeListFromFloats(data[0], data[1]);
|
||
|
list = (CELL*)list->contents;
|
||
|
for(i = 2; i < N * 2; i += 2)
|
||
|
{
|
||
|
list->next = makeListFromFloats(data[i], data[i+1]);
|
||
|
list = list->next;
|
||
|
}
|
||
|
|
||
|
freeMemory(data);
|
||
|
|
||
|
return(listData);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * makeListFromFloats(double num1, double num2)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
CELL * list;
|
||
|
|
||
|
list = getCell(CELL_EXPRESSION);
|
||
|
list->contents = (UINT)stuffFloat(num1);
|
||
|
cell = (CELL *)list->contents;
|
||
|
cell->next = stuffFloat(num2);
|
||
|
return(list);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Fast Fourier Transform
|
||
|
// algorithm modified for zero-offset data[] and double precision from
|
||
|
//
|
||
|
// Numerical Recipes in 'C', 2nd Edition
|
||
|
// W.H. Press, S.A. Teukolsky
|
||
|
// W.T. Vettering, B.P. Flannery
|
||
|
// Cambridge University Press, 1992
|
||
|
*/
|
||
|
|
||
|
#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
|
||
|
|
||
|
void fastFourierTransform(double data[], unsigned int nn, int isign)
|
||
|
{
|
||
|
unsigned int n, mmax, m, j, istep, i;
|
||
|
double wtemp, wr, wpr, wpi, wi, theta;
|
||
|
double tempr, tempi;
|
||
|
|
||
|
n = nn << 1;
|
||
|
j = 1;
|
||
|
|
||
|
for(i = 1; i < n; i += 2)
|
||
|
{
|
||
|
if(j > i)
|
||
|
{
|
||
|
SWAP(data[j-1], data[i-1]);
|
||
|
SWAP(data[j], data[i]);
|
||
|
}
|
||
|
m = n >> 1;
|
||
|
while(m >= 2 && j > m)
|
||
|
{
|
||
|
j -= m;
|
||
|
m >>= 1;
|
||
|
}
|
||
|
j += m;
|
||
|
}
|
||
|
|
||
|
|
||
|
mmax = 2;
|
||
|
while(n > mmax)
|
||
|
{
|
||
|
istep = mmax << 1;
|
||
|
theta = isign * (6.28318530717959/mmax);
|
||
|
wtemp = sin(0.5 * theta);
|
||
|
wpr = -2.0 * wtemp * wtemp;
|
||
|
wpi = sin(theta);
|
||
|
wr = 1.0;
|
||
|
wi = 0.0;
|
||
|
for(m = 1; m < mmax; m += 2)
|
||
|
{
|
||
|
for(i = m; i <= n; i += istep)
|
||
|
{
|
||
|
j = i + mmax;
|
||
|
tempr = wr * data[j-1] - wi * data[j];
|
||
|
tempi = wr * data[j] + wi * data[j-1];
|
||
|
data[j-1] = data[i-1] - tempr;
|
||
|
data[j] = data[i] - tempi;
|
||
|
data[i-1] += tempr;
|
||
|
data[i] += tempi;
|
||
|
}
|
||
|
wtemp = wr;
|
||
|
wr = wtemp * wpr - wi * wpi + wr;
|
||
|
wi = wi * wpr + wtemp * wpi + wi;
|
||
|
}
|
||
|
mmax = istep;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* --------------------------- probability distributions ----------------- */
|
||
|
|
||
|
#define DIST_RANDOM 0
|
||
|
#define DIST_NORMAL 1
|
||
|
|
||
|
double getRandom(double offset, double scale, int type)
|
||
|
{
|
||
|
int i;
|
||
|
double randnum;
|
||
|
|
||
|
if(type == DIST_RANDOM)
|
||
|
{
|
||
|
randnum = my_random();
|
||
|
return(scale * randnum/max_rand + offset);
|
||
|
}
|
||
|
|
||
|
if(type == DIST_NORMAL)
|
||
|
{
|
||
|
randnum = 0.0;
|
||
|
for(i = 0; i < 12; i++)
|
||
|
randnum += my_random() % 1024;
|
||
|
return(scale * (randnum - 6144 + 6)/1024 + offset);
|
||
|
}
|
||
|
|
||
|
return(0.0);
|
||
|
}
|
||
|
|
||
|
CELL * randomDist(CELL * params, int type)
|
||
|
{
|
||
|
double randnum;
|
||
|
size_t i;
|
||
|
size_t n = 0;
|
||
|
double scale = 1.0;
|
||
|
double offset = 0.0;
|
||
|
CELL * dist;
|
||
|
CELL * cell;
|
||
|
|
||
|
if(params->type != CELL_NIL)
|
||
|
{
|
||
|
params = getFloat(params, &offset);
|
||
|
params = getFloat(params, &scale);
|
||
|
if(params->type != CELL_NIL)
|
||
|
getInteger(params, (UINT*)&n);
|
||
|
}
|
||
|
|
||
|
if( n == 0)
|
||
|
{
|
||
|
randnum = getRandom(offset, scale, type);
|
||
|
return(stuffFloat(randnum));
|
||
|
}
|
||
|
|
||
|
dist = getCell(CELL_EXPRESSION);
|
||
|
randnum = getRandom(offset, scale, type);
|
||
|
dist->contents = (UINT)stuffFloat(randnum);
|
||
|
cell = (CELL*)dist->contents;
|
||
|
for(i = 1; i < n; i++)
|
||
|
{
|
||
|
randnum = getRandom(offset, scale, type);
|
||
|
cell->next = stuffFloat(randnum);
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
|
||
|
return(dist);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_normal(CELL * params)
|
||
|
{
|
||
|
return(randomDist(params, DIST_NORMAL));
|
||
|
}
|
||
|
|
||
|
CELL * p_random(CELL * params)
|
||
|
{
|
||
|
return(randomDist(params, DIST_RANDOM));
|
||
|
}
|
||
|
|
||
|
CELL * p_randomize(CELL * params)
|
||
|
{
|
||
|
CELL * list;
|
||
|
CELL * cell;
|
||
|
CELL * * vector;
|
||
|
size_t length, i, j;
|
||
|
INT rnum;
|
||
|
double scale;
|
||
|
|
||
|
getListHead(params, &list);
|
||
|
|
||
|
if((length = listlen(list)) <= 1)
|
||
|
return(makeCell(CELL_EXPRESSION, (UINT)copyList(list)));
|
||
|
|
||
|
/* build index vector */
|
||
|
cell = list;
|
||
|
vector = allocMemory(length * sizeof(UINT));
|
||
|
for(i = 0; i < length; i++)
|
||
|
{
|
||
|
vector[i] = copyCell(cell);
|
||
|
vector[i]->next = (void *)i;
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
|
||
|
/* reorganize randomly */
|
||
|
RANDOMIZE:
|
||
|
for(i = 0; i < (length - 1); i++)
|
||
|
{
|
||
|
scale = length - i;
|
||
|
while((rnum = my_random()) == max_rand);
|
||
|
rnum = (scale * rnum)/max_rand;
|
||
|
j = i + rnum;
|
||
|
cell = vector[i];
|
||
|
vector[i] = vector[j];
|
||
|
vector[j] = cell;
|
||
|
}
|
||
|
|
||
|
/* check that new sequence is different
|
||
|
for default no flag or nil flag */
|
||
|
if(!getFlag(params->next))
|
||
|
{
|
||
|
for(i = 0; i < length; i++)
|
||
|
if(vector[i]->next != (void *)i) break;
|
||
|
|
||
|
if(i == length) goto RANDOMIZE;
|
||
|
}
|
||
|
|
||
|
/* relink the list */
|
||
|
cell = list = getCell(CELL_EXPRESSION);
|
||
|
cell->contents = (UINT)vector[0];
|
||
|
cell = (CELL *)cell->contents;
|
||
|
for(i = 1; i < length; i++)
|
||
|
{
|
||
|
cell->next = vector[i];
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
cell->next = nilCell;
|
||
|
freeMemory(vector);
|
||
|
|
||
|
return(list);
|
||
|
}
|
||
|
|
||
|
CELL * probability_x(CELL * params, int type);
|
||
|
double probChi2(double chi2, UINT df);
|
||
|
double probT(double t, UINT df);
|
||
|
double probF(double t, UINT df1, UINT df2);
|
||
|
double critical_value(double p, UINT df1, UINT df2, double max_val, int type);
|
||
|
double gammaln(double xx);
|
||
|
double betai(double a, double b, double x);
|
||
|
double gammap(double a, double x);
|
||
|
double betacf(double a, double b, double x);
|
||
|
static double gser(double a, double x, double gln);
|
||
|
double gcf(double a, double x, double gln);
|
||
|
|
||
|
#define SQRT2 1.414213562373095
|
||
|
|
||
|
CELL * p_probabilityZ(CELL * params)
|
||
|
{
|
||
|
double z;
|
||
|
double p;
|
||
|
|
||
|
getFloat(params, &z);
|
||
|
|
||
|
p = 0.5 + erf(z/SQRT2) / 2.0;
|
||
|
|
||
|
return(stuffFloat(p));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_criticalZ(CELL * params)
|
||
|
{
|
||
|
double p;
|
||
|
double sign = 1.0;
|
||
|
#define Z_EPSILON 0.000001 /* Accuracy of Z approximation */
|
||
|
double minZ = 0.0;
|
||
|
double maxZ = 6.0;
|
||
|
double Zval;
|
||
|
double Z;
|
||
|
|
||
|
getFloat(params, &p);
|
||
|
|
||
|
if (p < 0.5)
|
||
|
{
|
||
|
p = 1.0 - p;
|
||
|
sign = -1.0;
|
||
|
}
|
||
|
|
||
|
Zval = 2.0; /* fair first value */
|
||
|
while ((maxZ - minZ) > Z_EPSILON)
|
||
|
{
|
||
|
if ( (0.5 + erf(Zval/SQRT2) / 2.0) < p) minZ = Zval;
|
||
|
else maxZ = Zval;
|
||
|
Zval = (maxZ + minZ) * 0.5;
|
||
|
}
|
||
|
|
||
|
Z = (Zval > 5.999999) ? sign * 6.0 : Zval * sign;
|
||
|
|
||
|
return(stuffFloat(Z));
|
||
|
}
|
||
|
|
||
|
|
||
|
double probChi2(double chi2, UINT df)
|
||
|
{
|
||
|
return(gammap(df/2.0, chi2/2.0));
|
||
|
}
|
||
|
|
||
|
|
||
|
double probT(double t, UINT df)
|
||
|
{
|
||
|
double bta;
|
||
|
|
||
|
bta = betai(df/2.0, 0.5, 1.0/(1.0 + t*t/df));
|
||
|
if(t > 0.0) return(1.0 - 0.5 * bta);
|
||
|
else if(t < 0.0) return(0.5 * bta);
|
||
|
return(0.5);
|
||
|
}
|
||
|
|
||
|
double probF(double f, UINT df1, UINT df2)
|
||
|
{
|
||
|
double prob;
|
||
|
|
||
|
prob = 2.0 * betai(0.5 * df2, 0.5 * df1, df2 / (df2 + df1 * f));
|
||
|
|
||
|
if(prob > 1) prob = 2.0 - prob;
|
||
|
return(prob / 2.0);
|
||
|
}
|
||
|
|
||
|
#define STAT_CHI2 1
|
||
|
#define STAT_T 2
|
||
|
#define STAT_F 3
|
||
|
|
||
|
CELL * p_probabilityChi2(CELL * params)
|
||
|
{
|
||
|
return(probability_x(params, STAT_CHI2));
|
||
|
}
|
||
|
|
||
|
CELL * p_probabilityT(CELL * params)
|
||
|
{
|
||
|
return(probability_x(params, STAT_T));
|
||
|
}
|
||
|
|
||
|
CELL * p_probabilityF(CELL * params)
|
||
|
{
|
||
|
return(probability_x(params, STAT_F));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * probability_x(CELL * params, int type)
|
||
|
{
|
||
|
double x;
|
||
|
UINT df1;
|
||
|
UINT df2;
|
||
|
double prob = 0.0;
|
||
|
|
||
|
params = getFloat(params, &x);
|
||
|
params = getInteger(params, &df1);
|
||
|
if(type == STAT_F)
|
||
|
getInteger(params, &df2);
|
||
|
|
||
|
switch(type)
|
||
|
{
|
||
|
case STAT_CHI2:
|
||
|
prob = 1.0 - probChi2(x, df1);
|
||
|
break;
|
||
|
case STAT_T:
|
||
|
prob = 1.0 - probT(x, df1);
|
||
|
break;
|
||
|
case STAT_F:
|
||
|
prob = probF(x, df1, df2);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(stuffFloat(prob));
|
||
|
}
|
||
|
|
||
|
|
||
|
double critical_value(double p, UINT df1, UINT df2, double max_val, int type)
|
||
|
{
|
||
|
#define NEWTON_EPSILON 0.000001 /* Accuracy of Newton approximation */
|
||
|
double minval = 0.0;
|
||
|
double maxval = max_val;
|
||
|
double critval;
|
||
|
double prob = 0.0;
|
||
|
|
||
|
if (p <= 0.0) return 0.0;
|
||
|
else if (p >= 1.0) return maxval;
|
||
|
|
||
|
critval = (df1 + df2) / sqrt(p); /* fair first value */
|
||
|
while ((maxval - minval) > NEWTON_EPSILON)
|
||
|
{
|
||
|
switch(type)
|
||
|
{
|
||
|
case STAT_CHI2:
|
||
|
prob = probChi2(critval, df1);
|
||
|
break;
|
||
|
case STAT_T:
|
||
|
prob = probT(critval, df1);
|
||
|
break;
|
||
|
case STAT_F:
|
||
|
prob = 1.0 - probF(critval, df1, df2);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
if (prob < p) minval = critval;
|
||
|
else maxval = critval;
|
||
|
critval = (maxval + minval) * 0.5;
|
||
|
}
|
||
|
|
||
|
return critval;
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * criticalX(CELL * params, int type)
|
||
|
{
|
||
|
double p;
|
||
|
UINT df1;
|
||
|
UINT df2 = 0;
|
||
|
double x;
|
||
|
|
||
|
params = getFloat(params, &p);
|
||
|
params = getInteger(params, &df1);
|
||
|
if(type == STAT_F) getInteger(params, &df2);
|
||
|
|
||
|
x = critical_value((1.0 - p), df1, df2, 99999.0, type);
|
||
|
|
||
|
if(x < NEWTON_EPSILON) x = 0.0;
|
||
|
|
||
|
return(stuffFloat(x));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_criticalChi2(CELL * params)
|
||
|
{
|
||
|
return(criticalX(params, STAT_CHI2));
|
||
|
}
|
||
|
|
||
|
CELL * p_criticalT(CELL * params)
|
||
|
{
|
||
|
return(criticalX(params, STAT_T));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_criticalF(CELL * params)
|
||
|
{
|
||
|
return(criticalX(params, STAT_F));
|
||
|
}
|
||
|
|
||
|
/* Built-in versions for random() and srandom() are used only
|
||
|
when 'seed' was called with extra 'true' value. Guarantees
|
||
|
platform and compiler/libc indepedence when needed for some
|
||
|
applications. '(seed)' then can be used to retrieve state,
|
||
|
'(seed num true N)' can be used to set 'nshuff', which should
|
||
|
be 0 to when starting with a previously saved state seed.
|
||
|
|
||
|
Adapted from FreeBSD:
|
||
|
http://fxr.watson.org/fxr/source/libkern/random.c
|
||
|
result is uniform on [0, 2^31 - 1].
|
||
|
*/
|
||
|
|
||
|
|
||
|
UINT nshuff = 50; /* to drop some "seed -> 1st value" linearity */
|
||
|
uint32_t randseed = 937186357; /* after srandom(1), NSHUFF=50 counted */
|
||
|
int my_random_flag = 0; /* if not set, call libc version */
|
||
|
|
||
|
void my_srandom(uint32_t seed)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if(my_random_flag == 0) srandom(seed);
|
||
|
else
|
||
|
{
|
||
|
randseed = seed;
|
||
|
for (i = 0; i < nshuff; i++)
|
||
|
my_random();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32_t my_random()
|
||
|
{
|
||
|
int32_t x, hi, lo, t;
|
||
|
|
||
|
if(my_random_flag == 0) return(random());
|
||
|
|
||
|
/*
|
||
|
* Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
|
||
|
* From "Random number generators: good ones are hard to find",
|
||
|
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
|
||
|
* October 1988, p. 1195. (from FreeBSD code base)
|
||
|
*/
|
||
|
|
||
|
if ((x = randseed) == 0) x = 123459876;
|
||
|
hi = x / 127773;
|
||
|
lo = x % 127773;
|
||
|
t = 16807 * lo - 2836 * hi;
|
||
|
if (t < 0) t += 0x7fffffff;
|
||
|
randseed = t;
|
||
|
return (t);
|
||
|
}
|
||
|
|
||
|
#ifdef ALTERNATIVE_MY_RANDOM /* used for EMSCRIPTEN before v1.29 */
|
||
|
int m_w = 0x12345678; /* must not be zero, nor 0x464fffff */
|
||
|
int m_z = 0x23456789; /* must not be zero, nor 0x9068ffff */
|
||
|
|
||
|
long int random(void)
|
||
|
{
|
||
|
m_z = 36969 * (m_z & 65535) + (m_z >> 16);
|
||
|
m_w = 18000 * (m_w & 65535) + (m_w >> 16);
|
||
|
return (((m_z << 16) + m_w) & 0x7fffffff); /* 31-bit result */
|
||
|
}
|
||
|
|
||
|
void srandom(unsigned int init)
|
||
|
{
|
||
|
m_z = init;
|
||
|
m_w = 3 * init;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* ----------------------- betai and gammaln fucntions ----------------------*/
|
||
|
|
||
|
|
||
|
static int paramError;
|
||
|
|
||
|
CELL * p_beta(CELL * params)
|
||
|
{
|
||
|
double a, b, beta;
|
||
|
|
||
|
params = getFloat(params, &a);
|
||
|
getFloat(params, &b);
|
||
|
|
||
|
beta = exp(gammaln(a) + gammaln(b) - gammaln(a+b));
|
||
|
|
||
|
return(stuffFloat(beta));
|
||
|
}
|
||
|
|
||
|
CELL * p_betai(CELL * params)
|
||
|
{
|
||
|
double a, b, x, result;
|
||
|
|
||
|
params = getFloat(params, &x);
|
||
|
params = getFloat(params, &a);
|
||
|
getFloat(params, &b);
|
||
|
|
||
|
paramError = 0;
|
||
|
|
||
|
result = betai(a,b,x);
|
||
|
|
||
|
if(paramError)
|
||
|
return(nilCell);
|
||
|
|
||
|
return(stuffFloat(result));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_gammaln(CELL * params)
|
||
|
{
|
||
|
double x, result;
|
||
|
|
||
|
getFloat(params, &x);
|
||
|
|
||
|
paramError = 0;
|
||
|
|
||
|
result = gammaln(x);
|
||
|
|
||
|
if(paramError)
|
||
|
return(nilCell);
|
||
|
|
||
|
return(stuffFloat(result));
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_gammai(CELL * params)
|
||
|
{
|
||
|
double a, x, result;
|
||
|
|
||
|
params = getFloat(params, &a);
|
||
|
getFloat(params, &x);
|
||
|
|
||
|
result = gammap(a, x);
|
||
|
|
||
|
/*
|
||
|
printf("in p_gammai() result = %f\n", result);
|
||
|
*/
|
||
|
|
||
|
return(stuffFloat(result));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* these functions are adapted from:
|
||
|
Numerical Recipes in C
|
||
|
W.H.Press, S.A. Teukolsky, W.T. Vettering, B.P. Flannery
|
||
|
Cambridge University Press (c) 1992
|
||
|
*/
|
||
|
|
||
|
#define ITMAX 100
|
||
|
#define EPS7 3.0e-7
|
||
|
|
||
|
double betai(double a, double b, double x)
|
||
|
{
|
||
|
double bt;
|
||
|
|
||
|
if (x < 0.0 || x > 1.0)
|
||
|
{
|
||
|
paramError = 1;
|
||
|
return(0.0);
|
||
|
}
|
||
|
|
||
|
if (x == 0.0 || x == 1.0)
|
||
|
bt = 0.0;
|
||
|
else
|
||
|
bt = exp(gammaln(a+b)-gammaln(a)-gammaln(b)+a*log(x)+b*log(1.0-x));
|
||
|
|
||
|
if (x < (a+1.0)/(a+b+2.0))
|
||
|
return (bt * betacf(a,b,x) / a);
|
||
|
else
|
||
|
return (1.0 - bt * betacf(b,a,1.0-x) / b);
|
||
|
}
|
||
|
|
||
|
|
||
|
double betacf(double a, double b, double x)
|
||
|
{
|
||
|
double qap,qam,qab,em,tem,d;
|
||
|
double bz,bm,bp,bpp;
|
||
|
double az,am,ap,app,aold;
|
||
|
int m;
|
||
|
|
||
|
bm = az = am = 1.0;
|
||
|
qab=a+b;
|
||
|
qap=a+1.0;
|
||
|
qam=a-1.0;
|
||
|
bz=1.0-qab*x/qap;
|
||
|
for (m=1;m<=ITMAX;m++)
|
||
|
{
|
||
|
em=(double) m;
|
||
|
tem=em+em;
|
||
|
d=em*(b-em)*x/((qam+tem)*(a+tem));
|
||
|
ap=az+d*am;
|
||
|
bp=bz+d*bm;
|
||
|
d = -(a+em)*(qab+em)*x/((qap+tem)*(a+tem));
|
||
|
app=ap+d*az;
|
||
|
bpp=bp+d*bz;
|
||
|
aold=az;
|
||
|
am=ap/bpp;
|
||
|
bm=bp/bpp;
|
||
|
az=app/bpp;
|
||
|
bz=1.0;
|
||
|
if (fabs(az-aold) < (EPS7 * fabs(az))) return az;
|
||
|
}
|
||
|
|
||
|
return(paramError = 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
double gammaln(double xx)
|
||
|
{
|
||
|
double x,y,tmp,ser;
|
||
|
static double cof[6] = {
|
||
|
76.18009172947146,
|
||
|
-86.50532032941677,
|
||
|
24.01409824083091,
|
||
|
-1.231739572450155,
|
||
|
0.1208650973866179e-2,
|
||
|
-0.5395239384953e-5};
|
||
|
|
||
|
int j;
|
||
|
|
||
|
if(xx == 0.0)
|
||
|
fatalError(ERR_INVALID_PARAMETER_0, NULL, 0);
|
||
|
|
||
|
y=x=xx;
|
||
|
tmp=x+5.5;
|
||
|
tmp -= (x+0.5)*log(tmp);
|
||
|
ser=1.000000000190015;
|
||
|
|
||
|
for (j=0;j<=5;j++) ser += cof[j]/++y;
|
||
|
|
||
|
return -tmp+log(2.5066282746310005*ser/x);
|
||
|
}
|
||
|
|
||
|
|
||
|
#define EPS9 3.0e-9
|
||
|
#define FPMIN 1.0e-307
|
||
|
|
||
|
/* incomplete Gamma function
|
||
|
//
|
||
|
// gammap = P(a,x)
|
||
|
// gammaq = Q(a,x) = 1.0 - P(a,x)
|
||
|
//
|
||
|
// prob-chi2 = gammap(df/2, chi2/2)
|
||
|
// of beeing as good as observed (>=)
|
||
|
*/
|
||
|
double gammap(double a, double x)
|
||
|
{
|
||
|
double gln;
|
||
|
gln = gammaln(a);
|
||
|
#ifdef DEBUG
|
||
|
/* horrible error on LLVM 32-bit Apple update Oct 7, 2010, fine on LLVM 64-bit
|
||
|
result is fine in printf() but gets passed up as NaN to gammai() by return() */
|
||
|
printf("in gammap() result %f\n", (x < (a + 1.0)) ? gser(a, x, gln) : (1.0 - gcf(a ,x , gln)));
|
||
|
#endif
|
||
|
return( (x < (a + 1.0)) ? gser(a, x, gln) : (1.0 - gcf(a ,x , gln)) );
|
||
|
}
|
||
|
|
||
|
|
||
|
static double gser(double a, double x, double gln)
|
||
|
{
|
||
|
double ap, del, sum;
|
||
|
int n;
|
||
|
|
||
|
ap = a;
|
||
|
del = 1.0/a;
|
||
|
sum = del;
|
||
|
|
||
|
for (n = 1 ; n <= ITMAX ; n++)
|
||
|
{
|
||
|
++ap;
|
||
|
del *= x / ap;
|
||
|
sum += del;
|
||
|
if (fabs(del) < fabs(sum) * EPS9)
|
||
|
return sum * exp(-x + a * log(x) - gln);
|
||
|
}
|
||
|
|
||
|
return sum * exp(-x + a * log(x) - gln);
|
||
|
}
|
||
|
|
||
|
|
||
|
double gcf(double a, double x, double gln)
|
||
|
{
|
||
|
double b, c, d, h, an, del;
|
||
|
int i;
|
||
|
|
||
|
b = x + 1 - a;
|
||
|
c = 1.0/FPMIN;
|
||
|
d = 1.0/b;
|
||
|
h = d;
|
||
|
|
||
|
for (i = 1 ; i <= ITMAX ; i++)
|
||
|
{
|
||
|
an = -i * (i - a);
|
||
|
b += 2;
|
||
|
|
||
|
d = an * d + b;
|
||
|
if (fabs(d) < FPMIN) d = FPMIN;
|
||
|
|
||
|
c = b + an/c;
|
||
|
if (fabs(c) < FPMIN) c = FPMIN;
|
||
|
|
||
|
d = 1.0/d;
|
||
|
del = d * c;
|
||
|
h *= del;
|
||
|
if (fabs(del-1.0) < EPS9) break;
|
||
|
}
|
||
|
|
||
|
return exp(-x + a * log(x) - gln) * h;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------- Binomial distribution -------------------- */
|
||
|
|
||
|
CELL * p_binomial(CELL * params)
|
||
|
{
|
||
|
INT n, k;
|
||
|
double bico, p, binomial;
|
||
|
|
||
|
params = getInteger(params, (UINT *)&n);
|
||
|
params = getInteger(params, (UINT *)&k);
|
||
|
getFloat(params, &p);
|
||
|
|
||
|
bico = exp(gammaln(n + 1.0) - gammaln(k + 1.0) - gammaln(n - k + 1.0));
|
||
|
|
||
|
binomial = bico * pow(p, (double)k) * pow(1.0 - p, (double)(n - k));
|
||
|
|
||
|
return(stuffFloat(binomial));
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------------------------------------------- */
|
||
|
|
||
|
CELL * p_series(CELL * params)
|
||
|
{
|
||
|
double fromFlt, factFlt;
|
||
|
ssize_t count, i;
|
||
|
CELL * series;
|
||
|
CELL * cell;
|
||
|
CELL * pCell;
|
||
|
CELL * expr;
|
||
|
CELL * cellIdx;
|
||
|
UINT * resultIdxSave;
|
||
|
jmp_buf errorJumpSave;
|
||
|
int errNo;
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
pCell = evaluateExpression(params->next);
|
||
|
params = params->next;
|
||
|
getInteger(params->next, (UINT *)&count);
|
||
|
|
||
|
series = getCell(CELL_EXPRESSION);
|
||
|
if(count <= 0) return(series);
|
||
|
|
||
|
if(isNumber(pCell->type))
|
||
|
{
|
||
|
if(!isNumber(cell->type))
|
||
|
return(errorProcExt(ERR_NUMBER_EXPECTED, cell));
|
||
|
fromFlt = getDirectFloat(cell);
|
||
|
factFlt = getDirectFloat(pCell);
|
||
|
cell = copyCell(cell);
|
||
|
series->contents = (UINT)cell;
|
||
|
for(i = 1; i < count; i++)
|
||
|
{
|
||
|
fromFlt *= factFlt;
|
||
|
cell->next = stuffFloat(fromFlt);
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
}
|
||
|
else /* assumes lambda or primitive */
|
||
|
{
|
||
|
cellIdx = initIteratorIndex();
|
||
|
addList(series, copyCell(cell));
|
||
|
resultIdxSave = resultStackIdx;
|
||
|
memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
|
||
|
if((errNo = setjmp(errorJump)) != 0)
|
||
|
{
|
||
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
||
|
deleteList(series);
|
||
|
longjmp(errorJump, errNo);
|
||
|
}
|
||
|
|
||
|
for(i = 1; i < count; i++)
|
||
|
{
|
||
|
cell = copyCell(cell);
|
||
|
cleanupResults(resultIdxSave);
|
||
|
expr = makeCell(CELL_EXPRESSION, (UINT)copyCell(pCell));
|
||
|
((CELL *)expr->contents)->next = cell;
|
||
|
pushResult(expr);
|
||
|
cell = evaluateExpression(expr);
|
||
|
addList(series, copyCell(cell));
|
||
|
if(cellIdx->type == CELL_LONG) cellIdx->contents += 1;
|
||
|
}
|
||
|
recoverIteratorIndex(cellIdx);
|
||
|
memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
|
||
|
}
|
||
|
|
||
|
series->aux = (UINT)cell; /* last element optimization */
|
||
|
return(series);
|
||
|
}
|
||
|
|
||
|
/* ------------------------------- prime numbers ---------------------------- */
|
||
|
|
||
|
/*
|
||
|
* adapted for newLISP from the following code:
|
||
|
*
|
||
|
* factor.c -- print prime factorization of a number
|
||
|
* Ray Gardner -- 1985 -- public domain
|
||
|
* Modified Feb. 1989 by Thad Smith > public domain
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
CELL * p_factor (CELL * params)
|
||
|
{
|
||
|
INT64 d, n;
|
||
|
INT k;
|
||
|
CELL * factList;
|
||
|
int i;
|
||
|
|
||
|
getInteger64Ext(params, &n, TRUE);
|
||
|
|
||
|
if (n < 2) return(nilCell);
|
||
|
|
||
|
factList = getCell(CELL_EXPRESSION);
|
||
|
|
||
|
d = 2;
|
||
|
for (k = 0; (n % d) == 0; k++)
|
||
|
n /= d;
|
||
|
for(i = 0; i < k; i++) addList(factList, stuffInteger64(d));
|
||
|
|
||
|
for (d = 3; d * d <= n; d += 2)
|
||
|
{
|
||
|
for (k = 0; (n % d) == 0; k++)
|
||
|
n /= d;
|
||
|
for(i = 0; i < k; i++) addList(factList, stuffInteger64(d));
|
||
|
}
|
||
|
|
||
|
if (n > 1)
|
||
|
addList(factList, stuffInteger64(n));
|
||
|
|
||
|
return(factList);
|
||
|
}
|
||
|
|
||
|
/* see http://en.wikipedia.org/wiki/Euclidean_algorithm */
|
||
|
|
||
|
CELL * gcdBig(CELL * a, CELL * b);
|
||
|
CELL * isZero(CELL * cell);
|
||
|
|
||
|
CELL * p_gcd(CELL * params)
|
||
|
{
|
||
|
INT64 m, n, r;
|
||
|
CELL * cell;
|
||
|
#ifdef BIGINT
|
||
|
CELL * x;
|
||
|
CELL * y;
|
||
|
UINT * resultIdxSave = resultStackIdx;
|
||
|
#endif
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
params = params->next;
|
||
|
|
||
|
#ifdef BIGINT
|
||
|
if(cell->type == CELL_BIGINT)
|
||
|
{
|
||
|
x = copyCell(cell);
|
||
|
NEXT_BIG_GCD:
|
||
|
y = p_bigInt(params);
|
||
|
cell = gcdBig(x, y);
|
||
|
cleanupResults(resultIdxSave);
|
||
|
deleteList(x);
|
||
|
deleteList(y);
|
||
|
if(params->next != nilCell)
|
||
|
{
|
||
|
params = params->next;
|
||
|
x = cell;
|
||
|
goto NEXT_BIG_GCD;
|
||
|
}
|
||
|
*(int*)cell->contents = 1; /* abs */
|
||
|
return(cell);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
cell = getInteger64Ext(cell, &m, FALSE);
|
||
|
while(params != nilCell)
|
||
|
{
|
||
|
params = getInteger64Ext(params, &n, TRUE);
|
||
|
while (n != 0)
|
||
|
{
|
||
|
r = n;
|
||
|
n = m % n;
|
||
|
m = r;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(m < 0) m = -m;
|
||
|
return(stuffInteger64(m));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* for bigint use
|
||
|
(define (gcd-big a b)
|
||
|
(if (= b 0) a (gcd-big b (% a b))))
|
||
|
*/
|
||
|
|
||
|
#define NEW_BIG_GCD
|
||
|
#ifdef NEW_BIG_GCD
|
||
|
CELL * gcdBig(CELL * a, CELL * b)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
|
||
|
while (isZero(b) == nilCell)
|
||
|
{
|
||
|
a->next = b;
|
||
|
cell = arithmetikOp(a, OP_MODULO);
|
||
|
a->next = nilCell;
|
||
|
pushResult(cell);
|
||
|
a = b;
|
||
|
b = cell;
|
||
|
}
|
||
|
|
||
|
return(copyCell(a));
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
CELL * gcdBig(CELL * a, CELL * b)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
if(isZero(b) == trueCell) return(copyCell(a));
|
||
|
|
||
|
a->next = b;
|
||
|
b->next = nilCell;
|
||
|
|
||
|
cell = arithmetikOp(a, OP_MODULO);
|
||
|
a->next = nilCell;
|
||
|
pushResult(cell);
|
||
|
|
||
|
return(gcdBig(b, cell));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* ------------------------------- financial functions ---------------------- */
|
||
|
|
||
|
|
||
|
CELL * p_pmt(CELL * params)
|
||
|
{
|
||
|
INT nper;
|
||
|
double rate, pv;
|
||
|
double fv = 0.0;
|
||
|
double pmt = 0.0;
|
||
|
double inc;
|
||
|
INT type = 0;
|
||
|
|
||
|
params = getFloat(params, &rate);
|
||
|
params = getInteger(params, (UINT *)&nper);
|
||
|
params = getFloat(params, &pv);
|
||
|
if(params != nilCell)
|
||
|
{
|
||
|
params = getFloat(params, &fv);
|
||
|
if(params != nilCell) getInteger(params, (UINT *)&type);
|
||
|
}
|
||
|
|
||
|
if(rate == 0)
|
||
|
pmt = (-pv - fv) / nper;
|
||
|
else
|
||
|
{
|
||
|
inc = pow(1 + rate, (double)nper);
|
||
|
pmt = - (pv * inc + fv) / ((1 + rate * type) * ((inc - 1) / rate));
|
||
|
}
|
||
|
|
||
|
return stuffFloat(pmt);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_pv(CELL * params)
|
||
|
{
|
||
|
INT nper;
|
||
|
double rate, pmt, pv;
|
||
|
double fv = 0.0;
|
||
|
double inc;
|
||
|
INT type = 0;
|
||
|
|
||
|
params = getFloat(params, &rate);
|
||
|
params = getInteger(params, (UINT *)&nper);
|
||
|
params = getFloat(params, &pmt);
|
||
|
|
||
|
if(params != nilCell)
|
||
|
{
|
||
|
params = getFloat(params, &fv);
|
||
|
if(params != nilCell)
|
||
|
getInteger(params, (UINT *)&type);
|
||
|
}
|
||
|
|
||
|
if(rate == 0)
|
||
|
pv = - pmt * nper - fv;
|
||
|
else
|
||
|
{
|
||
|
inc = pow(1 + rate, (double)nper);
|
||
|
pv = (-pmt * (1 + rate * type) * ((inc - 1) / rate) - fv) / inc;
|
||
|
}
|
||
|
|
||
|
return stuffFloat(pv);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_fv(CELL * params)
|
||
|
{
|
||
|
double rate, pmt, pv;
|
||
|
INT nper, type;
|
||
|
double inc, fv;
|
||
|
|
||
|
params = getFloat(params, &rate);
|
||
|
params = getInteger(params, (UINT *)&nper);
|
||
|
params = getFloat(params, &pmt);
|
||
|
params = getFloat(params, &pv);
|
||
|
if(params != nilCell)
|
||
|
getInteger(params, (UINT *)&type);
|
||
|
else type = 0;
|
||
|
|
||
|
|
||
|
if(rate == 0)
|
||
|
fv = - pmt * nper - pv;
|
||
|
else
|
||
|
{
|
||
|
inc = pow(1 + rate, (double)nper);
|
||
|
fv = -pmt * (1 + rate * type) * ((inc - 1) / rate) - pv * inc;
|
||
|
}
|
||
|
|
||
|
return stuffFloat(fv);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_nper(CELL * params)
|
||
|
{
|
||
|
double rate, pmt, pv;
|
||
|
double fv = 0.0;
|
||
|
double R, c, nper;
|
||
|
INT type = 0;
|
||
|
|
||
|
params = getFloat(params, &rate);
|
||
|
params = getFloat(params, &pmt);
|
||
|
params = getFloat(params, &pv);
|
||
|
|
||
|
if(params != nilCell)
|
||
|
{
|
||
|
params = getFloat(params, &fv);
|
||
|
if(params != nilCell) getInteger(params, (UINT *)&type);
|
||
|
}
|
||
|
|
||
|
if(rate == 0)
|
||
|
nper = (-pv - fv) / pmt;
|
||
|
else if(rate > -1.0)
|
||
|
{
|
||
|
R = 1.0 + rate;
|
||
|
c = pmt * (type ? R : 1.0) / rate;
|
||
|
nper = log((c - fv) / (c + pv)) / log(R);
|
||
|
}
|
||
|
else nper = sqrt(-1.0); /* NaN */
|
||
|
|
||
|
|
||
|
return stuffFloat(nper);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_npv(CELL * params)
|
||
|
{
|
||
|
CELL * list;
|
||
|
double rate, cashFlow, fNum;
|
||
|
int count;
|
||
|
|
||
|
params = getFloat(params, &rate);
|
||
|
list = evaluateExpression(params);
|
||
|
if(!isList(list->type))
|
||
|
return(errorProcExt(ERR_LIST_EXPECTED, params));
|
||
|
list = (CELL *)list->contents;
|
||
|
|
||
|
cashFlow = 0.0;
|
||
|
count = 0;
|
||
|
while(list != nilCell)
|
||
|
{
|
||
|
fNum = getDirectFloat(list);
|
||
|
cashFlow += fNum / pow((1.0 + rate), (double)++count);
|
||
|
list = list->next;
|
||
|
}
|
||
|
|
||
|
return stuffFloat(cashFlow);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Internal Rate of Return - irr
|
||
|
|
||
|
adapted from a C++ program by:
|
||
|
|
||
|
Bernt Arne Odegaard, 1999 http://finance.bi.no/~bernt
|
||
|
|
||
|
Note, that some data have multiple solutions, this search
|
||
|
algorithm returns only one
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
double cfPv(int N, int times[], double amounts[], double rate)
|
||
|
{
|
||
|
double PV = 0.0;
|
||
|
int t;
|
||
|
|
||
|
for(t = 0; t < N; t++)
|
||
|
PV += amounts[t] / pow((1.0 + rate), (double)times[t]);
|
||
|
|
||
|
return(PV);
|
||
|
}
|
||
|
|
||
|
|
||
|
#define PRECISION 1.0e-5
|
||
|
#define MAX_ITERATIONS 50
|
||
|
#define IRR_ERROR -1.0
|
||
|
|
||
|
double irr(int N, int times[], double amounts[], double x2)
|
||
|
{
|
||
|
double est1, est2;
|
||
|
double x1 = 0.0;
|
||
|
double f, rtb, dx;
|
||
|
double x_mid, f_mid;
|
||
|
int i;
|
||
|
|
||
|
est1 = cfPv(N, times, amounts, x1);
|
||
|
est2 = cfPv(N, times, amounts, x2);
|
||
|
|
||
|
for(i=0; i<MAX_ITERATIONS; i++)
|
||
|
{
|
||
|
if(est1 * est2 < 0.0) break;
|
||
|
|
||
|
if(fabs(est1) < fabs(est2))
|
||
|
est1 = cfPv(N, times, amounts, x1 += 1.6 * (x1 - x2));
|
||
|
else
|
||
|
est2 = cfPv(N, times, amounts, x2 += 1.6 * (x2 - x1));
|
||
|
}
|
||
|
|
||
|
if (est2 * est1 > 0.0) return (IRR_ERROR);
|
||
|
|
||
|
f = cfPv(N, times, amounts, x1);
|
||
|
dx=0;
|
||
|
|
||
|
if(f < 0.0)
|
||
|
{
|
||
|
rtb = x1;
|
||
|
dx=x2-x1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rtb = x2;
|
||
|
dx = x1-x2;
|
||
|
};
|
||
|
|
||
|
for(i = 0; i< MAX_ITERATIONS; i++)
|
||
|
{
|
||
|
dx *= 0.5;
|
||
|
x_mid = rtb + dx;
|
||
|
f_mid = cfPv(N, times, amounts, x_mid);
|
||
|
|
||
|
if(f_mid <= 0.0)
|
||
|
rtb = x_mid;
|
||
|
|
||
|
if((fabs(f_mid) < PRECISION) || (fabs(dx) < PRECISION))
|
||
|
return x_mid;
|
||
|
};
|
||
|
|
||
|
return(IRR_ERROR);
|
||
|
}
|
||
|
|
||
|
CELL * p_irr(CELL * params)
|
||
|
{
|
||
|
CELL * amounts;
|
||
|
CELL * times;
|
||
|
CELL * list;
|
||
|
double result;
|
||
|
double guess = 0.5;
|
||
|
double * amountsVec;
|
||
|
int * timesVec;
|
||
|
int i, N = 0;
|
||
|
INT number;
|
||
|
|
||
|
params = getListHead(params, &amounts);
|
||
|
list = amounts;
|
||
|
if(params != nilCell)
|
||
|
{
|
||
|
params = getListHead(params, ×);
|
||
|
if(params != nilCell)
|
||
|
getFloat(params, &guess);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
times = NULL;
|
||
|
|
||
|
while(list != nilCell)
|
||
|
{
|
||
|
++N;
|
||
|
list = list->next;
|
||
|
}
|
||
|
|
||
|
amountsVec = (double *)allocMemory(N * sizeof(double));
|
||
|
timesVec = (int *)allocMemory(N * sizeof(int));
|
||
|
|
||
|
for(i = 0; i < N; i++)
|
||
|
{
|
||
|
if(isNumber(amounts->type))
|
||
|
{
|
||
|
amountsVec[i] = getDirectFloat(amounts);
|
||
|
amounts = amounts->next;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
freeMemory(amountsVec);
|
||
|
freeMemory(timesVec);
|
||
|
return(errorProcExt(ERR_NUMBER_EXPECTED, amounts));
|
||
|
}
|
||
|
|
||
|
if(times == NULL)
|
||
|
timesVec[i] = i + 1;
|
||
|
else
|
||
|
{
|
||
|
times = getIntegerExt(times, (UINT *)&number, FALSE);
|
||
|
timesVec[i] = number;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
result = irr(N, timesVec, amountsVec, guess);
|
||
|
if(result < 0.00001)
|
||
|
result = 0.0;
|
||
|
else
|
||
|
{
|
||
|
result = floor((10000 * result + 0.5))/10000;
|
||
|
}
|
||
|
|
||
|
freeMemory(amountsVec);
|
||
|
freeMemory(timesVec);
|
||
|
|
||
|
if(result == IRR_ERROR)
|
||
|
return(nilCell);
|
||
|
|
||
|
return(stuffFloat(result));
|
||
|
}
|
||
|
|
||
|
/* ----------------------------------- CRC32 ----------------------- */
|
||
|
|
||
|
/* see also https://github.com/mattsta/crcspeed/blob/master/crc64speed.c
|
||
|
for fast 64-bt crc and here: https://matt.sh/redis-crcspeed
|
||
|
*/
|
||
|
|
||
|
#ifdef CRC16
|
||
|
unsigned short crc16(unsigned char * buff, int len)
|
||
|
{
|
||
|
int i;
|
||
|
unsigned short acc = 0xFFFF;
|
||
|
|
||
|
for(i = 0; i < len; i++)
|
||
|
{
|
||
|
acc ^= buff[i];
|
||
|
acc = (acc >> 8) | (acc << 8);
|
||
|
acc ^= (acc & 0xff00) << 4;
|
||
|
acc ^= (acc >> 8) >> 4;
|
||
|
acc ^= (acc & 0xff00) >> 5;
|
||
|
}
|
||
|
|
||
|
return(acc);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Algorithm from: http://www.w3.org/TR/PNG-CRCAppendix.html */
|
||
|
|
||
|
CELL * p_crc32(CELL * params)
|
||
|
{
|
||
|
char * data;
|
||
|
size_t len;
|
||
|
unsigned int crc;
|
||
|
|
||
|
getStringSize(params, &data, &len, TRUE);
|
||
|
crc = update_crc(0xffffffffL, (unsigned char *)data, (int)len) ^ 0xffffffffL;
|
||
|
return(stuffInteger64(crc));
|
||
|
}
|
||
|
|
||
|
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
|
||
|
should be initialized to all 1's, and the transmitted value
|
||
|
is the 1's complement of the final running CRC (see the
|
||
|
crc() routine below)).
|
||
|
*/
|
||
|
|
||
|
unsigned int update_crc(unsigned int crc, unsigned char *buf, int len)
|
||
|
{
|
||
|
/* unsigned int crc_table[256]; */
|
||
|
static unsigned int * crc_table = NULL;
|
||
|
unsigned int c;
|
||
|
int n, k;
|
||
|
|
||
|
if(crc_table == NULL)
|
||
|
{
|
||
|
/* make crc table */
|
||
|
crc_table = (unsigned int *)malloc(sizeof(unsigned int) * 256);
|
||
|
for (n = 0; n < 256; n++)
|
||
|
{
|
||
|
c = (unsigned int) n;
|
||
|
for (k = 0; k < 8; k++)
|
||
|
{
|
||
|
if (c & 1)
|
||
|
c = 0xedb88320L ^ (c >> 1);
|
||
|
else
|
||
|
c = c >> 1;
|
||
|
}
|
||
|
crc_table[n] = c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
c = crc;
|
||
|
|
||
|
/* update crc */
|
||
|
for (n = 0; n < len; n++)
|
||
|
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----------------------------------- Bayesian statistics -------------------------- */
|
||
|
|
||
|
/*
|
||
|
|
||
|
(bayes-train M1 M2 [M3 ... Mn] D)
|
||
|
|
||
|
takes two or more lists M1, M2 ... with tokens from a joint set of tokens T.
|
||
|
Token can be symbols or strings other datatypes are ignored.
|
||
|
Tokerns are placed in a common dictionary in context D and the frquency
|
||
|
is counted how often they occur in each category Mi.
|
||
|
|
||
|
The M categories represent data models for which a sequence of tokens can be
|
||
|
classified see (bayes-query ...)
|
||
|
|
||
|
Each token in D is a content addressable symbol in D containing a
|
||
|
list of ferquencies of that token how often it occurs in each category.
|
||
|
String tokens are prepended with an undersocre _ before convering them
|
||
|
to a symbol in D.
|
||
|
|
||
|
The function returns a list of token numbers in the different category models:
|
||
|
(N-of-tokens-in-M1 N-of-tokens-in-M2)
|
||
|
|
||
|
(bayes-train M1 M2 [M3 ... Mn] D)
|
||
|
|
||
|
*/
|
||
|
|
||
|
CELL * p_bayesTrain(CELL * params)
|
||
|
{
|
||
|
CELL * * category;
|
||
|
CELL * list;
|
||
|
CELL * count;
|
||
|
int * total;
|
||
|
int i, idx, maxIdx = 0;
|
||
|
SYMBOL * ctx;
|
||
|
SYMBOL * sPtr;
|
||
|
SYMBOL * totalPtr;
|
||
|
char * token;
|
||
|
|
||
|
list = params;
|
||
|
while(list != nilCell) list = list->next, maxIdx++;
|
||
|
--maxIdx; /* last is a context not a category */
|
||
|
if(maxIdx < 1) errorProc(ERR_MISSING_ARGUMENT);
|
||
|
|
||
|
category = alloca(maxIdx * sizeof(CELL *));
|
||
|
total = alloca(maxIdx * sizeof(int));
|
||
|
token = alloca(MAX_SYMBOL + 1);
|
||
|
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
params = getListHead(params, &list);
|
||
|
category[idx] = list;
|
||
|
}
|
||
|
|
||
|
if((ctx = getCreateContext(params, TRUE)) == NULL)
|
||
|
return(errorProcExt(ERR_SYMBOL_OR_CONTEXT_EXPECTED, params));
|
||
|
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
list = category[idx];
|
||
|
total[idx] = 0;
|
||
|
while(list != nilCell)
|
||
|
{
|
||
|
|
||
|
switch(list->type)
|
||
|
{
|
||
|
case CELL_STRING:
|
||
|
if(list->aux > MAX_SYMBOL + 1) continue;
|
||
|
*token = '_';
|
||
|
memcpy(token + 1, (char *)list->contents, list->aux);
|
||
|
break;
|
||
|
case CELL_SYMBOL:
|
||
|
strncpy(token, ((SYMBOL *)list->contents)->name, MAX_SYMBOL + 1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
sPtr = translateCreateSymbol(token, CELL_EXPRESSION, ctx, TRUE);
|
||
|
if(((CELL*)sPtr->contents)->type == CELL_NIL)
|
||
|
{
|
||
|
/* create list with maxIdx 0s */
|
||
|
count = getCell(CELL_EXPRESSION);
|
||
|
sPtr->contents = (UINT)count;
|
||
|
count->contents = (UINT)stuffInteger(0);
|
||
|
count = (CELL *)count->contents;
|
||
|
for(i = 1; i < maxIdx; i++)
|
||
|
{
|
||
|
count->next = stuffInteger(0);
|
||
|
count = count->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* increment value at idx */
|
||
|
count = (CELL *)sPtr->contents;
|
||
|
if(count->type != CELL_EXPRESSION)
|
||
|
return(errorProcExt(ERR_LIST_EXPECTED, count));
|
||
|
count = (CELL *)count->contents;
|
||
|
for(i = 0; i < idx; i++)
|
||
|
count = count->next;
|
||
|
if(count->type == CELL_LONG)
|
||
|
count->contents++;
|
||
|
#ifndef NEWLISP64
|
||
|
else if(count->type == CELL_INT64)
|
||
|
*(INT64 *)&count->aux += 1;
|
||
|
#endif
|
||
|
else
|
||
|
return(errorProcExt(ERR_NUMBER_EXPECTED, count));
|
||
|
total[idx]++;
|
||
|
list = list->next;
|
||
|
} /* done category idx */
|
||
|
}
|
||
|
|
||
|
totalPtr = translateCreateSymbol("total", CELL_EXPRESSION, ctx, TRUE);
|
||
|
if(((CELL *)totalPtr->contents)->type == CELL_NIL)
|
||
|
{
|
||
|
count = getCell(CELL_EXPRESSION);
|
||
|
totalPtr->contents = (UINT)count;
|
||
|
count->contents = (UINT)stuffInteger(0);
|
||
|
count = (CELL *)count->contents;
|
||
|
for(i = 1; i < maxIdx; i++)
|
||
|
{
|
||
|
count->next = stuffInteger(0);
|
||
|
count = count->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
count = (CELL *)totalPtr->contents;
|
||
|
if(count->type != CELL_EXPRESSION)
|
||
|
return(errorProcExt(ERR_LIST_EXPECTED, count));
|
||
|
count = (CELL *)count->contents;
|
||
|
for(i = 0; i < maxIdx; i++)
|
||
|
{
|
||
|
if(count->type == CELL_LONG)
|
||
|
count->contents += total[i];
|
||
|
#ifndef NEWLISP64
|
||
|
else if(count->type == CELL_INT64)
|
||
|
*(INT64 *)&count->aux += total[i];
|
||
|
#endif
|
||
|
count = count->next;
|
||
|
}
|
||
|
|
||
|
return(copyCell((CELL *)totalPtr->contents));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
(bayes-query L D [trueChainedBayes])
|
||
|
(bayes-query L D [trueChainedBayes] [trueFloatProbs)
|
||
|
|
||
|
Takes a list of tokens L and a trained dictionary D and returns a list of the
|
||
|
combined probabilities of the tokens to be in one category A versus the other
|
||
|
categories B. All token in L should occur in D, for tokens which are not in D
|
||
|
equal probability is asssumed over categories.
|
||
|
|
||
|
Token can be strings or symbols. If token are strings, they are prepended with
|
||
|
an underscore when looked up in D. When frequencies in D were learned using
|
||
|
bayes-train, the underscore was automatically prepended during learning.
|
||
|
|
||
|
for 2 categories:
|
||
|
|
||
|
p(tkn|A) * p(A)
|
||
|
p(A|tkn) = ---------------------------------
|
||
|
p(tkn|A) * p(A) + p(tkn|B) * p(B)
|
||
|
|
||
|
p(A|tkn) is the posterior for A which gets prior p(A) for the next token the
|
||
|
priors: p(A) and p(B) = 1 are substituted after every token. p(A) = p(not B).
|
||
|
|
||
|
for N categories:
|
||
|
|
||
|
p(tkn|Mc) * p(Mc)
|
||
|
p(Mc|tkn) = ------------------------------- ; Mc is one of N categories
|
||
|
sum-i-N( p(tkn|Mi) * p(Mi) )
|
||
|
|
||
|
|
||
|
When in chain Bayes mode p(Mc|tkn) is the posterior for Mc and replaces the
|
||
|
prior p(Mc) for the next token. In chain Bayes mode tokens with 0 frequency
|
||
|
in one category will effectiviely put the probability of this category to 0.
|
||
|
This causes queries resulting in 0 probabilities for all categories to yield
|
||
|
NaN values.
|
||
|
|
||
|
The pure chain Bayes mode is the more sensitive one for changes, when a token
|
||
|
count of 0 occurs the resulting probability goes to a complete 0 in this
|
||
|
category, while other categories gain higher probabilities. In the Fisher's
|
||
|
Chi2 mode the the zero-category is still assigned a probability resulting from
|
||
|
other tokens with non-zero counts.
|
||
|
*/
|
||
|
|
||
|
CELL * p_bayesQuery(CELL * params)
|
||
|
{
|
||
|
CELL * tokens;
|
||
|
CELL * tkn;
|
||
|
char * token;
|
||
|
SYMBOL * ctx;
|
||
|
SYMBOL * sPtr;
|
||
|
SYMBOL * totPtr;
|
||
|
CELL * count;
|
||
|
CELL * total;
|
||
|
int i, idx;
|
||
|
int nTkn = 0; /* number of token in query */
|
||
|
int maxIdx = 0; /* number of catagories */
|
||
|
int N = 0; /* total of tokens in all categories */
|
||
|
int chainBayes, probFlag;
|
||
|
double * priorP;
|
||
|
double * postP;
|
||
|
double * p_tkn_and_cat;
|
||
|
double p_tkn_and_all_cat;
|
||
|
double * Pchi2 = NULL;
|
||
|
double * Qchi2 = NULL;
|
||
|
INT countNum, totalNum;
|
||
|
|
||
|
CELL * result = NULL;
|
||
|
CELL * cell = NULL;
|
||
|
|
||
|
params = getListHead(params, &tokens);
|
||
|
params = getContext(params, &ctx);
|
||
|
|
||
|
chainBayes = getFlag(params);
|
||
|
probFlag = getFlag(params->next);
|
||
|
|
||
|
totPtr = translateCreateSymbol("total", CELL_EXPRESSION, ctx, FALSE);
|
||
|
if(totPtr == NULL) return(nilCell);
|
||
|
|
||
|
total = (CELL *)totPtr->contents;
|
||
|
if(total->type != CELL_EXPRESSION)
|
||
|
return(errorProcExt(ERR_LIST_EXPECTED, (CELL *)totPtr->contents));
|
||
|
|
||
|
/*
|
||
|
Get number of categories maxIdx and total N in all categories.
|
||
|
If no probabilities are specified get frequencies/counts
|
||
|
*/
|
||
|
total = (CELL *)total->contents;
|
||
|
while(total != nilCell)
|
||
|
{
|
||
|
if(probFlag == FALSE)
|
||
|
{
|
||
|
if(total->type == CELL_LONG)
|
||
|
N += total->contents;
|
||
|
#ifndef NEWLISP64
|
||
|
else if(total->type == CELL_INT64)
|
||
|
N += *(INT64 *)&total->aux;
|
||
|
#endif
|
||
|
}
|
||
|
total = total->next;
|
||
|
maxIdx++;
|
||
|
}
|
||
|
|
||
|
/* allocate memory for priors and posts for each category */
|
||
|
priorP = alloca(maxIdx * sizeof(double));
|
||
|
postP = alloca(maxIdx * sizeof(double));
|
||
|
p_tkn_and_cat = alloca(maxIdx * sizeof(double));
|
||
|
|
||
|
/* allocate memory fo Chi-2 probs for each category */
|
||
|
if(!chainBayes)
|
||
|
{
|
||
|
Pchi2 = alloca(maxIdx * sizeof(double));
|
||
|
Qchi2 = alloca(maxIdx * sizeof(double));
|
||
|
}
|
||
|
|
||
|
/* calculate the prior prob for each category */
|
||
|
total = (CELL *)((CELL *)totPtr->contents)->contents;
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
if(probFlag == TRUE)
|
||
|
#ifndef NEWLISP64
|
||
|
priorP[idx] = *(double *)&total->aux;
|
||
|
#else
|
||
|
priorP[idx] = (double)total->contents;
|
||
|
#endif
|
||
|
else
|
||
|
{
|
||
|
if(total->type == CELL_LONG)
|
||
|
priorP[idx] = (double)total->contents / N;
|
||
|
#ifndef NEWLISP64
|
||
|
else /* INT64 */
|
||
|
priorP[idx] = (double)*(INT64 *)&total->aux / N;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef BAYES_DEBUG
|
||
|
printf("priorP[%d]=%f probability of category %d\n", idx, priorP[idx], idx);
|
||
|
#endif
|
||
|
|
||
|
total = total->next;
|
||
|
/* initialize Fisher's Chi-2 probs and priors */
|
||
|
if(!chainBayes)
|
||
|
{
|
||
|
Pchi2[idx] = Qchi2[idx] = 0.0;
|
||
|
priorP[idx] = 1.0 / maxIdx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
token = alloca(MAX_SYMBOL + 1);
|
||
|
tkn = tokens;
|
||
|
while(tkn != nilCell) tkn = tkn->next, nTkn++;
|
||
|
|
||
|
/* for each token calculate p(tkn|M) in each category M */
|
||
|
tkn = tokens;
|
||
|
for(i = 0; i < nTkn; i++)
|
||
|
{
|
||
|
switch(tkn->type)
|
||
|
{
|
||
|
case CELL_STRING:
|
||
|
if(tkn->aux > MAX_SYMBOL + 1) continue;
|
||
|
*token = '_';
|
||
|
memcpy(token + 1, (char *)tkn->contents, tkn->aux);
|
||
|
break;
|
||
|
case CELL_SYMBOL:
|
||
|
strncpy(token, ((SYMBOL *)tkn->contents)->name, MAX_SYMBOL + 1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if((sPtr = lookupSymbol((char *)token, ctx)) == NULL)
|
||
|
{
|
||
|
/* skip the token if it doesn't occur in data */
|
||
|
tkn = tkn->next;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
count = (CELL *)sPtr->contents;
|
||
|
if(count->type != CELL_EXPRESSION) continue;
|
||
|
|
||
|
count = (CELL *)(CELL *)count->contents;
|
||
|
total = (CELL *)((CELL *)totPtr->contents)->contents;
|
||
|
|
||
|
/* in each category M[idx] */
|
||
|
p_tkn_and_all_cat = 0.0;
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
if(probFlag)
|
||
|
#ifndef NEWLISP64
|
||
|
p_tkn_and_cat[idx] = *(double *)&count->aux * priorP[idx];
|
||
|
#else
|
||
|
p_tkn_and_cat[idx] = *(double *)&count->contents * priorP[idx];
|
||
|
#endif
|
||
|
else /* p(M) * p(tkn|M) */
|
||
|
{
|
||
|
/* count of token in category idx */
|
||
|
getInteger(count, (UINT *)&countNum);
|
||
|
/* total of all tokens in category idx */
|
||
|
getInteger(total, (UINT *)&totalNum);
|
||
|
p_tkn_and_cat[idx] = priorP[idx] * countNum / totalNum;
|
||
|
}
|
||
|
|
||
|
/* accumulate probability of token in all cataegories */
|
||
|
p_tkn_and_all_cat += p_tkn_and_cat[idx];
|
||
|
|
||
|
#ifdef BAYES_DEBUG
|
||
|
printf("token[%d] p(M[%d]) * p(tkn|M[%d])=%lf * %ld / %ld = %lf\n", i, idx, idx,
|
||
|
priorP[idx], countNum, totalNum, (double)p_tkn_and_cat[idx]);
|
||
|
#endif
|
||
|
count = count->next;
|
||
|
total = total->next;
|
||
|
}
|
||
|
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
if(!chainBayes)
|
||
|
{
|
||
|
postP[idx] = p_tkn_and_cat[idx] / p_tkn_and_all_cat;
|
||
|
|
||
|
/* handle probability limits of 0 and using very small value */
|
||
|
if(postP[idx] == 0.0)
|
||
|
Qchi2[idx] += log(3e-308) * -2.0;
|
||
|
else
|
||
|
Qchi2[idx] += log(postP[idx]) * -2.0;
|
||
|
|
||
|
if(postP[idx] == 1.0)
|
||
|
Pchi2[idx] += log(3e-308) * -2.0;
|
||
|
else
|
||
|
Pchi2[idx] += log(1.0 - postP[idx]) * -2.0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
postP[idx] = p_tkn_and_cat[idx] / p_tkn_and_all_cat;
|
||
|
priorP[idx] = postP[idx];
|
||
|
}
|
||
|
#ifdef BAYES_DEBUG
|
||
|
printf("postP[%d] = p_tkn_and_cat[%d] / p_tkn_and_all_cat = %lf / %lf = %lf\n",
|
||
|
idx, idx, p_tkn_and_cat[idx], p_tkn_and_all_cat, postP[idx]);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
tkn = tkn->next;
|
||
|
}
|
||
|
|
||
|
if(!chainBayes)
|
||
|
{
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
#ifdef BAYES_DEBUG
|
||
|
printf("Qchi2[%d] = %f, Pchi2[%d] = %f, nTkn = %d\n", idx, Qchi2[idx], idx, Pchi2[idx], nTkn);
|
||
|
#endif
|
||
|
/* corrected swapped Pchi2[idx] and Qchi2[idx] in 10.5.5 */
|
||
|
postP[idx] = (probChi2(Pchi2[idx], 2 * nTkn) - probChi2(Qchi2[idx], 2 * nTkn) + 1.0) / 2.0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
for(idx = 0; idx < maxIdx; idx++)
|
||
|
{
|
||
|
if(idx == 0)
|
||
|
{
|
||
|
result = getCell(CELL_EXPRESSION);
|
||
|
result->contents = (UINT)stuffFloat(*(postP + idx));
|
||
|
cell = (CELL *)result->contents;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cell->next = stuffFloat(*(postP + idx));
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
//
|
||
|
// Copyright (C) 1992-2016 Lutz Mueller <lutz@nuevatec.com>
|
||
|
//
|
||
|
// This program is free software; you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License version 2, 1991,
|
||
|
// as published by the Free Software Foundation.
|
||
|
//
|
||
|
// This program is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with this program; if not, write to the Free Software
|
||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
//
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
'unify' for Prolog like unification of s-expressions:
|
||
|
(unify '(f (g A) A) '(f B xyz)) => binds A to xyz and B to (g xyz)
|
||
|
|
||
|
variable symbols must start with an upper-case letter, variables
|
||
|
containing nil are considered unbound
|
||
|
|
||
|
after linear left to right unification each variable symbol is expanded
|
||
|
by all other variable symbols
|
||
|
*/
|
||
|
|
||
|
#ifdef SUPPORT_UTF8
|
||
|
#include <wctype.h>
|
||
|
#endif
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
CELL * left;
|
||
|
CELL * right;
|
||
|
void * next;
|
||
|
} TERMSET;
|
||
|
|
||
|
void pushSet(TERMSET * * root, CELL * left, CELL * right);
|
||
|
CELL * unify(CELL * left, CELL * right);
|
||
|
int unifyGetType(CELL * cell);
|
||
|
void substitute(CELL * expr, CELL * sym, TERMSET * tset);
|
||
|
CELL * subsym(CELL * expr, CELL * sym, CELL * cell);
|
||
|
CELL * finishUnify(CELL * result);
|
||
|
int occurCheck(CELL * symCell, CELL * expr);
|
||
|
void printStack(TERMSET * tset);
|
||
|
void freeTermSet(TERMSET * * tset);
|
||
|
|
||
|
TERMSET * mgu = NULL; /* most general unifier */
|
||
|
TERMSET * ws = NULL;
|
||
|
|
||
|
int bindFlag;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
int debugFlag;
|
||
|
#endif
|
||
|
|
||
|
CELL * p_unify(CELL * params)
|
||
|
{
|
||
|
CELL * left, * right;
|
||
|
CELL * envHead;
|
||
|
left = evaluateExpression(params);
|
||
|
params = params->next;
|
||
|
right = evaluateExpression(params);
|
||
|
|
||
|
if((params = params->next) != nilCell)
|
||
|
{
|
||
|
params = getListHead(params, &envHead);
|
||
|
while(envHead != nilCell)
|
||
|
{
|
||
|
if(envHead->type != CELL_EXPRESSION)
|
||
|
return(errorProcExt(ERR_LIST_EXPECTED, envHead));
|
||
|
pushSet(&ws, copyCell((CELL*)envHead->contents),
|
||
|
copyCell(((CELL*)envHead->contents)->next));
|
||
|
envHead = envHead->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bindFlag = getFlag(params);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
debugFlag = getFlag(params->next);
|
||
|
if(debugFlag) printStack(ws);
|
||
|
#endif
|
||
|
|
||
|
return(unify(left, right));
|
||
|
}
|
||
|
|
||
|
#define UNIFY_ATOM 0
|
||
|
#define UNIFY_LIST 1
|
||
|
#define UNIFY_VAR 2
|
||
|
#define UNIFY_ANY 3
|
||
|
|
||
|
void pushSet(TERMSET * * root, CELL * left, CELL * right)
|
||
|
{
|
||
|
TERMSET * set;
|
||
|
|
||
|
set = (TERMSET *)callocMemory(sizeof(TERMSET));
|
||
|
|
||
|
set->left = left;
|
||
|
set->right = right;
|
||
|
set->next = *root;
|
||
|
*root = set;
|
||
|
}
|
||
|
|
||
|
void popSet(TERMSET * * root, CELL * * left, CELL * * right)
|
||
|
{
|
||
|
TERMSET * set;
|
||
|
|
||
|
set = *root;
|
||
|
*root = set->next;
|
||
|
|
||
|
*left = set->left;
|
||
|
*right = set->right;
|
||
|
|
||
|
freeMemory(set);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * unify(CELL * left, CELL * right)
|
||
|
{
|
||
|
int leftType, rightType;
|
||
|
CELL * lCell, * rCell;
|
||
|
|
||
|
pushSet(&ws, copyCell(left), copyCell(right));
|
||
|
|
||
|
while(ws != NULL)
|
||
|
{
|
||
|
popSet(&ws, &left, &right);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("unify:");
|
||
|
printCell(left, FALSE, OUT_CONSOLE);
|
||
|
printf(" ");
|
||
|
printCell(right, FALSE, OUT_CONSOLE);
|
||
|
printf("\n");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
leftType = unifyGetType(left);
|
||
|
rightType = unifyGetType(right);
|
||
|
|
||
|
if(leftType == UNIFY_ANY || rightType == UNIFY_ANY)
|
||
|
{
|
||
|
deleteList(left);
|
||
|
deleteList(right);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( (leftType == UNIFY_ATOM && rightType == UNIFY_ATOM) ||
|
||
|
(left->contents == right->contents))
|
||
|
{
|
||
|
if(compareCells(left, right) == 0)
|
||
|
{
|
||
|
deleteList(left);
|
||
|
deleteList(right);
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
deleteList(left);
|
||
|
deleteList(right);
|
||
|
return(finishUnify(nilCell));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(leftType == UNIFY_VAR && !occurCheck(left, right))
|
||
|
{
|
||
|
substitute(right, left, mgu); /* expand(right-expr, left-sym) in mgu set */
|
||
|
substitute(right, left, ws); /* expand(right-expr, left-sym) in ws set */
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("ws stack\n");
|
||
|
printStack(ws);
|
||
|
}
|
||
|
#endif
|
||
|
pushSet(&mgu, left, right);
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("mgu stack\n");
|
||
|
printStack(mgu);
|
||
|
}
|
||
|
#endif
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(rightType == UNIFY_VAR && !occurCheck(right, left))
|
||
|
{
|
||
|
substitute(left, right, mgu); /* expand(left-expr, right-sym) in mgu set */
|
||
|
substitute(left, right, ws); /* expand(left-expr, right-sym) in ws set */
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("ws stack\n");
|
||
|
printStack(ws);
|
||
|
}
|
||
|
#endif
|
||
|
pushSet(&mgu, right, left);
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("mgu stack\n");
|
||
|
printStack(mgu);
|
||
|
}
|
||
|
#endif
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(leftType == UNIFY_LIST && rightType == UNIFY_LIST)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("lists:");
|
||
|
printCell(left, FALSE, OUT_CONSOLE);
|
||
|
printf(" ");
|
||
|
printCell(right, FALSE, OUT_CONSOLE);
|
||
|
printf("\n");
|
||
|
}
|
||
|
#endif
|
||
|
if(listlen((CELL*)left->contents) != listlen((CELL*)right->contents))
|
||
|
{
|
||
|
deleteList(left);
|
||
|
deleteList(right);
|
||
|
return(finishUnify(nilCell));
|
||
|
}
|
||
|
|
||
|
lCell = (CELL*)left->contents;
|
||
|
rCell = (CELL*)right->contents;
|
||
|
while(lCell != nilCell)
|
||
|
{
|
||
|
pushSet(&ws, copyCell(lCell), copyCell(rCell));
|
||
|
lCell = lCell->next;
|
||
|
rCell = rCell->next;
|
||
|
}
|
||
|
deleteList(left);
|
||
|
deleteList(right);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
deleteList(left);
|
||
|
deleteList(right);
|
||
|
return(finishUnify(nilCell));
|
||
|
}
|
||
|
|
||
|
return(finishUnify(trueCell));
|
||
|
}
|
||
|
|
||
|
int unifyGetType(CELL * cell)
|
||
|
{
|
||
|
SYMBOL * sPtr;
|
||
|
int wchar;
|
||
|
|
||
|
if(isSymbol(cell->type))
|
||
|
{
|
||
|
if(cell->type == CELL_SYMBOL)
|
||
|
sPtr = (SYMBOL *)cell->contents;
|
||
|
else
|
||
|
sPtr = getDynamicSymbol(cell);
|
||
|
|
||
|
if(*sPtr->name == '_' && *(sPtr->name + 1) == 0)
|
||
|
return(UNIFY_ANY);
|
||
|
|
||
|
#ifndef SUPPORT_UTF8
|
||
|
wchar = *sPtr->name;
|
||
|
#else
|
||
|
utf8_wchar(sPtr->name, &wchar);
|
||
|
#endif
|
||
|
return((wchar > 64 && wchar < 91) ? UNIFY_VAR : UNIFY_ATOM);
|
||
|
}
|
||
|
else if(isList(cell->type))
|
||
|
return(UNIFY_LIST);
|
||
|
|
||
|
return(UNIFY_ATOM);
|
||
|
}
|
||
|
|
||
|
|
||
|
int occurCheck(CELL * symCell, CELL * expr)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
|
||
|
if(!isEnvelope(expr->type))
|
||
|
return(symCell->contents == expr->contents);
|
||
|
|
||
|
cell = (CELL*)expr->contents;
|
||
|
|
||
|
while(cell != nilCell)
|
||
|
{
|
||
|
if(symCell->contents == cell->contents) return(1);
|
||
|
if(isEnvelope(cell->type) && occurCheck(symCell, cell)) return(1);
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
void substitute(CELL * expr, CELL * sym, TERMSET * tset)
|
||
|
{
|
||
|
if(tset == NULL)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("empty set in substitute %s for ", ((SYMBOL*)sym->contents)->name);
|
||
|
printCell(expr, FALSE, OUT_CONSOLE);
|
||
|
printf("\n");
|
||
|
}
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
while(tset != NULL)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("substitute %s for ", ((SYMBOL*)sym->contents)->name);
|
||
|
printCell(expr, FALSE, OUT_CONSOLE);
|
||
|
printf("\n");
|
||
|
printf("left:");
|
||
|
printCell(tset->left, FALSE, OUT_CONSOLE);
|
||
|
}
|
||
|
#endif
|
||
|
tset->left = subsym(expr, sym, tset->left);
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("->");
|
||
|
printCell(tset->left, FALSE, OUT_CONSOLE);
|
||
|
printf(" right:");
|
||
|
printCell(tset->right, FALSE, OUT_CONSOLE);
|
||
|
}
|
||
|
#endif
|
||
|
tset->right = subsym(expr, sym, tset->right);
|
||
|
#ifdef DEBUG
|
||
|
if(debugFlag)
|
||
|
{
|
||
|
printf("->");
|
||
|
printCell(tset->right, FALSE, OUT_CONSOLE);
|
||
|
printf("\n");
|
||
|
}
|
||
|
#endif
|
||
|
tset = tset->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * subsym(CELL * expr, CELL * sym, CELL * cell)
|
||
|
{
|
||
|
SYMBOL * sPtr;
|
||
|
CELL * sCell;
|
||
|
|
||
|
sPtr = (SYMBOL *)sym->contents;
|
||
|
sCell = (CELL *)sPtr->contents;
|
||
|
sPtr->contents = (UINT)expr;
|
||
|
|
||
|
if(isList(cell->type) || cell->type == CELL_QUOTE)
|
||
|
{
|
||
|
expr = expand(copyCell(cell), sPtr);
|
||
|
deleteList(cell);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(cell->contents == (UINT)sPtr)
|
||
|
{
|
||
|
expr = copyCell(expr);
|
||
|
deleteList(cell);
|
||
|
}
|
||
|
else
|
||
|
expr = cell;
|
||
|
}
|
||
|
|
||
|
sPtr->contents = (UINT)sCell;
|
||
|
return(expr);
|
||
|
}
|
||
|
|
||
|
CELL * finishUnify(CELL * result)
|
||
|
{
|
||
|
CELL * left, * right;
|
||
|
CELL * list = NULL;
|
||
|
CELL * assoc, * cell = NULL;
|
||
|
SYMBOL * sPtr;
|
||
|
|
||
|
if(result == nilCell)
|
||
|
{
|
||
|
freeTermSet(&mgu);
|
||
|
freeTermSet(&ws);
|
||
|
return(nilCell);
|
||
|
}
|
||
|
|
||
|
/* make an association list of all bound variables */
|
||
|
while(mgu != NULL)
|
||
|
{
|
||
|
popSet(&mgu, &left, &right);
|
||
|
|
||
|
if(!bindFlag)
|
||
|
{
|
||
|
assoc = getCell(CELL_EXPRESSION);
|
||
|
assoc->contents = (UINT)left;
|
||
|
left->next = right;
|
||
|
if(list == NULL)
|
||
|
{
|
||
|
list = getCell(CELL_EXPRESSION);
|
||
|
list->contents = (UINT)assoc;
|
||
|
}
|
||
|
else
|
||
|
cell->next = assoc;
|
||
|
cell = assoc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sPtr = (SYMBOL*)left->contents;
|
||
|
if(isProtected(sPtr->flags))
|
||
|
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(sPtr)));
|
||
|
sPtr->contents = (UINT)right;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
freeTermSet(&ws);
|
||
|
|
||
|
if(!list || bindFlag) return(getCell(CELL_EXPRESSION));
|
||
|
return(list);
|
||
|
}
|
||
|
|
||
|
|
||
|
void freeTermSet(TERMSET * * tset)
|
||
|
{
|
||
|
TERMSET * set;
|
||
|
|
||
|
while(*tset != NULL)
|
||
|
{
|
||
|
set = *tset;
|
||
|
deleteList(set->left);
|
||
|
deleteList(set->right);
|
||
|
*tset = set->next;
|
||
|
freeMemory(set);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
void printStack(TERMSET * tset)
|
||
|
{
|
||
|
while(tset != NULL)
|
||
|
{
|
||
|
printCell(tset->left, FALSE, OUT_CONSOLE);
|
||
|
printf("<->");
|
||
|
printCell(tset->right, FALSE, OUT_CONSOLE);
|
||
|
printf("\n");
|
||
|
tset = tset->next;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* ---------------------------------- end unify ----------------------------- */
|
||
|
|
||
|
CELL * p_bits(CELL * params)
|
||
|
{
|
||
|
int count = 0;
|
||
|
int i;
|
||
|
char temp[65];
|
||
|
char result[65];
|
||
|
INT64 num;
|
||
|
CELL * resultList;
|
||
|
|
||
|
params = getInteger64Ext(params, &num, TRUE);
|
||
|
|
||
|
do {
|
||
|
temp[count++] = (num % 2) != 0;
|
||
|
num = num >> 1;
|
||
|
} while (num != 0 && count < 64);
|
||
|
|
||
|
if(getFlag(params))
|
||
|
{
|
||
|
resultList = getCell(CELL_EXPRESSION);
|
||
|
for(i = 0; i < count; i++)
|
||
|
addList(resultList, (copyCell (temp[i] ? trueCell : nilCell)));
|
||
|
return(resultList);
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < count; i++)
|
||
|
result[i] = temp[count - 1 - i] + 48;
|
||
|
|
||
|
return(stuffStringN(result, count));
|
||
|
}
|
||
|
|
||
|
|
||
|
#define BOOL_EVEN 0
|
||
|
#define BOOL_ODD 1
|
||
|
|
||
|
CELL * isOddEven(CELL * params, int type)
|
||
|
{
|
||
|
INT64 num;
|
||
|
|
||
|
params = evaluateExpression(params);
|
||
|
|
||
|
#ifdef BIGINT
|
||
|
if(params->type == CELL_BIGINT)
|
||
|
num = *((int *)params->contents + params->aux - 1);
|
||
|
else
|
||
|
#endif
|
||
|
getInteger64Ext(params, &num, FALSE);
|
||
|
|
||
|
if(type == BOOL_EVEN)
|
||
|
return((0 == (num & 1)) ? trueCell : nilCell);
|
||
|
else /* BOOL_ODD */
|
||
|
return((0 == (num & 1)) ? nilCell : trueCell);
|
||
|
}
|
||
|
|
||
|
CELL * p_isOdd(CELL * params)
|
||
|
{ return(isOddEven(params, BOOL_ODD)); }
|
||
|
|
||
|
CELL * p_isEven(CELL * params)
|
||
|
{ return(isOddEven(params, BOOL_EVEN)); }
|
||
|
|
||
|
/* used when passing 32bit floats to library routines */
|
||
|
CELL * p_flt(CELL * params)
|
||
|
{
|
||
|
double dfloatV;
|
||
|
float floatV;
|
||
|
unsigned int number;
|
||
|
|
||
|
getFloat(params, &dfloatV);
|
||
|
|
||
|
floatV = dfloatV;
|
||
|
memcpy(&number, &floatV, 4);
|
||
|
|
||
|
return(stuffInteger64(number));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------ basic statistics ------------------------- */
|
||
|
|
||
|
double * getVector(CELL * data, UINT * N, double * Sum, double * Mean, double * Sd2)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
UINT idx, n;
|
||
|
double * vector = NULL;
|
||
|
double value, sum, ssq, sd2;
|
||
|
CELL * * addr;
|
||
|
|
||
|
n = sum = ssq = 0;
|
||
|
if(data->type == CELL_EXPRESSION)
|
||
|
{
|
||
|
if((data = cell = (CELL *)data->contents) == nilCell)
|
||
|
return(NULL);
|
||
|
n = 1;
|
||
|
while(cell->next != nilCell)
|
||
|
{ cell = cell->next; n++; }
|
||
|
cell = data;
|
||
|
vector = callocMemory(sizeof(double) * n);
|
||
|
for (idx = 0; idx < n; idx++)
|
||
|
{
|
||
|
value = getDirectFloat(cell);
|
||
|
*(vector + idx) = value;
|
||
|
sum += value;
|
||
|
ssq += value * value;
|
||
|
cell = cell->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if(data->type == CELL_ARRAY)
|
||
|
{
|
||
|
addr = (CELL * *)data->contents;
|
||
|
n = (data->aux - 1) / sizeof(CELL *);
|
||
|
vector = callocMemory(sizeof(double) * n);
|
||
|
for (idx = 0; idx < n; idx++)
|
||
|
{
|
||
|
cell = *(addr + idx);
|
||
|
value = getDirectFloat(cell);
|
||
|
*(vector + idx) = value;
|
||
|
sum += value;
|
||
|
ssq += value * value;
|
||
|
}
|
||
|
}
|
||
|
else return(NULL);
|
||
|
|
||
|
sd2 = ssq - sum * sum / n;
|
||
|
|
||
|
*N = n;
|
||
|
*Sum = sum;
|
||
|
*Mean = sum / n;
|
||
|
*Sd2 = sd2;
|
||
|
|
||
|
return(vector);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_stats(CELL * params)
|
||
|
{
|
||
|
CELL * cell;
|
||
|
UINT N = 0;
|
||
|
double sum, mean, sd2, avdev, sdev, var, skew, curt, s;
|
||
|
double * vector;
|
||
|
int idx;
|
||
|
|
||
|
if((vector = getVector(evaluateExpression(params), &N, &sum, &mean, &sd2)) == NULL)
|
||
|
return(errorProc(ERR_LIST_OR_ARRAY_EXPECTED));
|
||
|
|
||
|
var = sd2 / (N - 1); /* pop variance */
|
||
|
sdev = sqrt(var); /* standard deviation */
|
||
|
|
||
|
skew = curt = avdev = 0.0;
|
||
|
for(idx = 0; idx < N; idx++)
|
||
|
{
|
||
|
s = vector[idx] - mean;
|
||
|
avdev += fabs(s);
|
||
|
skew += s * s * s;
|
||
|
curt += s * s * s * s;
|
||
|
}
|
||
|
avdev /= N;
|
||
|
|
||
|
freeMemory(vector);
|
||
|
|
||
|
if(var != 0.0)
|
||
|
{
|
||
|
skew = skew / (N * var * sdev);
|
||
|
curt = curt / (N * var * var) - 3.0;
|
||
|
}
|
||
|
else skew = curt = 0.0;
|
||
|
|
||
|
cell = getCell(CELL_EXPRESSION);
|
||
|
addList(cell, stuffInteger(N));
|
||
|
addList(cell, stuffFloat(mean));
|
||
|
addList(cell, stuffFloat(avdev));
|
||
|
addList(cell, stuffFloat(sdev));
|
||
|
addList(cell, stuffFloat(var));
|
||
|
addList(cell, stuffFloat(skew));
|
||
|
addList(cell, stuffFloat(curt));
|
||
|
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
CELL * p_ttest(CELL * params)
|
||
|
{
|
||
|
UINT Nx, Ny, df;
|
||
|
double sumx, sumy, sumxy;
|
||
|
double meanx, meany;
|
||
|
double sd2x, sd2y;
|
||
|
double varx, vary;
|
||
|
double sdevx, sdevy;
|
||
|
double * X;
|
||
|
double * Y;
|
||
|
double svar, cov, t, tprob;
|
||
|
CELL * cell;
|
||
|
int dependent = FALSE, idx;
|
||
|
double pF = 0.0;
|
||
|
|
||
|
if((X = getVector(evaluateExpression(params), &Nx, &sumx, &meanx, &sd2x)) == NULL)
|
||
|
return(errorProc(ERR_LIST_OR_ARRAY_EXPECTED));
|
||
|
params = params->next;
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
if(isNumber(cell->type)) /* One sample t-test */
|
||
|
{
|
||
|
meany = getDirectFloat(cell);
|
||
|
sdevx = sqrt(sd2x / (Nx - 1));
|
||
|
sdevy = sdevx / sqrt(Nx); /* standard error of difference */
|
||
|
t = (meanx - meany) / ( sdevx / sqrt(Nx) );
|
||
|
df = Nx - 1;
|
||
|
goto TTEST_RESULT;
|
||
|
}
|
||
|
|
||
|
if((Y = getVector(evaluateExpression(params), &Ny, &sumy, &meany, &sd2y)) == NULL)
|
||
|
return(errorProc(ERR_LIST_OR_ARRAY_EXPECTED));
|
||
|
|
||
|
sumxy = 0.0;
|
||
|
for(idx = 0; idx < Nx; idx++)
|
||
|
sumxy += X[idx] * Y[idx];
|
||
|
|
||
|
freeMemory(X);
|
||
|
freeMemory(Y);
|
||
|
|
||
|
cell = evaluateExpression(params->next);
|
||
|
if(cell == trueCell)
|
||
|
{
|
||
|
dependent = TRUE;
|
||
|
if(Nx != Ny)
|
||
|
return(errorProc(ERR_WRONG_DIMENSIONS));
|
||
|
}
|
||
|
else if(isNumber(cell->type))
|
||
|
pF = getDirectFloat(cell);
|
||
|
|
||
|
varx = sd2x / (Nx - 1);
|
||
|
vary = sd2y / (Ny - 1);
|
||
|
sdevx = sqrt(varx);
|
||
|
sdevy = sqrt(vary);
|
||
|
cov = sumxy - sumx * sumy / Nx;
|
||
|
|
||
|
/* t for related samples Nx = Ny */
|
||
|
if(dependent)
|
||
|
{
|
||
|
df = Nx - 1;
|
||
|
cov /= df;
|
||
|
t = (meanx - meany) / sqrt((varx + vary - 2.0 * cov) / Nx);
|
||
|
}
|
||
|
/* t for different means in non-related samples */
|
||
|
else
|
||
|
{
|
||
|
/* if varx and vary are not equal calc Welch Student's t */
|
||
|
if(pF != 0.0 && probF(varx/vary, Nx - 1, Ny - 1) < pF)
|
||
|
{
|
||
|
t = (meanx - meany) / sqrt(varx/Nx + vary/Ny);
|
||
|
df = ((varx/Nx + vary/Ny) * (varx/Nx + vary/Ny)) /
|
||
|
(((varx/Nx) * (varx/Nx)) / (Nx - 1) + ((vary/Ny) * (vary/Ny))/(Ny - 1));
|
||
|
}
|
||
|
/* assume varx and vary are equal */
|
||
|
else
|
||
|
{
|
||
|
df = Nx + Ny - 2;
|
||
|
svar = (sd2x + sd2y) / df;
|
||
|
t = (meanx - meany) / sqrt(svar * (1.0/Nx + 1.0/Ny));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TTEST_RESULT:
|
||
|
tprob = 2.0 * (1.0 - probT(fabs(t), df)); /* two tailed */
|
||
|
cell = getCell(CELL_EXPRESSION);
|
||
|
addList(cell, stuffFloat(meanx));
|
||
|
addList(cell, stuffFloat(meany));
|
||
|
addList(cell, stuffFloat(sdevx));
|
||
|
addList(cell, stuffFloat(sdevy));
|
||
|
addList(cell, stuffFloat(t));
|
||
|
addList(cell, stuffInteger(df));
|
||
|
addList(cell, stuffFloat(tprob));
|
||
|
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
|
||
|
CELL * p_corr(CELL * params)
|
||
|
{
|
||
|
UINT idx, Nx, Ny, df;
|
||
|
double * X;
|
||
|
double * Y;
|
||
|
double sumxy, sumx, sumy, meanx, meany, sd2x, sd2y;
|
||
|
double cov, corr, b0, b1, t, tprob;
|
||
|
CELL * cell;
|
||
|
|
||
|
|
||
|
if((X = getVector(evaluateExpression(params), &Nx, &sumx, &meanx, &sd2x)) == NULL)
|
||
|
return(errorProc(ERR_LIST_OR_ARRAY_EXPECTED));
|
||
|
if((Y = getVector(evaluateExpression(params->next), &Ny, &sumy, &meany, &sd2y)) == NULL)
|
||
|
return(errorProc(ERR_LIST_OR_ARRAY_EXPECTED));
|
||
|
|
||
|
if(Nx != Ny)
|
||
|
return(errorProc(ERR_WRONG_DIMENSIONS));
|
||
|
|
||
|
sumxy = 0.0;
|
||
|
for(idx = 0; idx < Nx; idx++)
|
||
|
sumxy += X[idx] * Y[idx];
|
||
|
|
||
|
freeMemory(X);
|
||
|
freeMemory(Y);
|
||
|
|
||
|
cov = sumxy - sumx * sumy / Nx;
|
||
|
corr = cov / sqrt(sd2x * sd2y);
|
||
|
b1 = cov / sd2x;
|
||
|
b0 = meany - b1 * meanx;
|
||
|
t = corr * sqrt((Nx - 2) / (1.0 - corr * corr));
|
||
|
|
||
|
/* standard error of corr */
|
||
|
/* rse = sqrt( (1.0 - corr * corr) / (Nx - 2) ); */
|
||
|
/* see http://irthoughts.wordpress.com/2010/06/10/on-spearmans-correlation-coefficients-with-excel/ */
|
||
|
/* rse = corr / t; */
|
||
|
|
||
|
df = Nx - 2;
|
||
|
tprob = 2 * (1.0 - probT(fabs(t), df)); /* two tailed */
|
||
|
|
||
|
cell = getCell(CELL_EXPRESSION);
|
||
|
addList(cell, stuffFloat(corr));
|
||
|
addList(cell, stuffFloat(b0)); /* y = b0 + b1*x */
|
||
|
addList(cell, stuffFloat(b1));
|
||
|
addList(cell, stuffFloat(t));
|
||
|
addList(cell, stuffInteger(df));
|
||
|
addList(cell, stuffFloat(tprob));
|
||
|
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
/* ============================= Big Integer support ============================= */
|
||
|
|
||
|
/* other big int libs:
|
||
|
GNU GMP https://gmplib.org/
|
||
|
MPIR http://www.mpir.org/
|
||
|
BSDNT https://github.com/wbhart/bsdnt
|
||
|
*/
|
||
|
|
||
|
#ifdef BIGINT
|
||
|
|
||
|
/* translate either INT64 or double float to big int */
|
||
|
|
||
|
CELL * p_bigInt(CELL * params)
|
||
|
{
|
||
|
int * numPtr;
|
||
|
int len, size = 0;
|
||
|
CELL * cell;
|
||
|
char * ptr;
|
||
|
|
||
|
cell = evaluateExpression(params);
|
||
|
if(cell->type == CELL_BIGINT)
|
||
|
return(copyCell(cell));
|
||
|
|
||
|
if(cell->type == CELL_STRING)
|
||
|
{
|
||
|
ptr = (char *)cell->contents;
|
||
|
if(*ptr == '-' || *ptr == '+') ++size, ptr++;
|
||
|
while(isdigit(*ptr++)) ++size;
|
||
|
if(size == 0) return(nilCell);
|
||
|
numPtr = strToBigint((char *)cell->contents, size, &len);
|
||
|
}
|
||
|
else getBigintSizeDirect(cell, &numPtr, &len);
|
||
|
|
||
|
cell = getCell(CELL_BIGINT);
|
||
|
cell->aux = len + 1;
|
||
|
cell->contents = (UINT)numPtr;
|
||
|
|
||
|
return(cell);
|
||
|
}
|
||
|
|
||
|
/* does not do evaluate expression on cell
|
||
|
returns NULL when called with cell->type CELL_BIGINT
|
||
|
else returns numPtr which mast be freed or use by caller
|
||
|
*/
|
||
|
int * getBigintSizeDirect(CELL * cell, int * * numPtr, int * len)
|
||
|
{
|
||
|
int size = 0;
|
||
|
int * num = NULL;
|
||
|
|
||
|
#ifndef NEWLISP64
|
||
|
if(cell->type == CELL_INT64)
|
||
|
num = intToBigint(*(INT64 *)&cell->aux, &size);
|
||
|
else if(cell->type == CELL_LONG)
|
||
|
num = intToBigint((INT64)cell->contents, &size);
|
||
|
else if(cell->type == CELL_FLOAT)
|
||
|
{
|
||
|
#ifdef WINDOWS
|
||
|
if(isnan(*(double *)&cell->aux) || !_finite(*(double *)&cell->aux))
|
||
|
num = intToBigint(0, &size);
|
||
|
num = floatToBigint(*(double *)&cell->aux, &size);
|
||
|
#else
|
||
|
if(isnan(*(double *)&cell->aux))
|
||
|
num = intToBigint(0, &size);
|
||
|
num = floatToBigint(*(double *)&cell->aux, &size);
|
||
|
#endif
|
||
|
}
|
||
|
#else /* NEWLISP64 */
|
||
|
if(cell->type == CELL_LONG)
|
||
|
num = intToBigint((INT64)cell->contents, &size);
|
||
|
else if(cell->type == CELL_FLOAT)
|
||
|
{
|
||
|
if(isnan(*(double *)&cell->contents))
|
||
|
num = intToBigint(0, &size);
|
||
|
num = floatToBigint( *(double *)&cell->contents, &size);
|
||
|
}
|
||
|
#endif
|
||
|
else if(cell->type == CELL_BIGINT)
|
||
|
{
|
||
|
*numPtr = (int *)cell->contents;
|
||
|
*len = cell->aux - 1;
|
||
|
return(NULL);
|
||
|
}
|
||
|
else
|
||
|
errorProcArgs(ERR_NUMBER_EXPECTED, cell);
|
||
|
|
||
|
*numPtr = num;
|
||
|
*len = size;
|
||
|
|
||
|
return(num);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* memory for num int array is allocated inside
|
||
|
return is ptr to the int array and length in *intlen
|
||
|
*/
|
||
|
int * strToBigint(char * str, int len, int * intlen)
|
||
|
{
|
||
|
int n, i, j, cut;
|
||
|
int sign = 1;
|
||
|
char * ptr = str;
|
||
|
int * num;
|
||
|
|
||
|
/* don't look at trailing L */
|
||
|
if(*(str + len - 1) == 'L')
|
||
|
len--;
|
||
|
|
||
|
/* skip leading sign */
|
||
|
if(*ptr == '-' || *ptr == '+')
|
||
|
{
|
||
|
sign = (*ptr == '-') ? -1 : 1;
|
||
|
ptr++;
|
||
|
len--;
|
||
|
}
|
||
|
|
||
|
/* remove leading zeros */
|
||
|
while(len > 1 && *ptr == '0')
|
||
|
{
|
||
|
ptr++;
|
||
|
len--;
|
||
|
}
|
||
|
|
||
|
n = len / 9 + 1;
|
||
|
cut = len % 9;
|
||
|
if(cut) n++;
|
||
|
else cut = 9;
|
||
|
|
||
|
num = calloc(sizeof(int), n);
|
||
|
num[0] = sign;
|
||
|
|
||
|
for(i = 1; i < n; i++)
|
||
|
{
|
||
|
for(j = 0; j < cut; j++)
|
||
|
num[i] = 10 * num[i] + ptr[j] - 48;
|
||
|
ptr += cut;
|
||
|
cut = 9;
|
||
|
}
|
||
|
|
||
|
*intlen = n - 1;
|
||
|
return(num);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* when offset is specified (48) '+' is suppressed only '-' is put
|
||
|
when offset = 0, first digit is either -1 or 1
|
||
|
call with offset either 0 or 48
|
||
|
do ot call with 0 for num
|
||
|
*/
|
||
|
char * bigintToDigits(int * num, int n, int offset, int * slen)
|
||
|
{
|
||
|
int i, j, k = 0, cnt = 0, len = 0;
|
||
|
int q, basediv;
|
||
|
char * digits;
|
||
|
int bigdigit;
|
||
|
|
||
|
if(n == 1 && num[1] == 0)
|
||
|
{
|
||
|
digits = calloc(3, 1);
|
||
|
if(offset == 0)
|
||
|
{
|
||
|
digits[0] = '1';
|
||
|
digits[1] = 0;
|
||
|
}
|
||
|
else
|
||
|
digits[0] = '0';
|
||
|
return(digits);
|
||
|
}
|
||
|
|
||
|
/* cnt of digits in first big digit */
|
||
|
bigdigit = num[1];
|
||
|
basediv = BIGINT_BASE / 10;
|
||
|
while(bigdigit / basediv == 0)
|
||
|
{
|
||
|
basediv /= 10;
|
||
|
cnt++;
|
||
|
}
|
||
|
|
||
|
cnt = 9 - cnt;
|
||
|
len = 9 * (n - 1) + cnt;
|
||
|
|
||
|
digits = calloc(len + 2, 1);
|
||
|
if(offset != 0)
|
||
|
{
|
||
|
if(num[0] == -1) digits[k++] = '-';
|
||
|
}
|
||
|
else
|
||
|
digits[k++] = num[0];
|
||
|
|
||
|
for(i = 1; i <=n; i++)
|
||
|
{
|
||
|
bigdigit = num[i];
|
||
|
for(j = 0; j < cnt; j++)
|
||
|
{
|
||
|
q = bigdigit / basediv;
|
||
|
digits[k++] = q + offset;
|
||
|
bigdigit -= q * basediv;
|
||
|
basediv /= 10;
|
||
|
}
|
||
|
basediv = BIGINT_BASE / 10;
|
||
|
cnt = 9;
|
||
|
}
|
||
|
|
||
|
if(slen) *slen = len;
|
||
|
return(digits);
|
||
|
}
|
||
|
|
||
|
/* digits come in high to low with leading sign digit (1 or -1)
|
||
|
nx and ny are the length without sign digit
|
||
|
*/
|
||
|
|
||
|
int * addBigint(int * x, int nx, int * y, int ny, int * sm, int * nsm)
|
||
|
{
|
||
|
int i, carry = 0, digit, n, d, sign;
|
||
|
int * ptr;
|
||
|
|
||
|
if(nx < ny)
|
||
|
{
|
||
|
n = nx; nx = ny; ny = n;
|
||
|
ptr = x; x = y; y = ptr;
|
||
|
}
|
||
|
d = nx - ny;
|
||
|
|
||
|
if(*x != *y) /* signs are different */
|
||
|
{
|
||
|
sign = x[0];
|
||
|
y[0] = sign;
|
||
|
sm = subBigint(x, nx, y, ny, sm, nsm);
|
||
|
x[0] = sign; y[0] = sign * -1;
|
||
|
return(sm);
|
||
|
}
|
||
|
|
||
|
ptr = sm + 1;
|
||
|
|
||
|
/* memset(sm, 0, (nx + 2) * sizeof(int)); */
|
||
|
|
||
|
for(i = ny; i > 0; i--) /* ny is the smaller */
|
||
|
{
|
||
|
digit = x[i + d] + y[i] + carry;
|
||
|
carry = digit / BIGINT_BASE;
|
||
|
ptr[i + d] = digit % BIGINT_BASE;
|
||
|
}
|
||
|
|
||
|
for(i = nx - ny; i > 0; i--) /* nx is the bigger */
|
||
|
{
|
||
|
digit = x[i] + carry;
|
||
|
carry = digit / BIGINT_BASE;
|
||
|
ptr[i] = digit % BIGINT_BASE;
|
||
|
}
|
||
|
ptr[0] = carry;
|
||
|
|
||
|
if(*ptr == 0)
|
||
|
{
|
||
|
for(i = 0; i < nx; i++)
|
||
|
ptr[i] = ptr[i + 1];
|
||
|
*nsm = nx;
|
||
|
}
|
||
|
else
|
||
|
*nsm = nx + 1;
|
||
|
|
||
|
sm[0] = x[0];
|
||
|
|
||
|
return(sm);
|
||
|
}
|
||
|
|
||
|
|
||
|
int * subBigint(int * x, int nx, int * y, int ny, int * sm, int * nsm)
|
||
|
{
|
||
|
INT64 digit;
|
||
|
int * ptr;
|
||
|
int sign, i, j, n, carry = 0;
|
||
|
|
||
|
if(*x != *y)
|
||
|
{
|
||
|
sign = x[0];
|
||
|
y[0] = sign;
|
||
|
addBigint(x, nx, y, ny, sm, nsm);
|
||
|
x[0] = sign; y[0] = sign * -1;
|
||
|
return(sm);
|
||
|
}
|
||
|
|
||
|
/* compare and subtract the abs(smaller) from the abs(greater) */
|
||
|
if(cmpAbsBigint(x, nx, y, ny) >= 1)
|
||
|
sm[0] = x[0];
|
||
|
else
|
||
|
{
|
||
|
sm[0] = x[0] * -1;
|
||
|
n = nx; nx = ny; ny = n;
|
||
|
ptr = x; x = y; y = ptr;
|
||
|
}
|
||
|
|
||
|
for(i = nx, j = ny; i > 0; i--, j--)
|
||
|
{
|
||
|
if(j > 0)
|
||
|
digit = (INT64)x[i] - y[j] - carry;
|
||
|
else
|
||
|
digit = (INT64)x[i] - carry;
|
||
|
if(digit < 0)
|
||
|
{
|
||
|
digit = digit + BIGINT_BASE;
|
||
|
carry = 1;
|
||
|
}
|
||
|
else
|
||
|
carry = 0;
|
||
|
|
||
|
sm[i] = digit % BIGINT_BASE;
|
||
|
}
|
||
|
|
||
|
i = 1; n = 0;
|
||
|
|
||
|
/* remove leading zero's */
|
||
|
while (sm[i] == 0 && i <= nx) n++, i++;
|
||
|
if(n == nx)
|
||
|
{
|
||
|
*nsm = 1;
|
||
|
return(sm);
|
||
|
}
|
||
|
|
||
|
memmove((char *)sm + 1 * sizeof(int), (char *)sm + (n + 1) * sizeof(int), (nx - n) * sizeof(int));
|
||
|
*nsm = (nx - n);
|
||
|
|
||
|
return(sm);
|
||
|
}
|
||
|
|
||
|
|
||
|
int * mulBigint(int * x, int nx, int * y, int ny, int * p, int * n)
|
||
|
{
|
||
|
int i, j, k, carry;
|
||
|
INT64 digit;
|
||
|
|
||
|
memset(p, 0, (nx + ny + 1) * sizeof(int));
|
||
|
for(i = ny; i > 0 ; i--) /* for each digit in multiplier */
|
||
|
{
|
||
|
carry = 0;
|
||
|
for(j = nx; j > 0; j--)
|
||
|
{
|
||
|
digit = (INT64)p[j + i] + (INT64)y[i] * x[j] + carry;
|
||
|
carry = digit / BIGINT_BASE;
|
||
|
p[j + i] = digit % BIGINT_BASE;
|
||
|
}
|
||
|
digit = (INT64)p[i] + carry;
|
||
|
p[i] = digit % BIGINT_BASE;
|
||
|
}
|
||
|
|
||
|
/* remove leading zero's */
|
||
|
k = nx + ny;
|
||
|
while(p[1] == 0 && k > 1)
|
||
|
{
|
||
|
for(i = 1; i < k; i++)
|
||
|
p[i] = p[i + 1];
|
||
|
k--;
|
||
|
}
|
||
|
|
||
|
/* set sign and n */
|
||
|
*p = *x * *y;
|
||
|
*n = k;
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* q = x/y - caller must _not_ allocate space for q
|
||
|
*/
|
||
|
int * divModBigint(int * x, int nx, int * y, int ny, int rmndr, int * nq)
|
||
|
{
|
||
|
int * r;
|
||
|
int * q;
|
||
|
int * p;
|
||
|
int * ptr;
|
||
|
INT64 digit;
|
||
|
int i, j, k, carry;
|
||
|
int nr, sq, n, pn;
|
||
|
/* turn of certain optimizations using 'volatile' necessary
|
||
|
on Linux but will no affect performance on other platforms
|
||
|
*/
|
||
|
volatile double rFloat, yFloat;
|
||
|
|
||
|
if(y[1] == 0 && ny == 1)
|
||
|
errorProc(ERR_MATH);
|
||
|
|
||
|
if(cmpAbsBigint(x, nx, y, ny) < 0)
|
||
|
{
|
||
|
if(rmndr)
|
||
|
{
|
||
|
q = malloc((nx + 1) * sizeof(int));
|
||
|
memcpy((void *)q, (void *)x, (nx + 1) * sizeof(int));
|
||
|
*nq = nx;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
q = malloc(sizeof(int) * 2);
|
||
|
q[0] = 1; q[1] = 0;
|
||
|
*nq = 1;
|
||
|
}
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
r = alloca((nx + 1) * sizeof(int));
|
||
|
q = alloca((nx - ny + 1) * sizeof(int));
|
||
|
p = alloca((nx + 1) * sizeof(int));
|
||
|
|
||
|
nr = 0; sq = 0;
|
||
|
r[0] = q[0] = p[0] = 1;
|
||
|
yFloat = bigintToAbsFloat(y, (ny > 2) ? 2 : ny);
|
||
|
#ifdef DEBUG
|
||
|
printf("yFloat %f\n", yFloat);
|
||
|
#endif
|
||
|
for(i = 1; i <= nx; i++)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("i = %d\n", i);
|
||
|
#endif
|
||
|
r[++nr] = x[i];
|
||
|
#ifdef DEBUG
|
||
|
debug(r, nr, "r after <- x[i]");
|
||
|
#endif
|
||
|
if(sq == 0 && cmpAbsBigint(r, nr, y, ny) < 0)
|
||
|
continue;
|
||
|
|
||
|
n = (ny > 2) ? (nr + 2 - ny) : nr;
|
||
|
rFloat = bigintToAbsFloat(r, n);
|
||
|
#ifdef DEBUG
|
||
|
printf("rFloat %f\n", rFloat);
|
||
|
#endif
|
||
|
|
||
|
if(yFloat > rFloat)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("yFloat > rFloat\n");
|
||
|
#endif
|
||
|
q[++sq] = 0;
|
||
|
goto TRIM_ZEROS;
|
||
|
}
|
||
|
|
||
|
if(yFloat == rFloat)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
printf("yFloat == rFloat\n");
|
||
|
#endif
|
||
|
q[++sq] = 1;
|
||
|
}
|
||
|
else
|
||
|
q[++sq] = rFloat / yFloat + 1.0; /* like ceil() */
|
||
|
#ifdef DEBUG
|
||
|
debug(q, sq, "q after float div");
|
||
|
#endif
|
||
|
|
||
|
PRODUCT:
|
||
|
carry = 0;
|
||
|
for(j = ny, pn = ny; j > 0; j--)
|
||
|
{
|
||
|
digit = (INT64)y[j] * q[sq] + carry;
|
||
|
if(digit >= BIGINT_BASE)
|
||
|
{
|
||
|
p[j] = digit % BIGINT_BASE;
|
||
|
carry = digit/BIGINT_BASE;
|
||
|
}
|
||
|
else
|
||
|
p[j] = digit, carry = 0;
|
||
|
}
|
||
|
if(carry) /* shift right */
|
||
|
{
|
||
|
for(j = ny; j > 0; j--) p[j+1] = p[j];
|
||
|
p[1] = carry, ++pn;
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
debug(p, pn, "p product");
|
||
|
#endif
|
||
|
if(cmpAbsBigint(r, nr, p, pn) < 0)
|
||
|
{
|
||
|
q[sq] = q[sq] - 1; /* q[sq] too big */
|
||
|
#ifdef DEBUG
|
||
|
printf("decrementing q[sq]\n");
|
||
|
#endif
|
||
|
goto PRODUCT;
|
||
|
}
|
||
|
|
||
|
/* ----- inlined from subBigint ----- */
|
||
|
for(k = nr, j = pn, carry = 0; k > 0; k--, j--)
|
||
|
{
|
||
|
if(j > 0)
|
||
|
digit = (INT64)r[k] - p[j] - carry;
|
||
|
else
|
||
|
digit = (INT64)r[k] - carry;
|
||
|
if(digit < 0)
|
||
|
{
|
||
|
digit += BIGINT_BASE;
|
||
|
carry = 1;
|
||
|
}
|
||
|
else
|
||
|
carry = 0;
|
||
|
|
||
|
r[k] = digit % BIGINT_BASE;
|
||
|
}
|
||
|
/* trim leading zero's */
|
||
|
TRIM_ZEROS:
|
||
|
if(r[1] == 0) {
|
||
|
k = 1; n = 0;
|
||
|
while (r[k] == 0 && k <= nr) n++, k++;
|
||
|
if(n == nr) nr = 1;
|
||
|
else
|
||
|
{
|
||
|
nr = (nr - n);
|
||
|
memmove((char *)r + 1 * sizeof(int),
|
||
|
(char *)r + (n + 1) * sizeof(int), nr * sizeof(int));
|
||
|
}
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
debug(r, nr, "r after subtraction and trimming");
|
||
|
#endif
|
||
|
/* ---------------------------------- */
|
||
|
if(r[1] == 0 && i < nx) nr = 0;
|
||
|
}
|
||
|
|
||
|
if(rmndr)
|
||
|
{
|
||
|
q = malloc((nr + 1) * sizeof(int));
|
||
|
memcpy((void *)q, (void *) r, (nr + 1) * sizeof(int));
|
||
|
q[0] = x[0]; /* set sign */
|
||
|
*nq = nr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ptr = malloc((sq + 1) * sizeof(int));
|
||
|
memcpy((void *)ptr, (void *)q, (sq + 1) * sizeof(int));
|
||
|
q = ptr;
|
||
|
q[0] = *x * *y;
|
||
|
*nq = sq;
|
||
|
}
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
|
||
|
int cmpAbsBigint(int * x, int nx, int * y, int ny)
|
||
|
{
|
||
|
int cmp, i;
|
||
|
|
||
|
cmp = nx - ny;
|
||
|
if(cmp == 0)
|
||
|
{
|
||
|
for(i = 1; i <= nx; i++)
|
||
|
{
|
||
|
if(x[i] > y[i]) return(1);
|
||
|
if(x[i] < y[i]) return(-1);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
return (cmp > 0) ? 1 : -1;
|
||
|
}
|
||
|
|
||
|
int cmpBigint(int * x, int nx, int * y, int ny)
|
||
|
{
|
||
|
int cmp;
|
||
|
|
||
|
/* make sure 0 == -0 */
|
||
|
if(nx == 1 && ny == 1 && x[1] == 0 && y[1] == 0)
|
||
|
return(0);
|
||
|
|
||
|
if(*x > *y) return(1);
|
||
|
if(*x < *y) return(-1);
|
||
|
|
||
|
/* signs are both 1,1 or -1, -1 */
|
||
|
cmp = cmpAbsBigint(x, nx, y, ny);
|
||
|
|
||
|
return(cmp * *x);
|
||
|
}
|
||
|
|
||
|
/* biggest int64 9 223372036 854775807
|
||
|
smallest int64 -9 223372036 854775808
|
||
|
*/
|
||
|
|
||
|
INT64 bigintToInt64(CELL * cell)
|
||
|
{
|
||
|
INT64 num;
|
||
|
int * numPtr;
|
||
|
int i;
|
||
|
|
||
|
int maxInt[4] = {1, 9, 223372036, 854775807};
|
||
|
int minInt[4] = {-1, 9, 223372036, 854775808};
|
||
|
|
||
|
numPtr = (int *)(UINT)cell->contents;
|
||
|
if(cmpBigint((int *)(UINT)cell->contents, cell->aux -1, maxInt, 3) == 1 ||
|
||
|
cmpBigint((int *)(UINT)cell->contents, cell->aux - 1, minInt, 3) == -1)
|
||
|
errorProc(ERR_NUMBER_OUT_OF_RANGE);
|
||
|
|
||
|
num = numPtr[1];
|
||
|
for(i = 2; i < cell->aux; i++)
|
||
|
num = num * BIGINT_BASE + numPtr[i];
|
||
|
|
||
|
num = num * numPtr[0];
|
||
|
|
||
|
return(num);
|
||
|
}
|
||
|
|
||
|
int * intToBigint(INT64 num, int * len)
|
||
|
{
|
||
|
int idx = 1;
|
||
|
int * digit;
|
||
|
|
||
|
digit = malloc(4 * sizeof(int));
|
||
|
|
||
|
if(num < 0)
|
||
|
{
|
||
|
digit[0] = -1;
|
||
|
num = -num;
|
||
|
}
|
||
|
else
|
||
|
digit[0] = 1;
|
||
|
|
||
|
if(num > BIGINT_BASE2)
|
||
|
{
|
||
|
digit[idx] = (int)(num / BIGINT_BASE2);
|
||
|
num = num - digit[idx] * BIGINT_BASE2;
|
||
|
idx++;
|
||
|
}
|
||
|
|
||
|
if(num > BIGINT_BASE)
|
||
|
{
|
||
|
digit[idx] =(int)(num / BIGINT_BASE);
|
||
|
num = num - digit[idx] * BIGINT_BASE;
|
||
|
idx++;
|
||
|
}
|
||
|
|
||
|
digit[idx] = num;
|
||
|
|
||
|
*len = idx;
|
||
|
|
||
|
return(digit);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* only used internally by divModBigint()
|
||
|
does not check for overflow */
|
||
|
double bigintToAbsFloat(int * numPtr, int n)
|
||
|
{
|
||
|
double value;
|
||
|
int i;
|
||
|
|
||
|
value = numPtr[1];
|
||
|
for(i = 2; i <= n; i++)
|
||
|
value = value * BIGINT_BASE + numPtr[i];
|
||
|
|
||
|
return(value);
|
||
|
}
|
||
|
|
||
|
|
||
|
double bigintCellToFloat(CELL * cell)
|
||
|
{
|
||
|
double value;
|
||
|
int * numPtr;
|
||
|
int i;
|
||
|
|
||
|
numPtr = (int *)(UINT)cell->contents;
|
||
|
value = numPtr[1];
|
||
|
for(i = 2; i < cell->aux; i++)
|
||
|
{
|
||
|
value = value * BIGINT_BASE + numPtr[i];
|
||
|
if( value > 1.797693134862301e308)
|
||
|
return(1/0.0);
|
||
|
}
|
||
|
|
||
|
value *= numPtr[0];
|
||
|
|
||
|
return(value);
|
||
|
}
|
||
|
|
||
|
int * floatToBigint(double fnum, int * len)
|
||
|
{
|
||
|
int decDigits, bigDigits;
|
||
|
int inum, i, sign;
|
||
|
int * numPtr;
|
||
|
|
||
|
#ifdef SOLARIS
|
||
|
if(isnan(fnum - fnum))
|
||
|
#else
|
||
|
if(isinf(fnum))
|
||
|
#endif
|
||
|
errorProcExt2(ERR_CANNOT_CONVERT, stuffFloat(fnum));
|
||
|
|
||
|
sign = fnum < 0 ? -1 : 1;
|
||
|
fnum = fnum * sign;
|
||
|
|
||
|
/* account for rounding errors */
|
||
|
if(fnum > 1.797693134862301e308)
|
||
|
fnum = 1.797693134862301e308;
|
||
|
|
||
|
decDigits = log(fnum) / log(10) + 1;
|
||
|
if(decDigits <= 0)
|
||
|
{
|
||
|
numPtr = calloc(2, sizeof(int));
|
||
|
numPtr[0] = 1;
|
||
|
*len = 1;
|
||
|
return(numPtr);
|
||
|
}
|
||
|
|
||
|
bigDigits = ((decDigits - 1) / 9) + 1;
|
||
|
*len = bigDigits;
|
||
|
numPtr = calloc(bigDigits + 3, sizeof(int));
|
||
|
numPtr[0] = sign;
|
||
|
for(i = 1; i <= 3; i++)
|
||
|
{
|
||
|
inum = fnum / pow(1000000000, (bigDigits - i));
|
||
|
numPtr[i] = inum;
|
||
|
fnum = fnum - (INT64)inum * pow(1000000000, (bigDigits - i));
|
||
|
}
|
||
|
|
||
|
return(numPtr);
|
||
|
}
|
||
|
|
||
|
int lengthBigint(int * num, int len)
|
||
|
{
|
||
|
int cnt = 0;
|
||
|
int bigdigit, basediv;
|
||
|
|
||
|
if((bigdigit = num[1]) == 0) return(1);
|
||
|
|
||
|
basediv = BIGINT_BASE / 10;
|
||
|
while(bigdigit / basediv == 0)
|
||
|
basediv /= 10, cnt++;
|
||
|
|
||
|
return(9 * (len - 1) + 9 - cnt);
|
||
|
}
|
||
|
#endif
|
||
|
/* eof */
|