diff --git a/src/apps/aboutsystem/AboutSystem.cpp b/src/apps/aboutsystem/AboutSystem.cpp index c4182d7489..59d42e54b7 100644 --- a/src/apps/aboutsystem/AboutSystem.cpp +++ b/src/apps/aboutsystem/AboutSystem.cpp @@ -762,6 +762,12 @@ AboutView::AboutView(const BRect &rect) "Copyright " B_UTF8_COPYRIGHT " 1996-1997 Jeff Prosise. " "All rights reserved."); + // MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc + AddCopyrightEntry("MAPM", + "Copyright " B_UTF8_COPYRIGHT "1999-2007 Michael C. Ring. " + "All rights reserved.", + "http://tc.umn.edu/~ringx004"); + // OpenSound // AddCopyrightEntry("OpenSound", // "Copyright " B_UTF8_COPYRIGHT " 1996-2008 4Front Technologies ", diff --git a/src/apps/deskcalc/CalcView.cpp b/src/apps/deskcalc/CalcView.cpp index 33a5ebf47d..be110deb99 100644 --- a/src/apps/deskcalc/CalcView.cpp +++ b/src/apps/deskcalc/CalcView.cpp @@ -774,9 +774,6 @@ CalcView::SaveSettings(BMessage* archive) const void CalcView::Evaluate() { - const double EXP_SWITCH_HI = 1e12; // # digits to switch from std->exp form - const double EXP_SWITCH_LO = 1e-12; - BString expression = fExpressionTextView->Text(); if (expression.Length() == 0) { @@ -792,10 +789,8 @@ CalcView::Evaluate() play_sound(&zimp_ref, true, false, false); } -//printf("evaluate: %s\n", expression.String()); - // evaluate expression - double value = 0.0; + BString value; try { ExpressionParser parser; @@ -807,37 +802,8 @@ CalcView::Evaluate() return; } -//printf(" -> value: %f\n", value); - - // beautify the expression - // TODO: see if this is necessary at all - char buf[64]; - if (value == 0) { - strcpy(buf, "0"); - } else if (((value < EXP_SWITCH_HI) && (value > EXP_SWITCH_LO)) || - ((value > -EXP_SWITCH_HI) && (value < -EXP_SWITCH_LO))) { - // print in std form - sprintf(buf, "%.13f", value); - - // hack to remove surplus zeros! - if (strchr(buf, '.')) { - int32 i = strlen(buf) - 1; - for (; i > 0; i--) { - if (buf[i] == '0') - buf[i] = '\0'; - else - break; - } - if (buf[i] == '.') - buf[i] = '\0'; - } - } else { - // print in exponential form - sprintf(buf, "%e", value); - } - // render new result to display - fExpressionTextView->SetExpression(buf); + fExpressionTextView->SetExpression(value.String()); } diff --git a/src/apps/deskcalc/DeskCalc.cpp b/src/apps/deskcalc/DeskCalc.cpp index 8b9cf5c596..eda05006b4 100644 --- a/src/apps/deskcalc/DeskCalc.cpp +++ b/src/apps/deskcalc/DeskCalc.cpp @@ -33,7 +33,8 @@ main(int argc, char* argv[]) try { ExpressionParser parser; - printf("%f\n", parser.Evaluate(expression.String())); + BString result = parser.Evaluate(expression.String()); + printf("%s\n", result.String()); } catch (ParseException e) { printf("%s at %ld\n", e.message.String(), e.position + 1); return 1; diff --git a/src/apps/deskcalc/ExpressionParser.cpp b/src/apps/deskcalc/ExpressionParser.cpp index db407ae7fa..18bdc42029 100644 --- a/src/apps/deskcalc/ExpressionParser.cpp +++ b/src/apps/deskcalc/ExpressionParser.cpp @@ -12,8 +12,12 @@ #include #include +#include "m_apm.h" + #include "ExpressionParser.h" +static const int32 kMaxDigits = 64; + enum { TOKEN_IDENTIFIER = 'a', @@ -44,7 +48,7 @@ struct Token { Token() : string(""), type(TOKEN_NONE), - value(0.0), + value(0), position(0) { } @@ -60,7 +64,7 @@ struct Token { Token(const char* string, int32 length, int32 position, int32 type) : string(string, length), type(type), - value(0.0), + value(0), position(position) { } @@ -76,7 +80,7 @@ struct Token { BString string; int32 type; - double value; + MAPM value; int32 position; }; @@ -137,23 +141,30 @@ class Tokenizer { fCurrentChar++; } int32 length = fCurrentChar - begin; - temp << "&_"; + BString test = temp; + test << "&_"; double value; char t[2]; - int32 matches = sscanf(temp.String(), "%lf&%s", &value, t); - if (matches != 2) - throw ParseException("error in constant", _CurrentPos() - length); + int32 matches = sscanf(test.String(), "%lf&%s", &value, t); + if (matches != 2) { + throw ParseException("error in constant", + _CurrentPos() - length); + } - fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_CONSTANT); - fCurrentToken.value = value;; + fCurrentToken = Token(begin, length, _CurrentPos() - length, + TOKEN_CONSTANT); + fCurrentToken.value = temp.String(); } else if (isalpha(*fCurrentChar)) { const char* begin = fCurrentChar; - while (*fCurrentChar != 0 && (isalpha(*fCurrentChar) || isdigit(*fCurrentChar))) + while (*fCurrentChar != 0 && (isalpha(*fCurrentChar) + || isdigit(*fCurrentChar))) { fCurrentChar++; + } int32 length = fCurrentChar - begin; - fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_IDENTIFIER); + fCurrentToken = Token(begin, length, _CurrentPos() - length, + TOKEN_IDENTIFIER); } else { @@ -172,7 +183,8 @@ class Tokenizer { case '&': case '|': case '~': - fCurrentToken = Token(fCurrentChar, 1, _CurrentPos(), *fCurrentChar); + fCurrentToken = Token(fCurrentChar, 1, _CurrentPos(), + *fCurrentChar); fCurrentChar++; break; @@ -215,48 +227,73 @@ ExpressionParser::~ExpressionParser() } -double +BString ExpressionParser::Evaluate(const char* expressionString) { fTokenizer->SetTo(expressionString); - double value = _ParseBinary(); + MAPM value = _ParseBinary(); Token token = fTokenizer->NextToken(); if (token.type != TOKEN_END_OF_LINE) throw ParseException("parse error", token.position); - return value; + if (value == 0) + return BString("0"); + + BString result; + char* buffer = result.LockBuffer(kMaxDigits + 1); + // + 1 for the decimal point + if (buffer == NULL) + throw ParseException("out of memory", 0); + + value.toFixPtString(buffer, kMaxDigits); + + // remove surplus zeros + int32 lastChar = strlen(buffer) - 1; + if (strchr(buffer, '.')) { + while (buffer[lastChar] == '0') + lastChar--; + if (buffer[lastChar] == '.') + lastChar--; + } + result.UnlockBuffer(lastChar + 1); + + return result; } -double +MAPM ExpressionParser::_ParseBinary() { - double value = _ParseSum(); + return _ParseSum(); + // binary operation appearantly not supported by m_apm library, + // should not be too hard to implement though.... - while (true) { - Token token = fTokenizer->NextToken(); - switch (token.type) { - case TOKEN_AND: - value = (uint64)value & (uint64)_ParseSum(); - break; - case TOKEN_OR: - value = (uint64)value | (uint64)_ParseSum(); - break; - - default: - fTokenizer->RewindToken(); - return value; - } - } +// double value = _ParseSum(); +// +// while (true) { +// Token token = fTokenizer->NextToken(); +// switch (token.type) { +// case TOKEN_AND: +// value = (uint64)value & (uint64)_ParseSum(); +// break; +// case TOKEN_OR: +// value = (uint64)value | (uint64)_ParseSum(); +// break; +// +// default: +// fTokenizer->RewindToken(); +// return value; +// } +// } } -double +MAPM ExpressionParser::_ParseSum() { // TODO: check isnan()... - double value = _ParseProduct(); + MAPM value = _ParseProduct(); while (true) { Token token = fTokenizer->NextToken(); @@ -276,11 +313,11 @@ ExpressionParser::_ParseSum() } -double +MAPM ExpressionParser::_ParseProduct() { // TODO: check isnan()... - double value = _ParsePower(); + MAPM value = _ParsePower(); while (true) { Token token = fTokenizer->NextToken(); @@ -289,17 +326,17 @@ ExpressionParser::_ParseProduct() value = value * _ParsePower(); break; case TOKEN_SLASH: { - double rhs = _ParsePower(); - if (rhs == 0.0) + MAPM rhs = _ParsePower(); + if (rhs == MAPM(0)) throw ParseException("division by zero", token.position); value = value / rhs; break; } case TOKEN_MODULO: { - double rhs = _ParsePower(); - if (rhs == 0.0) + MAPM rhs = _ParsePower(); + if (rhs == MAPM(0)) throw ParseException("modulo by zero", token.position); - value = fmod(value, rhs); + value = value % rhs; break; } @@ -311,10 +348,10 @@ ExpressionParser::_ParseProduct() } -double +MAPM ExpressionParser::_ParsePower() { - double value = _ParseUnary(); + MAPM value = _ParseUnary(); while (true) { Token token = fTokenizer->NextToken(); @@ -322,12 +359,12 @@ ExpressionParser::_ParsePower() fTokenizer->RewindToken(); return value; } - value = pow(value, _ParseUnary()); + value.pow(_ParseUnary()); } } -double +MAPM ExpressionParser::_ParseUnary() { Token token = fTokenizer->NextToken(); @@ -339,8 +376,9 @@ ExpressionParser::_ParseUnary() return _ParseUnary(); case TOKEN_MINUS: return -_ParseUnary(); - case TOKEN_NOT: - return ~(uint64)_ParseUnary(); +// TODO: Implement ! +// case TOKEN_NOT: +// return ~(uint64)_ParseUnary(); case TOKEN_IDENTIFIER: return _ParseFunction(token); @@ -350,7 +388,7 @@ ExpressionParser::_ParseUnary() return _ParseAtom(); } - return 0.0; + return MAPM(0); } @@ -358,76 +396,96 @@ struct Function { const char* name; int argumentCount; void* function; - double value; + MAPM value; }; -static const Function kFunctions[] = { - { "e", 0, NULL, M_E }, - { "pi", 0, NULL, M_PI }, - { "abs", 1, (void*)&fabs }, - { "acos", 1, (void*)&acos }, - { "asin", 1, (void*)&asin }, - { "atan", 1, (void*)&atan }, - { "atan2", 2, (void*)&atan2 }, - { "ceil", 1, (void*)&ceil }, - { "cos", 1, (void*)&cos }, - { "cosh", 1, (void*)&cosh }, - { "exp", 1, (void*)&exp }, - { "fabs", 1, (void*)&fabs }, - { "floor", 1, (void*)&floor }, - { "fmod", 2, (void*)&fmod }, - { "log", 1, (void*)&log }, - { "log10", 1, (void*)&log10 }, - { "pow", 2, (void*)&pow }, - { "sin", 1, (void*)&sin }, - { "sinh", 1, (void*)&sinh }, - { "sqrt", 1, (void*)&sqrt }, - { "tan", 1, (void*)&tan }, - { "tanh", 1, (void*)&tanh }, - { "hypot", 2, (void*)&hypot }, - - { NULL }, -}; - -double -ExpressionParser::_ParseFunction(const Token& token) +void +ExpressionParser::_InitArguments(MAPM values[], int32 argumentCount) { - const Function* function = _FindFunction(token.string.String()); - if (!function) - throw ParseException("unknown identifier", token.position); - - if (function->argumentCount == 0) - return function->value; - _EatToken(TOKEN_OPENING_BRACKET); - double values[function->argumentCount]; - for (int32 i = 0; i < function->argumentCount; i++) { + for (int32 i = 0; i < argumentCount; i++) values[i] = _ParseBinary(); - } _EatToken(TOKEN_CLOSING_BRACKET); - - // hard coded cases for different count of arguments - switch (function->argumentCount) { - case 1: - return ((double (*)(double))function->function)(values[0]); - case 2: - return ((double (*)(double, double))function->function)(values[0], - values[1]); - case 3: - return ((double (*)(double, double, double))function->function)( - values[0], values[1], values[2]); - - default: - throw ParseException("unsupported function argument count", - token.position); - } } -double +MAPM +ExpressionParser::_ParseFunction(const Token& token) +{ + if (strcasecmp("e", token.string.String()) == 0) + return MAPM(M_E); + else if (strcasecmp("pi", token.string.String()) == 0) + return MAPM(M_PI); + + // hard coded cases for different count of arguments + // supports functions with 3 arguments at most + + MAPM values[3]; + + if (strcasecmp("abs", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].abs(); + } else if (strcasecmp("acos", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].acos(); + } else if (strcasecmp("asin", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].asin(); + } else if (strcasecmp("atan", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].atan(); + } else if (strcasecmp("atan2", token.string.String()) == 0) { + _InitArguments(values, 2); + return values[0].atan2(values[1]); + } else if (strcasecmp("ceil", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].ceil(); + } else if (strcasecmp("cos", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].cos(); + } else if (strcasecmp("cosh", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].cosh(); + } else if (strcasecmp("exp", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].exp(); + } else if (strcasecmp("floor", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].floor(); + } else if (strcasecmp("log", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].log(); + } else if (strcasecmp("log10", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].log10(); + } else if (strcasecmp("pow", token.string.String()) == 0) { + _InitArguments(values, 2); + return values[0].pow(values[1]); + } else if (strcasecmp("sin", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].sin(); + } else if (strcasecmp("sinh", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].sinh(); + } else if (strcasecmp("sqrt", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].sqrt(); + } else if (strcasecmp("tan", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].tan(); + } else if (strcasecmp("tanh", token.string.String()) == 0) { + _InitArguments(values, 1); + return values[0].tanh(); + } + + throw ParseException("unknown identifier", token.position); +} + + +MAPM ExpressionParser::_ParseAtom() { Token token = fTokenizer->NextToken(); @@ -441,7 +499,7 @@ ExpressionParser::_ParseAtom() _EatToken(TOKEN_OPENING_BRACKET); - double value = _ParseBinary(); + MAPM value = _ParseBinary(); _EatToken(TOKEN_CLOSING_BRACKET); @@ -460,15 +518,3 @@ ExpressionParser::_EatToken(int32 type) } } - -const Function* -ExpressionParser::_FindFunction(const char* name) const -{ - for (int32 i = 0; kFunctions[i].name; i++) { - if (strcasecmp(kFunctions[i].name, name) == 0) - return &kFunctions[i]; - } - - return NULL; -} - diff --git a/src/apps/deskcalc/ExpressionParser.h b/src/apps/deskcalc/ExpressionParser.h index d5f855dfad..5875cfef0e 100644 --- a/src/apps/deskcalc/ExpressionParser.h +++ b/src/apps/deskcalc/ExpressionParser.h @@ -6,12 +6,13 @@ * Ingo Weinhold * Stephan Aßmus */ - #ifndef EXPRESSION_PARSER_H #define EXPRESSION_PARSER_H + #include + class Tokenizer; class ParseException { @@ -34,26 +35,28 @@ class ParseException { struct Function; struct Token; +class MAPM; class ExpressionParser { public: ExpressionParser(); ~ExpressionParser(); - double Evaluate(const char* expressionString); + BString Evaluate(const char* expressionString); private: - double _ParseBinary(); - double _ParseSum(); - double _ParseProduct(); - double _ParsePower(); - double _ParseUnary(); - double _ParseFunction(const Token& token); - double _ParseAtom(); + MAPM _ParseBinary(); + MAPM _ParseSum(); + MAPM _ParseProduct(); + MAPM _ParsePower(); + MAPM _ParseUnary(); + void _InitArguments(MAPM values[], + int32 argumentCount); + MAPM _ParseFunction(const Token& token); + MAPM _ParseAtom(); void _EatToken(int32 type); - const Function* _FindFunction(const char* name) const; Tokenizer* fTokenizer; }; diff --git a/src/apps/deskcalc/Jamfile b/src/apps/deskcalc/Jamfile index bd66aaca05..71611cf3e2 100644 --- a/src/apps/deskcalc/Jamfile +++ b/src/apps/deskcalc/Jamfile @@ -2,6 +2,8 @@ SubDir HAIKU_TOP src apps deskcalc ; SetSubDirSupportedPlatformsBeOSCompatible ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps deskcalc mapm_4.9.5 ] ; + Application DeskCalc : CalcApplication.cpp CalcOptionsWindow.cpp @@ -11,6 +13,47 @@ Application DeskCalc : ExpressionParser.cpp ExpressionTextView.cpp InputTextView.cpp + + # m_apm files + mapmhasn.c + mapmhsin.c + mapm_pow.c + mapm_log.c + mapm_lg2.c + mapm_lg4.c + mapm_exp.c + mapm_lg3.c + mapmasin.c + mapmasn0.c + mapm_sin.c + mapm5sin.c + mapmrsin.c + mapm_cpi.c + mapmsqrt.c + mapmcbrt.c + mapmgues.c + mapmfact.c + mapm_gcd.c + mapmipwr.c + mapmpwr2.c + mapm_rnd.c + mapm_flr.c + mapm_fpf.c + mapm_rcp.c + mapmstck.c + mapm_div.c + mapm_mul.c + mapmfmul.c + mapm_fft.c + mapm_add.c + mapmistr.c + mapm_set.c + mapm_fam.c + mapmutil.c + mapmutl2.c + mapmutl1.c + mapmcnst.c + : be $(TARGET_LIBSTDC++) media : DeskCalc.rdef ; diff --git a/src/apps/deskcalc/mapm_4.9.5/README b/src/apps/deskcalc/mapm_4.9.5/README new file mode 100644 index 0000000000..b0dc622821 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/README @@ -0,0 +1,769 @@ +************************************************************************** + + MAPM + + Version 4.9.5 + + December 10, 2007 + + Michael C. Ring + + ringx004@tc.umn.edu + + Latest release will be available at + http://tc.umn.edu/~ringx004 + +*************************************************************************** +* * +* Copyright (C) 1999 - 2007 Michael C. Ring * +* * +* This software is Freeware. * +* * +* Permission to use, copy, and distribute this software and its * +* documentation for any purpose with or without fee is hereby granted, * +* provided that the above copyright notice appear in all copies and * +* that both that copyright notice and this permission notice appear * +* in supporting documentation. * +* * +* Permission to modify the software is granted. Permission to distribute * +* the modified code is granted. Modifications are to be distributed by * +* using the file 'license.txt' as a template to modify the file header. * +* 'license.txt' is available in the official MAPM distribution. * +* * +* To distribute modified source code, insert the file 'license.txt' * +* at the top of all modified source code files and edit accordingly. * +* * +* This software is provided "as is" without express or implied warranty. * +* * +*************************************************************************** + + --------------------------------------- + Mike's Arbitrary Precision Math Library + --------------------------------------- + +Mike's Arbitrary Precision Math Library is a set of functions that +allow the user to perform math to any level of accuracy that is +desired. The inspiration for this library was Lloyd Zusman's similar +APM package that was released in ~1988. I borrowed some of his ideas +in my implementation, creating a new data type (MAPM) and how the data +type was used by the user. However, there were a few things I wanted +my library to do that the original library did not : + +1) Round a value to any desired precision. This is very handy when + multiplying for many iterations. Since multiplication guarantees an + exact result, the number of digits will grow without bound. I wanted + a way to trim the number of significant digits that were retained. + +2) A natural support for floating point values. From most of the other + libraries I looked at, they seem to have a preference for integer + only type math manipulations. (However, this library will also do + integer only math if you desire). + + And if a library can only do integers, it can't do ... + +3) Trig functions and other common C math library functions. This library + will perform the following functions to any desired precision level : + SQRT, CBRT, SIN, COS, TAN, ARC-SIN, ARC-COS, ARC-TAN, ARC-TAN2, LOG, + LOG10, EXP, POW, SINH, COSH, TANH, ARC-SINH, ARC-COSH, ARC-TANH, and + also FACTORIAL. The full 'math.h' is not duplicated, though I think + these are most of the important ones. My definition of what's important + is what I've actually used in a real application. + +************************************************************************** + +NOTE: + +There is a COMPILER BUG in Microsoft's Visual C++ 7.x (VS.NET 2003) which +prevents a C++ MAPM application from compiling. + +This only affects C++ applications. C applications are OK. + +The compiler bug creates an error C2676 similar to this: + +...\mapm-49\M_APM.H(###) : error C2676: binary operator '-': 'MAPM' +doesn't define this operator or a conversion to a suitable type for the +predefined operator. + +To work around this bug, go to http://www.microsoft.com + +In the upper right corner of web page, search for "814455". + +The results of the search will point you to an article on how to work +around the problem. + +************************************************************************** + +NOTE: MAPM Library History can now be found in 'history.txt' + +************************************************************************** + +ANOTHER NOTE: For the Windows/DOS distribution, the filename convention +will always be in 8.3 format. This is because there are some users who +still use 16 bit DOS .... + +(I really wasn't sure what to call this library. 'Arbitrary Precision Math' +is a defacto standard for what this does, but that name was already taken, +so I just put an 'M' in front of it ...) + +************************************************************************** + +MAPM LIBRARY NUMERICAL LIMITATIONS: + +A general floating point number is of the form: + +Sn.nnnnnnnnE+yyyy ex: -4.318384739357974916E+6215 +Sn.nnnnnnnnE-yyyy ex: +8.208237913789131096523645193E-12873 + +'S' is the sign, + or -. + +In MAPM, a number (n.nnnn...) may contain up to ( INT_MAX - 1 ) digits. + +For example, an MAPM number with a 16 bit integer may contain 2^15 or 32,767 +digits. An MAPM number with a 32 bit integer may contain 2^31 or 2,147,483,647 +digits. All MAPM numbers are stored in RAM, there is no "data on disk" option. +So to represent the maximum number of digits on a 32 bit CPU will require +greater than 2 Gig of RAM. + +If you have a CPU with 64 bit ints, then the limitation is 2^63 or +9,223,372,036,854,775,807. It should be a very long time before computers +have this much RAM in them. + +For the exponent (yyyy), the limitations are also INT_MAX and INT_MIN. + +For a 16 bit CPU, the largest number you can represent is approx +0.9999999....E+32767. (H) + +For a 16 bit CPU, the smallest number you can represent (other than 0) +is approx 0.1E-32767. (L) + +For a 32 bit CPU, the largest number you can represent is approx +0.9999999....E+2147483647. (H) + +For a 32 bit CPU, the smallest number you can represent (other than 0) +is approx 0.1E-2147483647. (L) + +The limitations for negative numbers are the same as positive numbers. + + + Real Number Axis + + +------------------------+ --- +--------------------------+ + | | | | | + -H -L 0.0 +L +H + + + +MAPM can represent real numbers from -H to -L, 0.0, +L to +H. + +The number of significant digits is typically only limited by available RAM. + +In MAPM, numerical overflows and underflows are not handled very well +(actually not at all). There really isn't a clean and portable way to +detect integer overflow and underflow. Per K&R C, the result of integer +overflow/underflow is implementation dependent. In assembly language, when +you add two numbers, you have access to a "carry flag" to see if an overflow +occurred. C has no analogous operator to a carry flag. + +It is up to the user to decide if the results are valid for a given operation. +In a 32 bit environment, the limit is so large that this is likely not an +issue for most typical applications. However, it doesn't take much to overflow +a 16 bit int so care should taken in a 16 bit environment. + +The reaction to an integer overflow/underflow is unknown at run-time: + + o) adding 2 large positive numbers may silently roll over to a + negative number. + o) in some embedded applications an integer overflow/underflow triggers + a hardware exception. + +Since I don't have control over where this library could possibly run, +I chose to ignore the problem for now. If anyone has some suggestions +(that's portable), please let me know. + +************************************************************************** + +KNOWN BUGS : (Other than integer overflow discussed above....) None + +************************************************************************** + +IF YOU ARE IN A HURRY ... + +UNIX: (assumes gcc compiler) + +run make (build library + 4 executables) + +run make -f makefile.osx (for MAC OSX) + +--- OR --- + +run: mklib (this will create the library, lib_mapm.a) + +run: mkdemo (this will create 4 executables, 'calc', 'validate', + 'primenum', and 'cpp_demo') + + +DOS / Win NT/9x (in a DOS window for NT/9x): + +see the file 'README.DOS' for instructions. + + +************************************************************************** + +calc: This is a command line version of an RPN calculator. If you are + familiar with RPN calculators, the use of this program will be + quite obvious. The default is 30 decimal places but this can be + changed with the '-d' command line option. This is not an + interactive program, it just computes an expression from the command + line. Run 'calc' with no arguments to get a list of the operators. + + compute : (345.2 * 87.33) - (11.88 / 3.21E-2) + + calc 345.2 87.33 x 11.88 3.21E-2 / - + result: 29776.22254205607476635514018692 + + + compute PI to 70 decimal places : (6 * arcsin(0.5)) + + calc -d70 6 .5 as x + result : +3.1415926535897932384626433832795028841971693993751058209749445923078164 + + calc -d70 -1 ac (arccos(-1) for fastest possible way) + +validate : This program will compare the MAPM math functions to the C + standard library functions, like sqrt, sin, exp, etc. This + should give the user a good idea that the library is operating + correctly. The program will also perform high precision math + using known quantities like PI, log(2), etc. + + 'validate' also attempts to obtain as much code coverage of the + library as is practical. I used 'gcov' (available with the gcc + distribution) to test the code coverage. 100% coverage is not + obtained, compromises must be made in order to have the program + run in a reasonable amount of time. + +primenum: This program will generate the first 10 prime numbers starting + with the number entered as an argument. + + Example: primenum 1234567890 will output (actually 1 per line): + this took ~3 sec on my Linux PC, a 350MHz PII. + + 1234567891, 1234567907, 1234567913, 1234567927, 1234567949, + 1234567967, 1234567981, 1234568021, 1234568029, 1234568047 + + +************************************************************************** + +To use the library, simply include 'm_apm.h' and link your program +with the library, libmapm.a (unix) or mapm.lib (dos). + +Note: If your system creates libraries with a '.a' extension, then the +library will be named libmapm.a. (This conforms to typical unix naming +conventions). + +Note: If your system creates libraries with a '.lib' extension, then the +library will be named mapm.lib. + +For unix builds, you also may need to specify the math library (-lm) when +linking. The reason is some of the MAPM functions use an iterative algorithm. +When you use an iterative solution, you have to supply an initial guess. I +use the standard math library to generate this initial guess. I debated +whether this library should be stand-alone, i.e. generate it's own initial +guesses with some algorithm. In the end, I decided using the standard math +library would not be a big inconvienence and also it was just too tempting +having an immediate 15 digits of precision. When you prime the iterative +routines with 15 accurate digits, the MAPM functions converge faster. + +See the file 'algorithms.used' to see a description of the algorithms I +used in the library. Some I derived on my own, others I borrowed from people +smarter than me. Version 2 of the library supports a 'fast' multiplication +algorithm. The algorithm used is described in the algorithms.used file. A +considerable amount of time went into finding fast algorithms for the +library. However, some could possibly be even better. If anyone has a +more efficient algorithm for any of these functions, I would like to here +from you. + +See the file 'function.ref' to see a description of all the functions in +the library and the calling conventions, prototypes, etc. + +See the file 'struct.ref' which documents how I store the numbers internally +in the MAPM data structure. This will not be needed for normal use, but it +will be very useful if you need to change/add to the existing library. + +************************************************************************** + +USING MAPM IN A MULTI-THREADED APPLICATION : + +Note that the default MAPM library is NOT thread safe. MAPM internal data +structures could get corrupted if multiple MAPM functions are active at the +same time. The user should guarantee that only one thread is performing +MAPM functions. This can usually be achieved by a call to the operating +system to obtain a 'semaphore', 'mutex', or 'critical code section' so the +operating system will guarantee that only one MAPM thread will be active +at a time. + +The necessary function wrappers for thread safe operation can be found in +the sub-directory 'multi_thread' (unix) or 'multithd' (Win/Dos). For now, +only Microsoft Visual C++ 6.0 is supported. + +************************************************************************** + +QUICK TEMPLATE FOR NORMAL USE : + +The MAPM math is done on a new data type called "M_APM". This is +actually a pointer to a structure, but the contents of the structure +should never be manipulated: all operations on MAPM entities are done +through a functional interface. + +The MAPM routines will automatically allocate enough space in their +results to hold the proper number of digits. + +The caller must initialize all MAPM values before the routines can +operate on them (including the values intended to contain results of +calculations). Once this initialization is done, the user never needs +to worry about resizing the MAPM values, as this is handled inside the +MAPM routines and is totally invisible to the user. + +The result of a MAPM operation cannot be one of the other MAPM operands. +If you want this to be the case, you must put the result into a +temporary variable and then assign (m_apm_copy) it to the appropriate operand. + +All of the MAPM math functions begin with m_apm_*. + +There are some predefined constants for your use. In case it's not obvious, +these should never appear as a 'result' parameter in a function call. + +The following constants are available : (declared in m_apm.h) + +MM_Zero MM_One MM_Two MM_Three +MM_Four MM_Five MM_Ten +MM_PI MM_HALF_PI MM_2_PI MM_E +MM_LOG_E_BASE_10 MM_LOG_10_BASE_E MM_LOG_2_BASE_E MM_LOG_3_BASE_E + + +The non-integer constants above (PI, log(2), etc) are accurate to 128 +decimal places. The file mapmcnst.c contains these constants. I've +included 512 digit constants in this file also that are commented out. +If you need more than 512 digits, you can simply use the 'calc' program +to generate more precise constants (or create more precise constants at +run-time in your app). The number of significant digits in the constants +should be 6-8 more than the value specified in the #define. + + +Basic plan of attack: + +(1) get your 'numbers' into M_APM format. +(2) do your high precision math. +(3) get the M_APM numbers back into a format you can use. + + +-------- (1) -------- + +#include "m_apm.h" /* must be included before any M_APM 'declares' */ + +M_APM area_mapm; /* declare your variables */ +M_APM tmp_mapm; +M_APM array_mapm[10]; /* can use normal array notation */ +M_APM array2d_mapm[10][10]; + +area_mapm = m_apm_init() /* init your variables */ +tmp_mapm = m_apm_init(); + +for (i=0; i < M; i++) /* must init every element of the array */ + array_mapm[i] = m_apm_init(); + +for (i=0; i < M; i++) + for (j=0; j < N; j++) + array2d_mapm[i][j] = m_apm_init(); + +/* + * there are 3 ways to convert your number into an M_APM number + * (see the file function.ref) + * + * a) literal string (exponential notation OK) + * b) long variable + * c) double variable + */ + +m_apm_set_string(tmp_mapm, "5.3286E-7"); +m_apm_set_long(array_mapm[6], -872253L); +m_apm_set_double(array2d_mapm[3][7], -529.4486711); + + +-------- (2) -------- + +do your math ... + +m_apm_add(cc_mapm, aa_mapm, MM_PI); +m_apm_divide(bb_mapm, DECIMAL_PLACES, aa_mapm, MM_LOG_2_BASE_E); +m_apm_sin(bb_mapm, DECIMAL_PLACES, aa_mapm); +whatever ... + + +-------- (3) -------- + +There are 5 total functions for converting an M_APM number into something +useful. (See the file 'function.ref' for full function descriptions) + +For these 5 functions, M_APM number -> string is the conversion + +=================== +==== METHOD 1 ==== : floating point values (m_apm_to_string) +=================== + +the format will be in scientific (exponential) notation + +output string = [-]n.nnnnnE+x or ...E-x + +where 'n' are digits and the exponent will be always be present, +including E+0 + +it's easy to convert this to a double: + +double dtmp = atof(out_buffer); + + +=================== +==== METHOD 2 ==== : floating point values (m_apm_to_fixpt_string) +=================== (m_apm_to_fixpt_stringex) + (m_apm_to_fixpt_stringexp) +the format will be in fixed point notation + +output string = [-]mmm.nnnnnn + +where 'm' & 'n' are digits. + + +=================== +==== METHOD 3 ==== : integer values (m_apm_to_integer_string) +=================== + +the format will simply be digits with a possible leading '-' sign. + +output string = [-]nnnnnn + +where 'n' are digits. + +it's easy to convert this to a long : +long mtmp = atol(out_buffer); + +... or an int : +int itmp = atoi(out_buffer); + +Note that if the M_APM number has a fractional portion, the fraction +will be truncated and only the integer portion will be output. + + +char out_buffer[1024]; + +m_apm_to_string(out_buffer, DECIMAL_PLACES, mapm_number); + +m_apm_to_fixpt_string(out_buffer, DECIMAL_PLACES, mapm_number); + +m_apm_to_integer_string(out_buffer, mapm_number); + + +************************************************************************** + +********************************************************* +**** NOTES on the fixed point formatting functions **** +********************************************************* + +Assume you have the following code: + + +--> m_apm_set_string(aa_mapm, "2.0E18"); +--> m_apm_sqrt(bb_mapm, 40, aa_mapm); + +--> m_apm_to_string(buffer, 40, bb_mapm); +--> fprintf(stdout,"[%s]\n",buffer); + +--> m_apm_to_fixpt_string(buffer, 40, bb_mapm); +--> fprintf(stdout,"[%s]\n",buffer); + + +It is desired to compute the sqrt(2.0E+18) to +40 significant digits. You then want the result +output with 40 decimal places. But the output +from above is : + +[1.4142135623730950488016887242096980785697E+9] +[1414213562.3730950488016887242096980785697000000000] + + +Why are there 9 '0' in the fixed point formatted string?? + +The sqrt calculation computed 40 significant digits relative +to the number in EXPONENTIAL format. When the number is +output in exponential format, the 40 digits are as expected +with an exponent of 'E+9'. + +The same number formatted as fixed point appears to be an +error. Remember, we computed 40 significant digits. However, +the result has an exponent of '+9'. So, 9 of the digits are +needed *before* the decimal point. In our calculation, only +31 digits of precision remain from our original 40. We then +asked the fixed point formatting function to format 40 digits. +Only 31 are left so 9 zeros are used as pad at the end to +fulfill the 40 places asked for. + +Keep this in mind if you truly desire more accurate results +in fixed point formatting and your result contains a large +positive exponent. + +************************************************************************** + +MAPM C++ WRAPPER CLASS: + +Orion Sky Lawlor (olawlor@acm.org) has added a very nice C++ wrapper +class to m_apm.h. This C++ class will have no effect if you just use +a normal C compiler. The library will operate as before with no user +impacts. + +For now, I recommend compiling the library as 'C'. The library will +compile as a C++ library, but then it is likely that you would not +be able to use the library in a straight C application. Since the C++ +wrapper class works very nicely as is, there is no pressing need to compile +the library as C++. + +See the file 'cpp_function.ref' to see a description of how to use +the MAPM class. + +To compile and link the C++ demo program: (assuming the library is +already built) + +UNIX: + +g++ cpp_demo.cpp lib_mapm.a -s -o cpp_demo -lm + +GCC for DOS: (gxx (or g++) is the C++ compiler) + +gxx cpp_demo.cpp lib_mapm.a -s -o cpp_demo.exe -lm + + +Using the C++ wrapper allows you to do things like: + +// Compute the factorial of the integer n + +MAPM factorial(MAPM n) +{ + MAPM i; + MAPM product = 1; + for (i=2; i <= n; i++) + product *= i; + return product; +} + + +The syntax is the same as if you were just writing normal code, but all +the computations will be performed with the high precision math library, +using the new 'datatype' MAPM. + +The default precision of the computations is as follows: + +Addition, subtraction, and multiplication will maintain ALL significant +digits. + +All other operations (divide, sin, etc) will use the following rules: + +1) if the operation uses only one input value [y = sin(x)], the result 'y' + will be the same precision as 'x', with a minimum of 30 digits if 'x' is + less than 30 digits. + +2) if the operation uses two input values [z = atan2(y,x)], the result 'z' + will be the max digits of 'x' or 'y' with a minimum of 30. + +The default precision is 30 digits. You can change the precision at +any time with the function 'm_apm_cpp_precision'. (See function.ref) + +----> m_apm_cpp_precision(80); + +will result in all operations being accurate to a minimum of 80 significant +digits. If any operand contains more than the minimum number of digits, then +the result will contain the max number of digits of the operands. + + +NOTE!: Some real life use with the C++ wrapper has revealed a certain + tendency for a program to become quite slow after many iterations + (like in a for/while loop). After a little debug, the reason + became clear. Remember that multiplication will maintain ALL + significant digits : + + 20 digit number x 20 digit number = 40 digits + 40 digit number x 40 digit number = 80 digits + 80 digit number x 80 digit number = 160 digits + etc. + + So after numerous iterations, the number of significant digits + was growing without bound. The easy way to fix the problem is + to simply *round* your result after a multiply or some other + complex operation. For example: + + #define MAX_DIGITS 256 + + p1 = (p0 * sin(b1) * exp(1 + u1)) / sqrt(1 + b1); + p1 = p1.round(MAX_DIGITS); + + If you 'round' as shown here, your program will likely be + nearly as fast as a straight 'C' version. + + +NOTE #2! + + Reference the following code snippet: + + ... + + MAPM pi1, pi2; + char obuf[256]; + + m_apm_cpp_precision(62); + + pi1 = 2 * asin("1"); + pi2 = 2 * asin(1.0); + + pi1.toString(obuf, 60); printf("PI1 = [%s] \n",obuf); + pi2.toString(obuf, 60); printf("PI2 = [%s] \n",obuf); + + ... + + On my system, the output is : + +PI1 = [3.141592653589793238462643383279502884197169399375105820974945E+0] +PI2 = [3.141592653589790000000000000000000000000000000000000000000000E+0] + + + PI2 only has 15 significant digits! This is due to how the second + asin is called. It is called with a 'double' as the argument, hence + the compiler will use the default double asin function from the + standard library. This is likely not the intent but this would be + easy to miss if this was a complex calculation and we didn't know + the 'right' answer. + + In order to force the use of the overloaded MAPM functions, call the + MAPM functions with a quoted string as the argument (if the argument + is a constant and not a variable). + + This would also work (though it seems less elegant ...) : + + MAPM t = 1; + pi2 = 2 * asin(t); + +----------- + +If you have any questions or problems with the C++ wrapper, please let +me know. I am not very C++ proficient, but I'd still like to know about any +problems. Orion Sky Lawlor (olawlor@acm.org) is the one who implemented +the MAPM class, so he'll have to resolve any real hardcore problems, if you +have any. + +************************************************************************** + +TESTING : + +Testing the library was interesting. How do I know it's right? Since I +test the library against the standard C runtime math library (see below) +I have high confidence that the MAPM library is giving correct results. +The logic here is the basic algorithms are independent of the number of +digits calculated, more digits just takes longer. + +The MAPM library has been tested in the following environments : + +Linux i486 / gcc 2.7.2.3, gcc 2.95.2 +Linux i686 / gcc 2.91.66, gcc 2.95.2, gcc 2.95.3, gcc 3.0.4, gcc 3.2.3 +Linux i686 / Intel Linux C/C++ Compiler Verison 7.0 / 8.1 +FreeBSD 4.1 / gcc 2.95.1 +FreeBSD 4.8 / gcc 2.95.4 +FreeBSD 5.x / gcc 2.95.2, gcc 2.95.3 +Redhat Linux 8.2 / gcc 3.2 +HP-UX 9.x /gcc 2.5.8 +HP-UX 10.x / gcc 2.95.2 +Sun 5.5.1 (output from uname), gcc 3.1.1 +Sun Solaris 2.6 / gcc 2.95.1, gcc 2.95.3, gcc 3.2.3 +MAC OSX / gcc ? +DOS 5.0 using GCC 2.8.1 for DOS +DOS 5.0 using GCC 2.95.2 for DOS +DOS ??? using Borland Turbo C++ 3.0 +WIN NT+SP5 using Borland C++ 5.02 IDE, 5.2 & 5.5 command line. +WIN 2000 using National Instruments LabWindows CVI 6.0 +WIN98 using Borland C++ 5.5 command line. +WIN98 & NT & 2000 & XP using LCC-WIN32 Ver 3.2, 3.3 +WIN98 & NT using Watcom C 11.x +WIN95 & NT using Open Watcom 1.0 +WIN95 & WIN98 using MINGW-32 version mingw-1.0.1-20010726 +WIN95 & WIN2000 using DEV-CPP 5.0 Beta 8, 4.9.8.0 +MINGW-32 with gcc 3.2 (mingw special 20020817-1) +MINGW-32 with gcc 3.2.3 (mingw special 20030504-1) +WINXP & MINGW-32 with gcc 3.4.5 +WINXP & Digital Mars Compiler 8.49 +WIN?? using Metrowerks CodeWarrior Pro 7.0 for Windows +DOS 5.0 using Microsoft C 5.1 and 8.00c (16 bit EXEs) +WIN98 & NT using Microsoft Visual C++ 6.0 +WIN98 & NT using Microsoft Visual C++ 7.x (VS.NET 2003 except for + known compiler bug C2676) + + + +As a general rule, when calculating a quantity to a given number of decimal +places, I calculated 4-6 extra digits and then rounded the result to what was +asked for. I decided to be conservative and give a correct answer rather than +to be faster and possibly have the last 2-3 digits in error. Also, some of +the functions call other functions (calculating arc-cos will call cos, log +will call exp, etc.) so I had to calculate a few extra digits in each iteration +to guarantee the loops terminated correctly. + +1) I debugged the 4 basic math operations. I threw numerous test cases at + each of the operations until I knew they were correct. + + Also note that the math.h type functions all call the 4 basic operations + numerous times. So if all the math.h functions work, it is highly + probable the 4 basic math operations work also. + +2) 'math.h' type functions. + + SQRT: Not real hard to check. Single stepping through the iterative + loop showed it was always converging to the sqrt. + + CBRT: Similar to sqrt, single stepping through the iterative loop + showed it was always converging to the cube root. + + EXP: I wrote a separate algorithm which expanded the Taylor series + manually and compared the results against the library. + + POW: Straightforward since this just calls 'EXP'. + + LOG: I wrote a separate algorithm which expanded the Taylor series + manually and compared the results against the library. This + took a long time to execute since the normal series converges + VERY slowly for the log function. This is why the LOG function + uses an iterative algorithm. + + LOG10: Straightforward since this just calls 'LOG'. + + SIN/COS: I wrote a separate algorithm which expanded the Taylor series + manually and compared the results against the library. + + TAN: Straightforward since this just calls 'SIN' and 'COS'. + + ARC-x: Single stepping through the iterative loop showed the arc + family of functions were always converging. Also used these + to compute PI. The value of PI is now known to many, many + digits. I computed PI to 1000+ digits by computing: + + 6 * arcsin(0.5) and 4 * arctan(1) and 3 * arccos(0.5) + + and compared the output to the published 'real' values of PI. + + The arc family of functions exercise considerable portions + of the library. + + HYPERBOLIC: The hyperbolic functions just use exp, log, and the 4 basic + math operations. All of these functions simply use other + existing functions in the library. + + FINALLY: Run the program 'validate'. This program compares the first + 13-14 significant digits of the standard C library against + the MAPM library. If this program passes, you can feel + confident that the MAPM library is giving correct results. + +************************************************************************** diff --git a/src/apps/deskcalc/mapm_4.9.5/m_apm.h b/src/apps/deskcalc/mapm_4.9.5/m_apm.h new file mode 100644 index 0000000000..91b860fb29 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/m_apm.h @@ -0,0 +1,662 @@ + +/* + * M_APM - m_apm.h + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * This is the header file that the user will include. + * + * $Log: m_apm.h,v $ + * Revision 1.42 2007/12/03 02:28:25 mike + * update copyright + * + * Revision 1.41 2007/12/03 01:21:35 mike + * Update license + * Update version to 4.9.5 + * + * Revision 1.40 2004/05/31 22:06:02 mike + * add % operator to C++ wrapper + * + * Revision 1.39 2004/05/24 04:11:41 mike + * updated version to 4.9.2 + * + * Revision 1.38 2004/04/01 03:17:19 mike + * update version to 4.9.1 + * + * Revision 1.37 2004/01/02 20:40:49 mike + * fix date on copyright + * + * Revision 1.36 2004/01/02 00:52:38 mike + * update version to 4.9 + * + * Revision 1.35 2003/11/23 05:12:46 mike + * update version + * + * Revision 1.34 2003/07/21 20:59:54 mike + * update version to 4.8 + * + * Revision 1.33 2003/05/14 21:19:23 mike + * change version string + * + * Revision 1.32 2003/05/06 21:29:11 mike + * add defines for lib versions (and prototypes) + * + * Revision 1.31 2002/11/04 20:46:33 mike + * change definition of the M_APM structure + * + * Revision 1.30 2002/11/03 23:36:24 mike + * added new function, m_apm_integer_pow_nr + * + * Revision 1.29 2002/02/14 21:43:00 mike + * add set_random_seed prototype + * + * Revision 1.28 2001/08/28 18:29:32 mike + * fix fixptstringexp + * + * Revision 1.27 2001/08/27 22:45:03 mike + * fix typo + * + * Revision 1.26 2001/08/27 22:43:06 mike + * add new fix pt functions to C++ wrapper + * + * Revision 1.25 2001/08/26 22:09:13 mike + * add new prototype + * + * Revision 1.24 2001/08/25 16:48:21 mike + * add new prototypes + * + * Revision 1.23 2001/07/16 18:40:27 mike + * add free_all_mem, trim_mem_usage prototypes + * + * Revision 1.22 2001/07/15 20:49:21 mike + * added is_odd, is_even, gcd, lcm functions + * + * Revision 1.21 2001/03/25 21:24:55 mike + * add floor and ceil functions + * + * Revision 1.20 2000/09/23 19:05:29 mike + * add _reciprocal prototype + * + * Revision 1.19 2000/08/21 23:30:13 mike + * add _is_integer function + * + * Revision 1.18 2000/07/06 00:10:15 mike + * redo declare for MM_cpp_min_precision + * + * Revision 1.17 2000/07/04 20:59:43 mike + * move MM_cpp_min_precision into cplusplus block below + * + * Revision 1.16 2000/07/04 20:49:04 mike + * move 'MM_cpp_min_precision' inside the extern "C" + * brackets + * + * Revision 1.15 2000/04/06 21:19:38 mike + * minor final tweaks from Orion + * + * Revision 1.14 2000/04/05 20:15:25 mike + * add cpp_min_precision + * + * Revision 1.13 2000/04/04 22:20:09 mike + * updated some comments from Orion + * + * Revision 1.12 2000/04/04 19:46:36 mike + * fix preincrement, postincrement operators + * added some comments + * added 'ipow' operators + * + * Revision 1.11 2000/04/03 22:08:35 mike + * added MAPM C++ wrapper class + * supplied by Orion Sky Lawlor (olawlor@acm.org) + * + * Revision 1.10 2000/04/03 18:40:28 mike + * add #define atan2 for alias + * + * Revision 1.9 2000/04/03 18:05:23 mike + * added hyperbolic functions + * + * Revision 1.8 2000/04/03 17:26:57 mike + * add cbrt prototype + * + * Revision 1.7 1999/09/18 03:11:23 mike + * add new prototype + * + * Revision 1.6 1999/09/18 03:08:25 mike + * add new prototypes + * + * Revision 1.5 1999/09/18 01:37:55 mike + * added new prototype + * + * Revision 1.4 1999/07/12 02:04:30 mike + * added new function prototpye (m_apm_integer_string) + * + * Revision 1.3 1999/05/15 21:04:08 mike + * added factorial prototype + * + * Revision 1.2 1999/05/12 20:50:12 mike + * added more constants + * + * Revision 1.1 1999/05/12 20:48:25 mike + * Initial revision + * + * $Id: m_apm.h,v 1.42 2007/12/03 02:28:25 mike Exp $ + */ + +#ifndef M__APM__INCLUDED +#define M__APM__INCLUDED + +#ifdef __cplusplus +/* Comment this line out if you've compiled the library as C++. */ +#define APM_CONVERT_FROM_C +#endif + +#ifdef APM_CONVERT_FROM_C +extern "C" { +#endif + +typedef unsigned char UCHAR; + +typedef struct { + UCHAR *m_apm_data; + long m_apm_id; + int m_apm_refcount; /* <- used only by C++ MAPM class */ + int m_apm_malloclength; + int m_apm_datalength; + int m_apm_exponent; + int m_apm_sign; +} M_APM_struct; + +typedef M_APM_struct *M_APM; + + +#define MAPM_LIB_VERSION \ + "MAPM Library Version 4.9.5 Copyright (C) 1999-2007, Michael C. Ring" +#define MAPM_LIB_SHORT_VERSION "4.9.5" + + +/* + * convienient predefined constants + */ + +extern M_APM MM_Zero; +extern M_APM MM_One; +extern M_APM MM_Two; +extern M_APM MM_Three; +extern M_APM MM_Four; +extern M_APM MM_Five; +extern M_APM MM_Ten; + +extern M_APM MM_PI; +extern M_APM MM_HALF_PI; +extern M_APM MM_2_PI; +extern M_APM MM_E; + +extern M_APM MM_LOG_E_BASE_10; +extern M_APM MM_LOG_10_BASE_E; +extern M_APM MM_LOG_2_BASE_E; +extern M_APM MM_LOG_3_BASE_E; + + +/* + * function prototypes + */ + +extern M_APM m_apm_init(void); +extern void m_apm_free(M_APM); +extern void m_apm_free_all_mem(void); +extern void m_apm_trim_mem_usage(void); +extern char *m_apm_lib_version(char *); +extern char *m_apm_lib_short_version(char *); + +extern void m_apm_set_string(M_APM, char *); +extern void m_apm_set_double(M_APM, double); +extern void m_apm_set_long(M_APM, long); + +extern void m_apm_to_string(char *, int, M_APM); +extern void m_apm_to_fixpt_string(char *, int, M_APM); +extern void m_apm_to_fixpt_stringex(char *, int, M_APM, char, char, int); +extern char *m_apm_to_fixpt_stringexp(int, M_APM, char, char, int); +extern void m_apm_to_integer_string(char *, M_APM); + +extern void m_apm_absolute_value(M_APM, M_APM); +extern void m_apm_negate(M_APM, M_APM); +extern void m_apm_copy(M_APM, M_APM); +extern void m_apm_round(M_APM, int, M_APM); +extern int m_apm_compare(M_APM, M_APM); +extern int m_apm_sign(M_APM); +extern int m_apm_exponent(M_APM); +extern int m_apm_significant_digits(M_APM); +extern int m_apm_is_integer(M_APM); +extern int m_apm_is_even(M_APM); +extern int m_apm_is_odd(M_APM); + +extern void m_apm_gcd(M_APM, M_APM, M_APM); +extern void m_apm_lcm(M_APM, M_APM, M_APM); + +extern void m_apm_add(M_APM, M_APM, M_APM); +extern void m_apm_subtract(M_APM, M_APM, M_APM); +extern void m_apm_multiply(M_APM, M_APM, M_APM); +extern void m_apm_divide(M_APM, int, M_APM, M_APM); +extern void m_apm_integer_divide(M_APM, M_APM, M_APM); +extern void m_apm_integer_div_rem(M_APM, M_APM, M_APM, M_APM); +extern void m_apm_reciprocal(M_APM, int, M_APM); +extern void m_apm_factorial(M_APM, M_APM); +extern void m_apm_floor(M_APM, M_APM); +extern void m_apm_ceil(M_APM, M_APM); +extern void m_apm_get_random(M_APM); +extern void m_apm_set_random_seed(char *); + +extern void m_apm_sqrt(M_APM, int, M_APM); +extern void m_apm_cbrt(M_APM, int, M_APM); +extern void m_apm_log(M_APM, int, M_APM); +extern void m_apm_log10(M_APM, int, M_APM); +extern void m_apm_exp(M_APM, int, M_APM); +extern void m_apm_pow(M_APM, int, M_APM, M_APM); +extern void m_apm_integer_pow(M_APM, int, M_APM, int); +extern void m_apm_integer_pow_nr(M_APM, M_APM, int); + +extern void m_apm_sin_cos(M_APM, M_APM, int, M_APM); +extern void m_apm_sin(M_APM, int, M_APM); +extern void m_apm_cos(M_APM, int, M_APM); +extern void m_apm_tan(M_APM, int, M_APM); +extern void m_apm_arcsin(M_APM, int, M_APM); +extern void m_apm_arccos(M_APM, int, M_APM); +extern void m_apm_arctan(M_APM, int, M_APM); +extern void m_apm_arctan2(M_APM, int, M_APM, M_APM); + +extern void m_apm_sinh(M_APM, int, M_APM); +extern void m_apm_cosh(M_APM, int, M_APM); +extern void m_apm_tanh(M_APM, int, M_APM); +extern void m_apm_arcsinh(M_APM, int, M_APM); +extern void m_apm_arccosh(M_APM, int, M_APM); +extern void m_apm_arctanh(M_APM, int, M_APM); + +extern void m_apm_cpp_precision(int); /* only for C++ wrapper */ + +/* more intuitive alternate names for the ARC functions ... */ + +#define m_apm_asin m_apm_arcsin +#define m_apm_acos m_apm_arccos +#define m_apm_atan m_apm_arctan +#define m_apm_atan2 m_apm_arctan2 + +#define m_apm_asinh m_apm_arcsinh +#define m_apm_acosh m_apm_arccosh +#define m_apm_atanh m_apm_arctanh + +#ifdef APM_CONVERT_FROM_C +} /* End extern "C" bracket */ +#endif + +#ifdef __cplusplus /*<- Hides the class below from C compilers */ + +/* + This class lets you use M_APM's a bit more intuitively with + C++'s operator and function overloading, constructors, etc. + + Added 3/24/2000 by Orion Sky Lawlor, olawlor@acm.org +*/ + +extern +#ifdef APM_CONVERT_FROM_C +"C" +#endif +int MM_cpp_min_precision; + + +class MAPM { +protected: + +/* +The M_APM structure here is implemented as a reference- +counted, copy-on-write data structure-- this makes copies +very fast, but that's why it's so ugly. A MAPM object is +basically just a wrapper around a (possibly shared) +M_APM_struct myVal. +*/ + + + M_APM myVal; /* My M_APM structure */ + void create(void) {myVal=makeNew();} + void destroy(void) {unref(myVal);myVal=NULL;} + void copyFrom(M_APM Nval) + { + M_APM oldVal=myVal; + myVal=Nval; + ref(myVal); + unref(oldVal); + } + static M_APM makeNew(void) + { + M_APM val=m_apm_init(); + /* refcount initialized to 1 by 'm_apm_init' */ + return val; + } + static void ref(M_APM val) + { + val->m_apm_refcount++; + } + static void unref(M_APM val) + { + val->m_apm_refcount--; + if (val->m_apm_refcount==0) + m_apm_free(val); + } + + /* This routine is called to get a private (mutable) + copy of our current value. */ + M_APM val(void) + { + if (myVal->m_apm_refcount==1) + /* Return my private myVal */ + return myVal; + + /* Otherwise, our copy of myVal is shared-- + we need to make a new private copy. + */ + M_APM oldVal=myVal; + myVal=makeNew(); + m_apm_copy(myVal,oldVal); + unref(oldVal); + return myVal; + } + + /*BAD: C M_APM routines doesn't use "const" where they should-- + hence we have to cast to a non-const type here (FIX THIS!). + + (in due time.... MCR) + */ + M_APM cval(void) const + { + return (M_APM)myVal; + } + /* This is the default number of digits to use for + 1-ary functions like sin, cos, tan, etc. + It's the larger of my digits and cpp_min_precision. + */ + int myDigits(void) const + { + int maxd=m_apm_significant_digits(cval()); + if (maxd(const MAPM &m) const + {return m_apm_compare(cval(),m.cval())>0;} + int operator>=(const MAPM &m) const + {return m_apm_compare(cval(),m.cval())>=0;} + + /* Basic arithmetic operators */ + friend MAPM operator+(const MAPM &a,const MAPM &b) + {MAPM ret;m_apm_add(ret.val(),a.cval(),b.cval());return ret;} + friend MAPM operator-(const MAPM &a,const MAPM &b) + {MAPM ret;m_apm_subtract(ret.val(),a.cval(),b.cval());return ret;} + friend MAPM operator*(const MAPM &a,const MAPM &b) + {MAPM ret;m_apm_multiply(ret.val(),a.cval(),b.cval());return ret;} + friend MAPM operator%(const MAPM &a,const MAPM &b) + {MAPM quot,ret;m_apm_integer_div_rem(quot.val(),ret.val(), + a.cval(),b.cval());return ret;} + + /* Default division keeps larger of cpp_min_precision, numerator + digits of precision, or denominator digits of precision. */ + friend MAPM operator/(const MAPM &a,const MAPM &b) + {return a.divide(b,a.digits(b));} + + MAPM divide(const MAPM &m,int toDigits) const + {MAPM ret;m_apm_divide(ret.val(),toDigits,cval(), + m.cval());return ret;} + MAPM divide(const MAPM &m) const {return divide(m,digits(m));} + + /* Assignment arithmetic operators */ + MAPM &operator+=(const MAPM &m) {*this = *this+m;return *this;} + MAPM &operator-=(const MAPM &m) {*this = *this-m;return *this;} + MAPM &operator*=(const MAPM &m) {*this = *this*m;return *this;} + MAPM &operator/=(const MAPM &m) {*this = *this/m;return *this;} + MAPM &operator%=(const MAPM &m) {*this = *this%m;return *this;} + + /* Extracting/setting simple information: */ + int sign(void) const + {return m_apm_sign(cval());} + int exponent(void) const + {return m_apm_exponent(cval());} + int significant_digits(void) const + {return m_apm_significant_digits(cval());} + int is_integer(void) const + {return m_apm_is_integer(cval());} + int is_even(void) const + {return m_apm_is_even(cval());} + int is_odd(void) const + {return m_apm_is_odd(cval());} + + /* Functions: */ + MAPM abs(void) const + {MAPM ret;m_apm_absolute_value(ret.val(),cval());return ret;} + MAPM neg(void) const + {MAPM ret;m_apm_negate(ret.val(),cval());return ret;} + MAPM round(int toDigits) const + {MAPM ret;m_apm_round(ret.val(),toDigits,cval());return ret;} + MAPM operator-(void) const {return neg();} + +/* I got tired of typing the various declarations for a simple + 1-ary real-to-real function on MAPM's; hence this define: + The digits-free versions return my digits of precision or + cpp_min_precision, whichever is bigger. +*/ + +#define MAPM_1aryFunc(func) \ + MAPM func(int toDigits) const\ + {MAPM ret;m_apm_##func(ret.val(),toDigits,cval());return ret;}\ + MAPM func(void) const {return func(myDigits());} + + MAPM_1aryFunc(sqrt) + MAPM_1aryFunc(cbrt) + MAPM_1aryFunc(log) + MAPM_1aryFunc(exp) + MAPM_1aryFunc(log10) + MAPM_1aryFunc(sin) + MAPM_1aryFunc(asin) + MAPM_1aryFunc(cos) + MAPM_1aryFunc(acos) + MAPM_1aryFunc(tan) + MAPM_1aryFunc(atan) + MAPM_1aryFunc(sinh) + MAPM_1aryFunc(asinh) + MAPM_1aryFunc(cosh) + MAPM_1aryFunc(acosh) + MAPM_1aryFunc(tanh) + MAPM_1aryFunc(atanh) +#undef MAPM_1aryFunc + + void sincos(MAPM &sinR,MAPM &cosR,int toDigits) + {m_apm_sin_cos(sinR.val(),cosR.val(),toDigits,cval());} + void sincos(MAPM &sinR,MAPM &cosR) + {sincos(sinR,cosR,myDigits());} + MAPM pow(const MAPM &m,int toDigits) const + {MAPM ret;m_apm_pow(ret.val(),toDigits,cval(), + m.cval());return ret;} + MAPM pow(const MAPM &m) const {return pow(m,digits(m));} + MAPM atan2(const MAPM &x,int toDigits) const + {MAPM ret;m_apm_arctan2(ret.val(),toDigits,cval(), + x.cval());return ret;} + MAPM atan2(const MAPM &x) const + {return atan2(x,digits(x));} + + MAPM gcd(const MAPM &m) const + {MAPM ret;m_apm_gcd(ret.val(),cval(),m.cval());return ret;} + + MAPM lcm(const MAPM &m) const + {MAPM ret;m_apm_lcm(ret.val(),cval(),m.cval());return ret;} + + static MAPM random(void) + {MAPM ret;m_apm_get_random(ret.val());return ret;} + + MAPM floor(void) const + {MAPM ret;m_apm_floor(ret.val(),cval());return ret;} + MAPM ceil(void) const + {MAPM ret;m_apm_ceil(ret.val(),cval());return ret;} + + /* Functions defined only on integers: */ + MAPM factorial(void) const + {MAPM ret;m_apm_factorial(ret.val(),cval());return ret;} + MAPM ipow_nr(int p) const + {MAPM ret;m_apm_integer_pow_nr(ret.val(), + cval(),p);return ret;} + MAPM ipow(int p,int toDigits) const + {MAPM ret;m_apm_integer_pow(ret.val(), + toDigits,cval(),p);return ret;} + MAPM ipow(int p) const + {return ipow(p,myDigits());} + MAPM integer_divide(const MAPM &denom) const + {MAPM ret;m_apm_integer_divide(ret.val(),cval(), + denom.cval());return ret;} + void integer_div_rem(const MAPM &denom,MAPM ",MAPM &rem) const + {m_apm_integer_div_rem(quot.val(),rem.val(),cval(), + denom.cval());} + MAPM div(const MAPM &denom) const {return integer_divide(denom);} + MAPM rem(const MAPM &denom) const {MAPM ret,ignored; + integer_div_rem(denom,ignored,ret);return ret;} +}; + +/* math.h-style functions: */ + +inline MAPM fabs(const MAPM &m) {return m.abs();} +inline MAPM factorial(const MAPM &m) {return m.factorial();} +inline MAPM floor(const MAPM &m) {return m.floor();} +inline MAPM ceil(const MAPM &m) {return m.ceil();} +inline MAPM get_random(void) {return MAPM::random();} + +/* I got tired of typing the various declarations for a simple + 1-ary real-to-real function on MAPM's; hence this define: +*/ +#define MAPM_1aryFunc(func) \ + inline MAPM func(const MAPM &m) {return m.func();} \ + inline MAPM func(const MAPM &m,int toDigits) {return m.func(toDigits);} + +/* Define a big block of simple functions: */ + MAPM_1aryFunc(sqrt) + MAPM_1aryFunc(cbrt) + MAPM_1aryFunc(log) + MAPM_1aryFunc(exp) + MAPM_1aryFunc(log10) + MAPM_1aryFunc(sin) + MAPM_1aryFunc(asin) + MAPM_1aryFunc(cos) + MAPM_1aryFunc(acos) + MAPM_1aryFunc(tan) + MAPM_1aryFunc(atan) + MAPM_1aryFunc(sinh) + MAPM_1aryFunc(asinh) + MAPM_1aryFunc(cosh) + MAPM_1aryFunc(acosh) + MAPM_1aryFunc(tanh) + MAPM_1aryFunc(atanh) +#undef MAPM_1aryFunc + +/* Computes x to the power y */ +inline MAPM pow(const MAPM &x,const MAPM &y,int toDigits) + {return x.pow(y,toDigits);} +inline MAPM pow(const MAPM &x,const MAPM &y) + {return x.pow(y);} +inline MAPM atan2(const MAPM &y,const MAPM &x,int toDigits) + {return y.atan2(x,toDigits);} +inline MAPM atan2(const MAPM &y,const MAPM &x) + {return y.atan2(x);} +inline MAPM gcd(const MAPM &u,const MAPM &v) + {return u.gcd(v);} +inline MAPM lcm(const MAPM &u,const MAPM &v) + {return u.lcm(v);} +#endif +#endif + diff --git a/src/apps/deskcalc/mapm_4.9.5/m_apm_lc.h b/src/apps/deskcalc/mapm_4.9.5/m_apm_lc.h new file mode 100644 index 0000000000..5f59e28256 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/m_apm_lc.h @@ -0,0 +1,400 @@ + +/* + * M_APM - m_apm_lc.h + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * This is the local header file needed to build the library + * + * $Log: m_apm_lc.h,v $ + * Revision 1.45 2007/12/04 01:26:02 mike + * add support for Digital Mars compiler + * + * Revision 1.44 2007/12/03 01:23:54 mike + * Update license + * + * Revision 1.43 2004/05/28 19:30:16 mike + * add new prototype + * + * Revision 1.42 2003/10/25 22:36:01 mike + * add support for National Instruments CVI + * + * Revision 1.41 2003/07/21 19:42:50 mike + * rename M_APM_EXIT to M_APM_FATAL + * change M_APM_RETURN to 0, set M_APM_FATAL to 1 + * + * Revision 1.40 2003/07/21 19:14:29 mike + * add new prototype + * + * Revision 1.39 2003/05/04 20:09:10 mike + * add support for Open Watcom 1.0 + * + * Revision 1.38 2003/05/01 21:54:04 mike + * add math.h, add new prototype + * + * Revision 1.37 2003/04/01 23:19:01 mike + * add new log constants and prototypes + * + * Revision 1.36 2003/03/30 23:02:49 mike + * add new log constants and new prototypes + * + * Revision 1.35 2002/11/03 23:21:28 mike + * add new prototype, M_set_to_zero + * + * Revision 1.34 2002/05/18 15:38:52 mike + * add MINGW compiler #define + * + * Revision 1.33 2002/02/14 19:42:59 mike + * add conditional compiler stuff for Metrowerks Codewarrior compiler + * + * Revision 1.32 2001/08/25 16:45:40 mike + * add new prototype + * + * Revision 1.31 2001/07/24 18:13:31 mike + * add new prototype + * + * Revision 1.30 2001/07/16 18:38:04 mike + * add 'free_all' prototypes + * + * Revision 1.29 2001/02/07 19:13:27 mike + * eliminate MM_skip_limit_PI_check + * + * Revision 1.28 2001/01/23 21:10:24 mike + * add new prototype for M_long_2_ascii + * + * Revision 1.27 2000/12/10 14:30:52 mike + * added ifdef for LCC-WIN32 compiler + * + * Revision 1.26 2000/12/02 19:41:45 mike + * add arc functions near 0 + * + * Revision 1.25 2000/11/14 22:48:29 mike + * add BORLANDC to pre-processor stuff + * + * Revision 1.24 2000/10/22 21:17:56 mike + * add _MSC_VER check for VC++ compilers + * + * Revision 1.23 2000/10/18 23:09:27 mike + * add new prototype + * + * Revision 1.22 2000/09/23 18:55:30 mike + * add new prototype fpr M_apm_sdivide + * + * Revision 1.21 2000/08/01 22:21:55 mike + * add prototype + * + * Revision 1.20 2000/07/19 17:21:26 mike + * add ifdef for older Borland compilers + * + * Revision 1.19 2000/07/11 20:09:30 mike + * add new prototype + * + * Revision 1.18 2000/05/19 17:09:57 mike + * add local copies for PI variables + * + * Revision 1.17 2000/05/04 23:21:56 mike + * change/add new global internal MAPM values + * + * Revision 1.16 2000/04/11 18:44:43 mike + * no longer need the constant 'Fifteen' + * + * Revision 1.15 2000/04/03 17:27:08 mike + * added cbrt prototype + * + * Revision 1.14 2000/02/03 22:41:34 mike + * add MAPM_* memory function defines + * + * Revision 1.13 1999/07/09 22:46:10 mike + * add skip limit integer + * + * Revision 1.12 1999/07/08 23:35:20 mike + * change constant + * + * Revision 1.11 1999/07/08 22:55:38 mike + * add new constant + * + * Revision 1.10 1999/06/23 01:08:11 mike + * added constant '15' + * + * Revision 1.9 1999/06/20 23:38:11 mike + * updated for new prototypes + * + * Revision 1.8 1999/06/20 23:30:03 mike + * added new constants + * + * Revision 1.7 1999/06/20 19:23:12 mike + * delete constants no longer needed + * + * Revision 1.6 1999/06/20 18:50:21 mike + * added more constants + * + * Revision 1.5 1999/06/19 20:37:30 mike + * add stack prototypes + * + * Revision 1.4 1999/05/31 23:01:38 mike + * delete some unneeded constants + * + * Revision 1.3 1999/05/15 02:23:28 mike + * fix define for M_COS + * + * Revision 1.2 1999/05/15 02:16:56 mike + * add check for number of decimal places + * + * Revision 1.1 1999/05/12 20:51:22 mike + * Initial revision + * + * $Id: m_apm_lc.h,v 1.45 2007/12/04 01:26:02 mike Exp $ + */ + +#ifndef M__APM_LOCAL_INC +#define M__APM_LOCAL_INC + +#include +#include +#include +#include +#include "m_apm.h" + +/* + * this supports older (and maybe newer?) Borland compilers. + * these Borland compilers define __MSDOS__ + */ + +#ifndef MSDOS +#ifdef __MSDOS__ +#define MSDOS +#endif +#endif + +/* + * this supports some newer Borland compilers (i.e., v5.5). + */ + +#ifndef MSDOS +#ifdef __BORLANDC__ +#define MSDOS +#endif +#endif + +/* + * this supports the LCC-WIN32 compiler + */ + +#ifndef MSDOS +#ifdef __LCC__ +#define MSDOS +#endif +#endif + +/* + * this supports Micro$oft Visual C++ and also possibly older + * straight C compilers as well. + */ + +#ifndef MSDOS +#ifdef _MSC_VER +#define MSDOS +#endif +#endif + +/* + * this supports the Metrowerks CodeWarrior 7.0 compiler (I think...) + */ + +#ifndef MSDOS +#ifdef __MWERKS__ +#define MSDOS +#endif +#endif + +/* + * this supports the MINGW 32 compiler + */ + +#ifndef MSDOS +#ifdef __MINGW_H +#define MSDOS +#endif +#endif + +/* + * this supports the Open Watcom 1.0 compiler + */ + +#ifndef MSDOS +#ifdef __WATCOMC__ +#define MSDOS +#endif +#endif + +/* + * this supports the Digital Mars compiler + */ + +#ifndef MSDOS +#ifdef __DMC__ +#define MSDOS +#endif +#endif + +/* + * this supports National Instruments LabWindows CVI + */ + +#ifndef _HAVE_NI_LABWIN_CVI_ +#ifdef _CVI_ +#define _HAVE_NI_LABWIN_CVI_ +#endif +#endif + +/* + * If for some reason (RAM limitations, slow floating point, whatever) + * you do NOT want to use the FFT multiply algorithm, un-comment the + * #define below, delete mapm_fft.c and remove mapm_fft from the build. + */ + +/* #define NO_FFT_MULTIPLY */ + +/* + * use your own memory management functions if desired. + * re-define MAPM_* below to point to your functions. + * an example is shown below. + */ + +/* +extern void *memory_allocate(unsigned int); +extern void *memory_reallocate(void *, unsigned int); +extern void memory_free(void *); + +#define MAPM_MALLOC memory_allocate +#define MAPM_REALLOC memory_reallocate +#define MAPM_FREE memory_free +*/ + +/* default: use the standard C library memory functions ... */ + +#define MAPM_MALLOC malloc +#define MAPM_REALLOC realloc +#define MAPM_FREE free + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define M_APM_IDENT 0x6BCC9AE5 +#define M_APM_RETURN 0 +#define M_APM_FATAL 1 + +/* number of digits in the global constants, PI, E, etc */ + +#define VALID_DECIMAL_PLACES 128 + +extern int MM_lc_PI_digits; +extern int MM_lc_log_digits; + +/* + * constants not in m_apm.h + */ + +extern M_APM MM_0_5; +extern M_APM MM_0_85; +extern M_APM MM_5x_125R; +extern M_APM MM_5x_64R; +extern M_APM MM_5x_256R; +extern M_APM MM_5x_Eight; +extern M_APM MM_5x_Sixteen; +extern M_APM MM_5x_Twenty; +extern M_APM MM_lc_PI; +extern M_APM MM_lc_HALF_PI; +extern M_APM MM_lc_2_PI; +extern M_APM MM_lc_log2; +extern M_APM MM_lc_log10; +extern M_APM MM_lc_log10R; + +/* + * prototypes for internal functions + */ + +#ifndef NO_FFT_MULTIPLY +extern void M_free_all_fft(void); +#endif + +extern void M_init_trig_globals(void); +extern void M_free_all_add(void); +extern void M_free_all_div(void); +extern void M_free_all_exp(void); +extern void M_free_all_pow(void); +extern void M_free_all_rnd(void); +extern void M_free_all_set(void); +extern void M_free_all_cnst(void); +extern void M_free_all_fmul(void); +extern void M_free_all_stck(void); +extern void M_free_all_util(void); + +extern int M_exp_compute_nn(int *, M_APM, M_APM); +extern void M_raw_exp(M_APM, int, M_APM); +extern void M_raw_sin(M_APM, int, M_APM); +extern void M_raw_cos(M_APM, int, M_APM); +extern void M_5x_sin(M_APM, int, M_APM); +extern void M_4x_cos(M_APM, int, M_APM); +extern void M_5x_do_it(M_APM, int, M_APM); +extern void M_4x_do_it(M_APM, int, M_APM); + +extern M_APM M_get_stack_var(void); +extern void M_restore_stack(int); +extern int M_get_sizeof_int(void); + +extern void M_apm_sdivide(M_APM, int, M_APM, M_APM); +extern void M_cos_to_sin(M_APM, int, M_APM); +extern void M_limit_angle_to_pi(M_APM, int, M_APM); +extern void M_log_near_1(M_APM, int, M_APM); +extern void M_get_sqrt_guess(M_APM, M_APM); +extern void M_get_cbrt_guess(M_APM, M_APM); +extern void M_get_log_guess(M_APM, M_APM); +extern void M_get_asin_guess(M_APM, M_APM); +extern void M_get_acos_guess(M_APM, M_APM); +extern void M_arcsin_near_0(M_APM, int, M_APM); +extern void M_arccos_near_0(M_APM, int, M_APM); +extern void M_arctan_near_0(M_APM, int, M_APM); +extern void M_arctan_large_input(M_APM, int, M_APM); +extern void M_log_basic_iteration(M_APM, int, M_APM); +extern void M_log_solve_cubic(M_APM, int, M_APM); +extern void M_check_log_places(int); +extern void M_log_AGM_R_func(M_APM, int, M_APM, M_APM); +extern void M_init_util_data(void); +extern void M_get_div_rem_addr(UCHAR **, UCHAR **); +extern void M_get_div_rem(int,UCHAR *, UCHAR *); +extern void M_get_div_rem_10(int, UCHAR *, UCHAR *); +extern void M_apm_normalize(M_APM); +extern void M_apm_scale(M_APM, int); +extern void M_apm_pad(M_APM, int); +extern void M_long_2_ascii(char *, long); +extern void M_check_PI_places(int); +extern void M_calculate_PI_AGM(M_APM, int); +extern void M_set_to_zero(M_APM); +extern int M_strposition(char *, char *); +extern char *M_lowercase(char *); +extern void M_apm_log_error_msg(int, char *); +extern void M_apm_round_fixpt(M_APM, int, M_APM); + +#endif + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm5sin.c b/src/apps/deskcalc/mapm_4.9.5/mapm5sin.c new file mode 100644 index 0000000000..0c2aac6873 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm5sin.c @@ -0,0 +1,184 @@ + +/* + * M_APM - mapm5sin.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm5sin.c,v 1.10 2007/12/03 01:26:16 mike Exp $ + * + * This file contains the functions that implement the sin (5x) + * and cos (4x) multiple angle relations + * + * $Log: mapm5sin.c,v $ + * Revision 1.10 2007/12/03 01:26:16 mike + * Update license + * + * Revision 1.9 2002/11/03 21:50:36 mike + * Updated function parameters to use the modern style + * + * Revision 1.8 2001/03/25 20:57:03 mike + * move cos_to_sin func in here + * + * Revision 1.7 2000/05/04 23:50:21 mike + * use multiple angle identity 4 times of larger COS angles + * + * Revision 1.6 1999/06/30 00:08:53 mike + * pass more decimal places to raw functions + * + * Revision 1.5 1999/06/20 23:41:32 mike + * changed COS to use 4x multiple angle identity instead of 5x + * + * Revision 1.4 1999/06/20 19:42:26 mike + * tweak number of dec places passed to sub-functions + * + * Revision 1.3 1999/06/20 19:03:56 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.2 1999/05/12 21:30:09 mike + * replace local 5.0 with global + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void M_5x_sin(M_APM r, int places, M_APM x) +{ +M_APM tmp8, tmp9; + +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +m_apm_multiply(tmp9, x, MM_5x_125R); /* 1 / (5*5*5) */ +M_raw_sin(tmp8, (places + 6), tmp9); +M_5x_do_it(tmp9, (places + 4), tmp8); +M_5x_do_it(tmp8, (places + 4), tmp9); +M_5x_do_it(r, places, tmp8); + +M_restore_stack(2); +} +/****************************************************************************/ +void M_4x_cos(M_APM r, int places, M_APM x) +{ +M_APM tmp8, tmp9; + +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +/* + * if |x| >= 1.0 use multiple angle identity 4 times + * if |x| < 1.0 use multiple angle identity 3 times + */ + +if (x->m_apm_exponent > 0) + { + m_apm_multiply(tmp9, x, MM_5x_256R); /* 1 / (4*4*4*4) */ + M_raw_cos(tmp8, (places + 8), tmp9); + M_4x_do_it(tmp9, (places + 8), tmp8); + M_4x_do_it(tmp8, (places + 6), tmp9); + M_4x_do_it(tmp9, (places + 4), tmp8); + M_4x_do_it(r, places, tmp9); + } +else + { + m_apm_multiply(tmp9, x, MM_5x_64R); /* 1 / (4*4*4) */ + M_raw_cos(tmp8, (places + 6), tmp9); + M_4x_do_it(tmp9, (places + 4), tmp8); + M_4x_do_it(tmp8, (places + 4), tmp9); + M_4x_do_it(r, places, tmp8); + } + +M_restore_stack(2); +} +/****************************************************************************/ +/* + * calculate the multiple angle identity for sin (5x) + * + * sin (5x) == 16 * sin^5 (x) - 20 * sin^3 (x) + 5 * sin(x) + */ +void M_5x_do_it(M_APM rr, int places, M_APM xx) +{ +M_APM tmp0, tmp1, t2, t3, t5; + +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +t2 = M_get_stack_var(); +t3 = M_get_stack_var(); +t5 = M_get_stack_var(); + +m_apm_multiply(tmp1, xx, xx); +m_apm_round(t2, (places + 4), tmp1); /* x ^ 2 */ + +m_apm_multiply(tmp1, t2, xx); +m_apm_round(t3, (places + 4), tmp1); /* x ^ 3 */ + +m_apm_multiply(t5, t2, t3); /* x ^ 5 */ + +m_apm_multiply(tmp0, xx, MM_Five); +m_apm_multiply(tmp1, t5, MM_5x_Sixteen); +m_apm_add(t2, tmp0, tmp1); +m_apm_multiply(tmp1, t3, MM_5x_Twenty); +m_apm_subtract(tmp0, t2, tmp1); + +m_apm_round(rr, places, tmp0); +M_restore_stack(5); +} +/****************************************************************************/ +/* + * calculate the multiple angle identity for cos (4x) + * + * cos (4x) == 8 * [ cos^4 (x) - cos^2 (x) ] + 1 + */ +void M_4x_do_it(M_APM rr, int places, M_APM xx) +{ +M_APM tmp0, tmp1, t2, t4; + +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +t2 = M_get_stack_var(); +t4 = M_get_stack_var(); + +m_apm_multiply(tmp1, xx, xx); +m_apm_round(t2, (places + 4), tmp1); /* x ^ 2 */ +m_apm_multiply(t4, t2, t2); /* x ^ 4 */ + +m_apm_subtract(tmp0, t4, t2); +m_apm_multiply(tmp1, tmp0, MM_5x_Eight); +m_apm_add(tmp0, MM_One, tmp1); +m_apm_round(rr, places, tmp0); +M_restore_stack(4); +} +/****************************************************************************/ +/* + * compute r = sqrt(1 - a ^ 2). + */ +void M_cos_to_sin(M_APM r, int places, M_APM a) +{ +M_APM tmp1, tmp2; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +m_apm_multiply(tmp1, a, a); +m_apm_subtract(tmp2, MM_One, tmp1); +m_apm_sqrt(r, places, tmp2); +M_restore_stack(2); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_add.c b/src/apps/deskcalc/mapm_4.9.5/mapm_add.c new file mode 100644 index 0000000000..45e945b422 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_add.c @@ -0,0 +1,326 @@ + +/* + * M_APM - mapm_add.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_add.c,v 1.5 2007/12/03 01:33:39 mike Exp $ + * + * This file contains basic addition/subtraction functions + * + * $Log: mapm_add.c,v $ + * Revision 1.5 2007/12/03 01:33:39 mike + * Update license + * + * Revision 1.4 2003/12/04 01:15:42 mike + * redo math with 'borrow' + * + * Revision 1.3 2002/11/03 22:03:31 mike + * Updated function parameters to use the modern style + * + * Revision 1.2 2001/07/16 18:59:25 mike + * add function M_free_all_add + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static M_APM M_work1 = NULL; +static M_APM M_work2 = NULL; +static int M_add_firsttime = TRUE; + +/****************************************************************************/ +void M_free_all_add() +{ +if (M_add_firsttime == FALSE) + { + m_apm_free(M_work1); + m_apm_free(M_work2); + M_add_firsttime = TRUE; + } +} +/****************************************************************************/ +void m_apm_add(M_APM r, M_APM a, M_APM b) +{ +int j, carry, sign, aexp, bexp, adigits, bdigits; + +if (M_add_firsttime) + { + M_add_firsttime = FALSE; + M_work1 = m_apm_init(); + M_work2 = m_apm_init(); + } + +if (a->m_apm_sign == 0) + { + m_apm_copy(r,b); + return; + } + +if (b->m_apm_sign == 0) + { + m_apm_copy(r,a); + return; + } + +if (a->m_apm_sign == 1 && b->m_apm_sign == -1) + { + b->m_apm_sign = 1; + m_apm_subtract(r,a,b); + b->m_apm_sign = -1; + return; + } + +if (a->m_apm_sign == -1 && b->m_apm_sign == 1) + { + a->m_apm_sign = 1; + m_apm_subtract(r,b,a); + a->m_apm_sign = -1; + return; + } + +sign = a->m_apm_sign; /* signs are the same, result will be same */ + +aexp = a->m_apm_exponent; +bexp = b->m_apm_exponent; + +m_apm_copy(M_work1, a); +m_apm_copy(M_work2, b); + +/* + * scale by at least 1 factor of 10 in case the MSB carrys + */ + +if (aexp == bexp) + { + M_apm_scale(M_work1, 2); /* shift 2 digits == 1 byte for efficiency */ + M_apm_scale(M_work2, 2); + } +else + { + if (aexp > bexp) + { + M_apm_scale(M_work1, 2); + M_apm_scale(M_work2, (aexp + 2 - bexp)); + } + else /* aexp < bexp */ + { + M_apm_scale(M_work2, 2); + M_apm_scale(M_work1, (bexp + 2 - aexp)); + } + } + +adigits = M_work1->m_apm_datalength; +bdigits = M_work2->m_apm_datalength; + +if (adigits >= bdigits) + { + m_apm_copy(r, M_work1); + j = (bdigits + 1) >> 1; + carry = 0; + + while (TRUE) + { + j--; + r->m_apm_data[j] += carry + M_work2->m_apm_data[j]; + + if (r->m_apm_data[j] >= 100) + { + r->m_apm_data[j] -= 100; + carry = 1; + } + else + carry = 0; + + if (j == 0) + break; + } + } +else + { + m_apm_copy(r, M_work2); + j = (adigits + 1) >> 1; + carry = 0; + + while (TRUE) + { + j--; + r->m_apm_data[j] += carry + M_work1->m_apm_data[j]; + + if (r->m_apm_data[j] >= 100) + { + r->m_apm_data[j] -= 100; + carry = 1; + } + else + carry = 0; + + if (j == 0) + break; + } + } + +r->m_apm_sign = sign; + +M_apm_normalize(r); +} +/****************************************************************************/ +void m_apm_subtract(M_APM r, M_APM a, M_APM b) +{ +int itmp, j, flag, icompare, sign, aexp, bexp, + borrow, adigits, bdigits; + +if (M_add_firsttime) + { + M_add_firsttime = FALSE; + M_work1 = m_apm_init(); + M_work2 = m_apm_init(); + } + +if (b->m_apm_sign == 0) + { + m_apm_copy(r,a); + return; + } + +if (a->m_apm_sign == 0) + { + m_apm_copy(r,b); + r->m_apm_sign = -(r->m_apm_sign); + return; + } + +if (a->m_apm_sign == 1 && b->m_apm_sign == -1) + { + b->m_apm_sign = 1; + m_apm_add(r,a,b); + b->m_apm_sign = -1; + return; + } + +if (a->m_apm_sign == -1 && b->m_apm_sign == 1) + { + b->m_apm_sign = -1; + m_apm_add(r,a,b); + b->m_apm_sign = 1; + return; + } + +/* now, the signs are the same */ +/* make a positive working copy */ + +m_apm_absolute_value(M_work1, a); +m_apm_absolute_value(M_work2, b); + +/* are they the same?? if so, the result is zero */ + +if ((icompare = m_apm_compare(M_work1, M_work2)) == 0) + { + M_set_to_zero(r); + return; + } + +if (icompare == 1) /* |a| > |b| (do A-B) */ + { + flag = TRUE; + sign = a->m_apm_sign; + } +else /* |b| > |a| (do B-A) */ + { + flag = FALSE; + sign = -(a->m_apm_sign); + } + +aexp = M_work1->m_apm_exponent; +bexp = M_work2->m_apm_exponent; + +if (aexp > bexp) + M_apm_scale(M_work2, (aexp - bexp)); + +if (aexp < bexp) + M_apm_scale(M_work1, (bexp - aexp)); + +adigits = M_work1->m_apm_datalength; +bdigits = M_work2->m_apm_datalength; + +if (adigits > bdigits) + M_apm_pad(M_work2, adigits); + +if (adigits < bdigits) + M_apm_pad(M_work1, bdigits); + +if (flag) /* perform A-B, M_work1 - M_work2 */ + { + m_apm_copy(r, M_work1); + j = (r->m_apm_datalength + 1) >> 1; + borrow = 0; + + while (TRUE) + { + j--; + itmp = (int)r->m_apm_data[j] - ((int)M_work2->m_apm_data[j] + borrow); + + if (itmp >= 0) + { + r->m_apm_data[j] = (UCHAR)itmp; + borrow = 0; + } + else + { + r->m_apm_data[j] = (UCHAR)(100 + itmp); + borrow = 1; + } + + if (j == 0) + break; + } + } +else /* perform B-A, M_work2 - M_work1 */ + { + m_apm_copy(r, M_work2); + j = (r->m_apm_datalength + 1) >> 1; + borrow = 0; + + while (TRUE) + { + j--; + itmp = (int)r->m_apm_data[j] - ((int)M_work1->m_apm_data[j] + borrow); + + if (itmp >= 0) + { + r->m_apm_data[j] = (UCHAR)itmp; + borrow = 0; + } + else + { + r->m_apm_data[j] = (UCHAR)(100 + itmp); + borrow = 1; + } + + if (j == 0) + break; + } + } + +r->m_apm_sign = sign; + +M_apm_normalize(r); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_cpi.c b/src/apps/deskcalc/mapm_4.9.5/mapm_cpi.c new file mode 100644 index 0000000000..c3e091e07b --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_cpi.c @@ -0,0 +1,173 @@ + +/* + * M_APM - mapm_cpi.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_cpi.c,v 1.4 2007/12/03 01:34:29 mike Exp $ + * + * This file contains the PI related functions. + * + * $Log: mapm_cpi.c,v $ + * Revision 1.4 2007/12/03 01:34:29 mike + * Update license + * + * Revision 1.3 2002/11/05 23:10:14 mike + * streamline the PI AGM algorithm + * + * Revision 1.2 2002/11/03 21:56:21 mike + * Updated function parameters to use the modern style + * + * Revision 1.1 2001/03/25 21:01:53 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + * check if our local copy of PI is precise enough + * for our purpose. if not, calculate PI so it's + * as precise as desired, accurate to 'places' decimal + * places. + */ +void M_check_PI_places(int places) +{ +int dplaces; + +dplaces = places + 2; + +if (dplaces > MM_lc_PI_digits) + { + MM_lc_PI_digits = dplaces + 2; + + /* compute PI using the AGM (see right below) */ + + M_calculate_PI_AGM(MM_lc_PI, (dplaces + 5)); + + m_apm_multiply(MM_lc_HALF_PI, MM_0_5, MM_lc_PI); + m_apm_multiply(MM_lc_2_PI, MM_Two, MM_lc_PI); + } +} +/****************************************************************************/ +/* + * Calculate PI using the AGM (Arithmetic-Geometric Mean) + * + * Init : A0 = 1 + * B0 = 1 / sqrt(2) + * Sum = 1 + * + * Iterate: n = 1... + * + * + * A = 0.5 * [ A + B ] + * n n-1 n-1 + * + * + * B = sqrt [ A * B ] + * n n-1 n-1 + * + * + * + * C = 0.5 * [ A - B ] + * n n-1 n-1 + * + * + * 2 n+1 + * Sum = Sum - C * 2 + * n + * + * + * At the end when C is 'small enough' : + * n + * + * 2 + * PI = 4 * A / Sum + * n+1 + * + * -OR- + * + * 2 + * PI = ( A + B ) / Sum + * n n + * + */ +void M_calculate_PI_AGM(M_APM outv, int places) +{ +M_APM tmp1, tmp2, a0, b0, c0, a1, b1, sum, pow_2; +int dplaces, nn; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +a0 = M_get_stack_var(); +b0 = M_get_stack_var(); +c0 = M_get_stack_var(); +a1 = M_get_stack_var(); +b1 = M_get_stack_var(); +sum = M_get_stack_var(); +pow_2 = M_get_stack_var(); + +dplaces = places + 16; + +m_apm_copy(a0, MM_One); +m_apm_copy(sum, MM_One); +m_apm_copy(pow_2, MM_Four); +m_apm_sqrt(b0, dplaces, MM_0_5); /* sqrt(0.5) */ + +while (TRUE) + { + m_apm_add(tmp1, a0, b0); + m_apm_multiply(a1, MM_0_5, tmp1); + + m_apm_multiply(tmp1, a0, b0); + m_apm_sqrt(b1, dplaces, tmp1); + + m_apm_subtract(tmp1, a0, b0); + m_apm_multiply(c0, MM_0_5, tmp1); + + /* + * the net 'PI' calculated from this iteration will + * be accurate to ~4 X the value of (c0)'s exponent. + * this was determined experimentally. + */ + + nn = -4 * c0->m_apm_exponent; + + m_apm_multiply(tmp1, c0, c0); + m_apm_multiply(tmp2, tmp1, pow_2); + m_apm_subtract(tmp1, sum, tmp2); + m_apm_round(sum, dplaces, tmp1); + + if (nn >= dplaces) + break; + + m_apm_copy(a0, a1); + m_apm_copy(b0, b1); + + m_apm_multiply(tmp1, pow_2, MM_Two); + m_apm_copy(pow_2, tmp1); + } + +m_apm_add(tmp1, a1, b1); +m_apm_multiply(tmp2, tmp1, tmp1); +m_apm_divide(tmp1, dplaces, tmp2, sum); +m_apm_round(outv, places, tmp1); + +M_restore_stack(9); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_div.c b/src/apps/deskcalc/mapm_4.9.5/mapm_div.c new file mode 100644 index 0000000000..acd289cf1b --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_div.c @@ -0,0 +1,337 @@ + +/* + * M_APM - mapm_div.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_div.c,v 1.12 2007/12/03 01:35:18 mike Exp $ + * + * This file contains the basic division functions + * + * $Log: mapm_div.c,v $ + * Revision 1.12 2007/12/03 01:35:18 mike + * Update license + * + * Revision 1.11 2003/07/21 20:07:13 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.10 2003/03/31 22:09:18 mike + * call generic error handling function + * + * Revision 1.9 2002/11/03 22:06:50 mike + * Updated function parameters to use the modern style + * + * Revision 1.8 2001/07/16 19:03:22 mike + * add function M_free_all_div + * + * Revision 1.7 2001/02/11 22:30:42 mike + * modify parameters to REALLOC + * + * Revision 1.6 2000/09/23 19:07:17 mike + * change _divide to M_apm_sdivide function name + * + * Revision 1.5 2000/04/11 18:38:55 mike + * use new algorithm to determine q-hat. uses more digits of + * the numerator and denominator. + * + * Revision 1.4 2000/02/03 22:45:08 mike + * use MAPM_* generic memory function + * + * Revision 1.3 1999/06/23 01:10:49 mike + * use predefined constant for '15' + * + * Revision 1.2 1999/06/23 00:55:09 mike + * change mult factor to 15 + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static M_APM M_div_worka; +static M_APM M_div_workb; +static M_APM M_div_tmp7; +static M_APM M_div_tmp8; +static M_APM M_div_tmp9; + +static int M_div_firsttime = TRUE; + +/****************************************************************************/ +void M_free_all_div() +{ +if (M_div_firsttime == FALSE) + { + m_apm_free(M_div_worka); + m_apm_free(M_div_workb); + m_apm_free(M_div_tmp7); + m_apm_free(M_div_tmp8); + m_apm_free(M_div_tmp9); + + M_div_firsttime = TRUE; + } +} +/****************************************************************************/ +void m_apm_integer_div_rem(M_APM qq, M_APM rr, M_APM aa, M_APM bb) +{ +m_apm_integer_divide(qq, aa, bb); +m_apm_multiply(M_div_tmp7, qq, bb); +m_apm_subtract(rr, aa, M_div_tmp7); +} +/****************************************************************************/ +void m_apm_integer_divide(M_APM rr, M_APM aa, M_APM bb) +{ +/* + * we must use this divide function since the + * faster divide function using the reciprocal + * will round the result (possibly changing + * nnm.999999... --> nn(m+1).0000 which would + * invalidate the 'integer_divide' goal). + */ + +M_apm_sdivide(rr, 4, aa, bb); + +if (rr->m_apm_exponent <= 0) /* result is 0 */ + { + M_set_to_zero(rr); + } +else + { + if (rr->m_apm_datalength > rr->m_apm_exponent) + { + rr->m_apm_datalength = rr->m_apm_exponent; + M_apm_normalize(rr); + } + } +} +/****************************************************************************/ +void M_apm_sdivide(M_APM r, int places, M_APM a, M_APM b) +{ +int j, k, m, b0, sign, nexp, indexr, icompare, iterations; +long trial_numer; +void *vp; + +if (M_div_firsttime) + { + M_div_firsttime = FALSE; + + M_div_worka = m_apm_init(); + M_div_workb = m_apm_init(); + M_div_tmp7 = m_apm_init(); + M_div_tmp8 = m_apm_init(); + M_div_tmp9 = m_apm_init(); + } + +sign = a->m_apm_sign * b->m_apm_sign; + +if (sign == 0) /* one number is zero, result is zero */ + { + if (b->m_apm_sign == 0) + { + M_apm_log_error_msg(M_APM_RETURN, "\'M_apm_sdivide\', Divide by 0"); + } + + M_set_to_zero(r); + return; + } + +/* + * Knuth step D1. Since base = 100, base / 2 = 50. + * (also make the working copies positive) + */ + +if (b->m_apm_data[0] >= 50) + { + m_apm_absolute_value(M_div_worka, a); + m_apm_absolute_value(M_div_workb, b); + } +else /* 'normal' step D1 */ + { + k = 100 / (b->m_apm_data[0] + 1); + m_apm_set_long(M_div_tmp9, (long)k); + + m_apm_multiply(M_div_worka, M_div_tmp9, a); + m_apm_multiply(M_div_workb, M_div_tmp9, b); + + M_div_worka->m_apm_sign = 1; + M_div_workb->m_apm_sign = 1; + } + +/* setup trial denominator for step D3 */ + +b0 = 100 * (int)M_div_workb->m_apm_data[0]; + +if (M_div_workb->m_apm_datalength >= 3) + b0 += M_div_workb->m_apm_data[1]; + +nexp = M_div_worka->m_apm_exponent - M_div_workb->m_apm_exponent; + +if (nexp > 0) + iterations = nexp + places + 1; +else + iterations = places + 1; + +k = (iterations + 1) >> 1; /* required size of result, in bytes */ + +if (k > r->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(r->m_apm_data, (k + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_sdivide\', Out of memory"); + } + + r->m_apm_malloclength = k + 28; + r->m_apm_data = (UCHAR *)vp; + } + +/* clear the exponent in the working copies */ + +M_div_worka->m_apm_exponent = 0; +M_div_workb->m_apm_exponent = 0; + +/* if numbers are equal, ratio == 1.00000... */ + +if ((icompare = m_apm_compare(M_div_worka, M_div_workb)) == 0) + { + iterations = 1; + r->m_apm_data[0] = 10; + nexp++; + } +else /* ratio not 1, do the real division */ + { + if (icompare == 1) /* numerator > denominator */ + { + nexp++; /* to adjust the final exponent */ + M_div_worka->m_apm_exponent += 1; /* multiply numerator by 10 */ + } + else /* numerator < denominator */ + { + M_div_worka->m_apm_exponent += 2; /* multiply numerator by 100 */ + } + + indexr = 0; + m = 0; + + while (TRUE) + { + /* + * Knuth step D3. Only use the 3rd -> 6th digits if the number + * actually has that many digits. + */ + + trial_numer = 10000L * (long)M_div_worka->m_apm_data[0]; + + if (M_div_worka->m_apm_datalength >= 5) + { + trial_numer += 100 * M_div_worka->m_apm_data[1] + + M_div_worka->m_apm_data[2]; + } + else + { + if (M_div_worka->m_apm_datalength >= 3) + trial_numer += 100 * M_div_worka->m_apm_data[1]; + } + + j = (int)(trial_numer / b0); + + /* + * Since the library 'normalizes' all the results, we need + * to look at the exponent of the number to decide if we + * have a lead in 0n or 00. + */ + + if ((k = 2 - M_div_worka->m_apm_exponent) > 0) + { + while (TRUE) + { + j /= 10; + if (--k == 0) + break; + } + } + + if (j == 100) /* qhat == base ?? */ + j = 99; /* if so, decrease by 1 */ + + m_apm_set_long(M_div_tmp8, (long)j); + m_apm_multiply(M_div_tmp7, M_div_tmp8, M_div_workb); + + /* + * Compare our q-hat (j) against the desired number. + * j is either correct, 1 too large, or 2 too large + * per Theorem B on pg 272 of Art of Compter Programming, + * Volume 2, 3rd Edition. + * + * The above statement is only true if using the 2 leading + * digits of the numerator and the leading digit of the + * denominator. Since we are using the (3) leading digits + * of the numerator and the (2) leading digits of the + * denominator, we eliminate the case where our q-hat is + * 2 too large, (and q-hat being 1 too large is quite remote). + */ + + if (m_apm_compare(M_div_tmp7, M_div_worka) == 1) + { + j--; + m_apm_subtract(M_div_tmp8, M_div_tmp7, M_div_workb); + m_apm_copy(M_div_tmp7, M_div_tmp8); + } + + /* + * Since we know q-hat is correct, step D6 is unnecessary. + * + * Store q-hat, step D5. Since D6 is unnecessary, we can + * do D5 before D4 and decide if we are done. + */ + + r->m_apm_data[indexr++] = (UCHAR)j; /* j == 'qhat' */ + m += 2; + + if (m >= iterations) + break; + + /* step D4 */ + + m_apm_subtract(M_div_tmp9, M_div_worka, M_div_tmp7); + + /* + * if the subtraction yields zero, the division is exact + * and we are done early. + */ + + if (M_div_tmp9->m_apm_sign == 0) + { + iterations = m; + break; + } + + /* multiply by 100 and re-save */ + M_div_tmp9->m_apm_exponent += 2; + m_apm_copy(M_div_worka, M_div_tmp9); + } + } + +r->m_apm_sign = sign; +r->m_apm_exponent = nexp; +r->m_apm_datalength = iterations; + +M_apm_normalize(r); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_exp.c b/src/apps/deskcalc/mapm_4.9.5/mapm_exp.c new file mode 100644 index 0000000000..9d8972828e --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_exp.c @@ -0,0 +1,408 @@ + +/* + * M_APM - mapm_exp.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_exp.c,v 1.37 2007/12/03 01:36:00 mike Exp $ + * + * This file contains the EXP function. + * + * $Log: mapm_exp.c,v $ + * Revision 1.37 2007/12/03 01:36:00 mike + * Update license + * + * Revision 1.36 2004/06/02 00:29:03 mike + * simplify logic in compute_nn + * + * Revision 1.35 2004/05/29 18:29:44 mike + * move exp nn calculation into its own function + * + * Revision 1.34 2004/05/21 20:41:01 mike + * fix potential buffer overflow + * + * Revision 1.33 2004/02/18 02:46:45 mike + * fix comment + * + * Revision 1.32 2004/02/18 02:41:35 mike + * check to make sure 'nn' does not overflow + * + * Revision 1.31 2004/01/01 00:06:38 mike + * make a comment more clear + * + * Revision 1.30 2003/12/31 21:44:57 mike + * simplify logic in _exp + * + * Revision 1.29 2003/12/28 00:03:27 mike + * dont allow 'tmp7' to get too small prior to divide by 256 + * + * Revision 1.28 2003/12/27 22:53:04 mike + * change 1024 to 512, if input is already small, call + * raw_exp directly and return + * + * Revision 1.27 2003/03/30 21:16:37 mike + * use global version of log(2) instead of local copy + * + * Revision 1.26 2002/11/03 22:30:18 mike + * Updated function parameters to use the modern style + * + * Revision 1.25 2001/08/06 22:07:00 mike + * round the 'nn' calculation to the nearest int + * + * Revision 1.24 2001/08/05 21:58:59 mike + * make 1 / log(2) constant shorter + * + * Revision 1.23 2001/07/16 19:10:23 mike + * add function M_free_all_exp + * + * Revision 1.22 2001/07/10 21:55:36 mike + * optimize raw_exp by using fewer digits as the + * subsequent terms get smaller + * + * Revision 1.21 2001/02/06 21:20:31 mike + * optimize 'nn' calculation (for the future) + * + * Revision 1.20 2001/02/05 21:55:12 mike + * minor optimization, use a multiply instead + * of a divide + * + * Revision 1.19 2000/08/22 21:34:41 mike + * increase local precision + * + * Revision 1.18 2000/05/18 22:05:22 mike + * move _pow to a separate file + * + * Revision 1.17 2000/05/04 23:21:01 mike + * use global var 256R + * + * Revision 1.16 2000/03/30 21:33:30 mike + * change termination of raw_exp to use ints, not MAPM numbers + * + * Revision 1.15 2000/02/05 22:59:46 mike + * adjust decimal places on calculation + * + * Revision 1.14 2000/02/04 20:45:21 mike + * re-compute log(2) on the fly if we need a more precise value + * + * Revision 1.13 2000/02/04 19:35:14 mike + * use just an approx log(2) for the integer divide + * + * Revision 1.12 2000/02/04 16:47:32 mike + * use the real algorithm for EXP + * + * Revision 1.11 1999/09/18 01:27:40 mike + * if X is 0 on the pow function, return 0 right away + * + * Revision 1.10 1999/06/19 20:54:07 mike + * changed local static MAPM to stack variables + * + * Revision 1.9 1999/06/01 22:37:44 mike + * adjust decimal places passed to raw function + * + * Revision 1.8 1999/06/01 01:44:03 mike + * change threshold from 1000 to 100 for 65536 divisor + * + * Revision 1.7 1999/06/01 01:03:31 mike + * vary 'q' instead of checking input against +/- 10 and +/- 40 + * + * Revision 1.6 1999/05/15 01:54:27 mike + * add check for number of decimal places + * + * Revision 1.5 1999/05/15 01:09:49 mike + * minor tweak to POW decimal places + * + * Revision 1.4 1999/05/13 00:14:00 mike + * added more comments + * + * Revision 1.3 1999/05/12 23:39:05 mike + * change #places passed to sub functions + * + * Revision 1.2 1999/05/10 21:35:13 mike + * added some comments + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static M_APM MM_exp_log2R; +static M_APM MM_exp_512R; +static int MM_firsttime1 = TRUE; + +/****************************************************************************/ +void M_free_all_exp() +{ +if (MM_firsttime1 == FALSE) + { + m_apm_free(MM_exp_log2R); + m_apm_free(MM_exp_512R); + + MM_firsttime1 = TRUE; + } +} +/****************************************************************************/ +void m_apm_exp(M_APM r, int places, M_APM x) +{ +M_APM tmp7, tmp8, tmp9; +int dplaces, nn, ii; + +if (MM_firsttime1) + { + MM_firsttime1 = FALSE; + + MM_exp_log2R = m_apm_init(); + MM_exp_512R = m_apm_init(); + + m_apm_set_string(MM_exp_log2R, "1.44269504089"); /* ~ 1 / log(2) */ + m_apm_set_string(MM_exp_512R, "1.953125E-3"); /* 1 / 512 */ + } + +tmp7 = M_get_stack_var(); +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +if (x->m_apm_sign == 0) /* if input == 0, return '1' */ + { + m_apm_copy(r, MM_One); + M_restore_stack(3); + return; + } + +if (x->m_apm_exponent <= -3) /* already small enough so call _raw directly */ + { + M_raw_exp(tmp9, (places + 6), x); + m_apm_round(r, places, tmp9); + M_restore_stack(3); + return; + } + +/* + From David H. Bailey's MPFUN Fortran package : + + exp (t) = (1 + r + r^2 / 2! + r^3 / 3! + r^4 / 4! ...) ^ q * 2 ^ n + + where q = 256, r = t' / q, t' = t - n Log(2) and where n is chosen so + that -0.5 Log(2) < t' <= 0.5 Log(2). Reducing t mod Log(2) and + dividing by 256 insures that -0.001 < r <= 0.001, which accelerates + convergence in the above series. + + I use q = 512 and also limit how small 'r' can become. The 'r' used + here is limited in magnitude from 1.95E-4 < |r| < 1.35E-3. Forcing + 'r' into a narrow range keeps the algorithm 'well behaved'. + + ( the range is [0.1 / 512] to [log(2) / 512] ) +*/ + +if (M_exp_compute_nn(&nn, tmp7, x) != 0) + { + M_apm_log_error_msg(M_APM_RETURN, + "\'m_apm_exp\', Input too large, Overflow"); + + M_set_to_zero(r); + M_restore_stack(3); + return; + } + +dplaces = places + 8; + +/* check to make sure our log(2) is accurate enough */ + +M_check_log_places(dplaces); + +m_apm_multiply(tmp8, tmp7, MM_lc_log2); +m_apm_subtract(tmp7, x, tmp8); + +/* + * guarantee that |tmp7| is between 0.1 and 0.9999999.... + * (in practice, the upper limit only reaches log(2), 0.693... ) + */ + +while (TRUE) + { + if (tmp7->m_apm_sign != 0) + { + if (tmp7->m_apm_exponent == 0) + break; + } + + if (tmp7->m_apm_sign >= 0) + { + nn++; + m_apm_subtract(tmp8, tmp7, MM_lc_log2); + m_apm_copy(tmp7, tmp8); + } + else + { + nn--; + m_apm_add(tmp8, tmp7, MM_lc_log2); + m_apm_copy(tmp7, tmp8); + } + } + +m_apm_multiply(tmp9, tmp7, MM_exp_512R); + +/* perform the series expansion ... */ + +M_raw_exp(tmp8, dplaces, tmp9); + +/* + * raise result to the 512 power + * + * note : x ^ 512 = (((x ^ 2) ^ 2) ^ 2) ... 9 times + */ + +ii = 9; + +while (TRUE) + { + m_apm_multiply(tmp9, tmp8, tmp8); + m_apm_round(tmp8, dplaces, tmp9); + + if (--ii == 0) + break; + } + +/* now compute 2 ^ N */ + +m_apm_integer_pow(tmp7, dplaces, MM_Two, nn); + +m_apm_multiply(tmp9, tmp7, tmp8); +m_apm_round(r, places, tmp9); + +M_restore_stack(3); /* restore the 3 locals we used here */ +} +/****************************************************************************/ +/* + compute int *n = round_to_nearest_int(a / log(2)) + M_APM b = MAPM version of *n + + returns 0: OK + -1, 1: failure +*/ +int M_exp_compute_nn(int *n, M_APM b, M_APM a) +{ +M_APM tmp0, tmp1; +void *vp; +char *cp, sbuf[48]; +int kk; + +*n = 0; +vp = NULL; +cp = sbuf; +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); + +/* find 'n' and convert it to a normal C int */ +/* we just need an approx 1/log(2) for this calculation */ + +m_apm_multiply(tmp1, a, MM_exp_log2R); + +/* round to the nearest int */ + +if (tmp1->m_apm_sign >= 0) + { + m_apm_add(tmp0, tmp1, MM_0_5); + m_apm_floor(tmp1, tmp0); + } +else + { + m_apm_subtract(tmp0, tmp1, MM_0_5); + m_apm_ceil(tmp1, tmp0); + } + +kk = tmp1->m_apm_exponent; +if (kk >= 42) + { + if ((vp = (void *)MAPM_MALLOC((kk + 16) * sizeof(char))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'M_exp_compute_nn\', Out of memory"); + } + + cp = (char *)vp; + } + +m_apm_to_integer_string(cp, tmp1); +*n = atoi(cp); + +m_apm_set_long(b, (long)(*n)); + +kk = m_apm_compare(b, tmp1); + +if (vp != NULL) + MAPM_FREE(vp); + +M_restore_stack(2); +return(kk); +} +/****************************************************************************/ +/* + calculate the exponential function using the following series : + + x^2 x^3 x^4 x^5 + exp(x) == 1 + x + --- + --- + --- + --- ... + 2! 3! 4! 5! + +*/ +void M_raw_exp(M_APM rr, int places, M_APM xx) +{ +M_APM tmp0, digit, term; +int tolerance, local_precision, prev_exp; +long m1; + +tmp0 = M_get_stack_var(); +term = M_get_stack_var(); +digit = M_get_stack_var(); + +local_precision = places + 8; +tolerance = -(places + 4); +prev_exp = 0; + +m_apm_add(rr, MM_One, xx); +m_apm_copy(term, xx); + +m1 = 2L; + +while (TRUE) + { + m_apm_set_long(digit, m1); + m_apm_multiply(tmp0, term, xx); + m_apm_divide(term, local_precision, tmp0, digit); + m_apm_add(tmp0, rr, term); + m_apm_copy(rr, tmp0); + + if ((term->m_apm_exponent < tolerance) || (term->m_apm_sign == 0)) + break; + + if (m1 != 2L) + { + local_precision = local_precision + term->m_apm_exponent - prev_exp; + + if (local_precision < 20) + local_precision = 20; + } + + prev_exp = term->m_apm_exponent; + m1++; + } + +M_restore_stack(3); /* restore the 3 locals we used here */ +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_fam.c b/src/apps/deskcalc/mapm_4.9.5/mapm_fam.c new file mode 100644 index 0000000000..143fdfe7cd --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_fam.c @@ -0,0 +1,70 @@ + +/* + * M_APM - mapm_fam.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_fam.c,v 1.5 2007/12/03 01:36:38 mike Exp $ + * + * This file contains the free all memory and similiar functions. + * + * $Log: mapm_fam.c,v $ + * Revision 1.5 2007/12/03 01:36:38 mike + * Update license + * + * Revision 1.4 2003/03/30 21:13:05 mike + * remove _log from free list + * + * Revision 1.3 2002/02/14 13:36:27 mike + * add conditional compile around free all FFT + * + * Revision 1.2 2001/07/16 18:52:40 mike + * add some comments + * + * Revision 1.1 2001/07/16 18:41:44 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_free_all_mem() +{ +M_free_all_add(); /* call each module which has statically declared data */ +M_free_all_div(); +M_free_all_exp(); + +#ifndef NO_FFT_MULTIPLY +M_free_all_fft(); +#endif + +M_free_all_pow(); +M_free_all_rnd(); +M_free_all_set(); +M_free_all_cnst(); +M_free_all_fmul(); +M_free_all_stck(); +M_free_all_util(); +} +/****************************************************************************/ +void m_apm_trim_mem_usage() +{ +m_apm_free_all_mem(); +m_apm_free(m_apm_init()); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_fft.c b/src/apps/deskcalc/mapm_4.9.5/mapm_fft.c new file mode 100644 index 0000000000..6ba2d3162d --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_fft.c @@ -0,0 +1,955 @@ + +/* + * M_APM - mapm_fft.c + * + * This FFT (Fast Fourier Transform) is from Takuya OOURA + * + * Copyright(C) 1996-1999 Takuya OOURA + * email: ooura@mmm.t.u-tokyo.ac.jp + * + * See full FFT documentation below ... (MCR) + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_fft.c,v 1.15 2007/12/03 01:37:42 mike Exp $ + * + * This file contains the FFT based FAST MULTIPLICATION function + * as well as its support functions. + * + * $Log: mapm_fft.c,v $ + * Revision 1.15 2007/12/03 01:37:42 mike + * no changes + * + * Revision 1.14 2003/07/28 19:39:01 mike + * change 16 bit constant + * + * Revision 1.13 2003/07/21 20:11:55 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.12 2003/05/01 21:55:36 mike + * remove math.h + * + * Revision 1.11 2003/03/31 22:10:09 mike + * call generic error handling function + * + * Revision 1.10 2002/11/03 22:11:48 mike + * Updated function parameters to use the modern style + * + * Revision 1.9 2001/07/16 19:16:15 mike + * add function M_free_all_fft + * + * Revision 1.8 2000/08/01 22:23:24 mike + * use sizeof(int) from function call to stop + * some compilers from complaining. + * + * Revision 1.7 2000/07/30 22:39:21 mike + * lower 16 bit malloc size + * + * Revision 1.6 2000/07/10 22:54:26 mike + * malloc the local data arrays + * + * Revision 1.5 2000/07/10 00:09:02 mike + * use local static arrays for smaller numbers + * + * Revision 1.4 2000/07/08 18:24:23 mike + * minor optimization tweak + * + * Revision 1.3 2000/07/08 17:52:49 mike + * do the FFT in base 10000 instead of MAPM numbers base 100 + * this runs faster and uses 1/2 the RAM + * + * Revision 1.2 2000/07/06 21:04:34 mike + * added more comments + * + * Revision 1.1 2000/07/06 20:42:05 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +#ifndef MM_PI_2 +#define MM_PI_2 1.570796326794896619231321691639751442098584699687 +#endif + +#ifndef WR5000 /* cos(MM_PI_2*0.5000) */ +#define WR5000 0.707106781186547524400844362104849039284835937688 +#endif + +#ifndef RDFT_LOOP_DIV /* control of the RDFT's speed & tolerance */ +#define RDFT_LOOP_DIV 64 +#endif + +extern void M_fast_mul_fft(UCHAR *, UCHAR *, UCHAR *, int); + +extern void M_rdft(int, int, double *); +extern void M_bitrv2(int, double *); +extern void M_cftfsub(int, double *); +extern void M_cftbsub(int, double *); +extern void M_rftfsub(int, double *); +extern void M_rftbsub(int, double *); +extern void M_cft1st(int, double *); +extern void M_cftmdl(int, int, double *); + +static double *M_aa_array, *M_bb_array; +static int M_size = -1; + +static char *M_fft_error_msg = "\'M_fast_mul_fft\', Out of memory"; + +/****************************************************************************/ +void M_free_all_fft() +{ +if (M_size > 0) + { + MAPM_FREE(M_aa_array); + MAPM_FREE(M_bb_array); + M_size = -1; + } +} +/****************************************************************************/ +/* + * multiply 'uu' by 'vv' with nbytes each + * yielding a 2*nbytes result in 'ww'. + * each byte contains a base 100 'digit', + * i.e.: range from 0-99. + * + * MSB LSB + * + * uu,vv [0] [1] [2] ... [N-1] + * ww [0] [1] [2] ... [2N-1] + */ + +void M_fast_mul_fft(UCHAR *ww, UCHAR *uu, UCHAR *vv, int nbytes) +{ +int mflag, i, j, nn2, nn; +double carry, nnr, dtemp, *a, *b; +UCHAR *w0; +unsigned long ul; + +if (M_size < 0) /* if first time in, setup working arrays */ + { + if (M_get_sizeof_int() == 2) /* if still using 16 bit compilers */ + M_size = 516; + else + M_size = 8200; + + M_aa_array = (double *)MAPM_MALLOC(M_size * sizeof(double)); + M_bb_array = (double *)MAPM_MALLOC(M_size * sizeof(double)); + + if ((M_aa_array == NULL) || (M_bb_array == NULL)) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_fft_error_msg); + } + } + +nn = nbytes; +nn2 = nbytes >> 1; + +if (nn > M_size) + { + mflag = TRUE; + + a = (double *)MAPM_MALLOC((nn + 8) * sizeof(double)); + b = (double *)MAPM_MALLOC((nn + 8) * sizeof(double)); + + if ((a == NULL) || (b == NULL)) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_fft_error_msg); + } + } +else + { + mflag = FALSE; + + a = M_aa_array; + b = M_bb_array; + } + +/* + * convert normal base 100 MAPM numbers to base 10000 + * for the FFT operation. + */ + +i = 0; +for (j=0; j < nn2; j++) + { + a[j] = (double)((int)uu[i] * 100 + uu[i+1]); + b[j] = (double)((int)vv[i] * 100 + vv[i+1]); + i += 2; + } + +/* zero fill the second half of the arrays */ + +for (j=nn2; j < nn; j++) + { + a[j] = 0.0; + b[j] = 0.0; + } + +/* perform the forward Fourier transforms for both numbers */ + +M_rdft(nn, 1, a); +M_rdft(nn, 1, b); + +/* perform the convolution ... */ + +b[0] *= a[0]; +b[1] *= a[1]; + +for (j=3; j <= nn; j += 2) + { + dtemp = b[j-1]; + b[j-1] = dtemp * a[j-1] - b[j] * a[j]; + b[j] = dtemp * a[j] + b[j] * a[j-1]; + } + +/* perform the inverse transform on the result */ + +M_rdft(nn, -1, b); + +/* perform a final pass to release all the carries */ +/* we are still in base 10000 at this point */ + +carry = 0.0; +j = nn; +nnr = 2.0 / (double)nn; + +while (1) + { + dtemp = b[--j] * nnr + carry + 0.5; + ul = (unsigned long)(dtemp * 1.0E-4); + carry = (double)ul; + b[j] = dtemp - carry * 10000.0; + + if (j == 0) + break; + } + +/* copy result to our destination after converting back to base 100 */ + +w0 = ww; +M_get_div_rem((int)ul, w0, (w0 + 1)); + +for (j=0; j <= (nn - 2); j++) + { + w0 += 2; + M_get_div_rem((int)b[j], w0, (w0 + 1)); + } + +if (mflag) + { + MAPM_FREE(b); + MAPM_FREE(a); + } +} +/****************************************************************************/ + +/* + * The following info is from Takuya OOURA's documentation : + * + * NOTE : MAPM only uses the 'RDFT' function (as well as the + * functions RDFT calls). All the code from here down + * in this file is from Takuya OOURA. The only change I + * made was to add 'M_' in front of all the functions + * I used. This was to guard against any possible + * name collisions in the future. + * + * MCR 06 July 2000 + * + * + * General Purpose FFT (Fast Fourier/Cosine/Sine Transform) Package + * + * Description: + * A package to calculate Discrete Fourier/Cosine/Sine Transforms of + * 1-dimensional sequences of length 2^N. + * + * fft4g_h.c : FFT Package in C - Simple Version I (radix 4,2) + * + * rdft: Real Discrete Fourier Transform + * + * Method: + * -------- rdft -------- + * A method with a following butterfly operation appended to "cdft". + * In forward transform : + * A[k] = sum_j=0^n-1 a[j]*W(n)^(j*k), 0<=k<=n/2, + * W(n) = exp(2*pi*i/n), + * this routine makes an array x[] : + * x[j] = a[2*j] + i*a[2*j+1], 0<=j RDFT + R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 + I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale) + a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k + rdft(n, 1, a); + + rdft(n, -1, a); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + + output data + a[2*k] = R[k], 0<=k + input data + a[2*j] = R[j], 0<=j= 0) { + if (n > 4) { + M_bitrv2(n, a); + M_cftfsub(n, a); + M_rftfsub(n, a); + } else if (n == 4) { + M_cftfsub(n, a); + } + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } else { + a[1] = 0.5 * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) { + M_rftbsub(n, a); + M_bitrv2(n, a); + M_cftbsub(n, a); + } else if (n == 4) { + M_cftfsub(n, a); + } + } +} + + + +void M_bitrv2(int n, double *a) +{ + int j0, k0, j1, k1, l, m, i, j, k; + double xr, xi, yr, yi; + + l = n >> 2; + m = 2; + while (m < l) { + l >>= 1; + m <<= 1; + } + if (m == l) { + j0 = 0; + for (k0 = 0; k0 < m; k0 += 2) { + k = k0; + for (j = j0; j < j0 + k0; j += 2) { + xr = a[j]; + xi = a[j + 1]; + yr = a[k]; + yi = a[k + 1]; + a[j] = yr; + a[j + 1] = yi; + a[k] = xr; + a[k + 1] = xi; + j1 = j + m; + k1 = k + 2 * m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += 2 * m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = n >> 1; i > (k ^= i); i >>= 1); + } + j1 = j0 + k0 + m; + k1 = j1 + m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = n >> 1; i > (j0 ^= i); i >>= 1); + } + } else { + j0 = 0; + for (k0 = 2; k0 < m; k0 += 2) { + for (i = n >> 1; i > (j0 ^= i); i >>= 1); + k = k0; + for (j = j0; j < j0 + k0; j += 2) { + xr = a[j]; + xi = a[j + 1]; + yr = a[k]; + yi = a[k + 1]; + a[j] = yr; + a[j + 1] = yi; + a[k] = xr; + a[k + 1] = xi; + j1 = j + m; + k1 = k + m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = n >> 1; i > (k ^= i); i >>= 1); + } + } + } +} + + + +void M_cftfsub(int n, double *a) +{ + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + M_cft1st(n, a); + l = 8; + while ((l << 2) < n) { + M_cftmdl(n, l, a); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = a[j + 1] - a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] += a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + + + +void M_cftbsub(int n, double *a) +{ + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + M_cft1st(n, a); + l = 8; + while ((l << 2) < n) { + M_cftmdl(n, l, a); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = -a[j + 1] + a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] = -a[j + 1] - a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + + + +void M_cft1st(int n, double *a) +{ + int j, kj, kr; + double ew, wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wn4r = WR5000; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wn4r * (x0r - x0i); + a[11] = wn4r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wn4r * (x0i - x0r); + a[15] = wn4r * (x0i + x0r); + ew = MM_PI_2 / n; + kr = 0; + for (j = 16; j < n; j += 16) { + for (kj = n >> 2; kj > (kr ^= kj); kj >>= 1); + wk1r = cos(ew * kr); + wk1i = sin(ew * kr); + wk2r = 1 - 2 * wk1i * wk1i; + wk2i = 2 * wk1i * wk1r; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + x0r = a[j] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + x0r = wn4r * (wk1r - wk1i); + wk1i = wn4r * (wk1r + wk1i); + wk1r = x0r; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } +} + + + +void M_cftmdl(int n, int l, double *a) +{ + int j, j1, j2, j3, k, kj, kr, m, m2; + double ew, wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + m = l << 2; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wn4r = WR5000; + for (j = m; j < l + m; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wn4r * (x0r - x0i); + a[j1 + 1] = wn4r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3] = wn4r * (x0i - x0r); + a[j3 + 1] = wn4r * (x0i + x0r); + } + ew = MM_PI_2 / n; + kr = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + for (kj = n >> 2; kj > (kr ^= kj); kj >>= 1); + wk1r = cos(ew * kr); + wk1i = sin(ew * kr); + wk2r = 1 - 2 * wk1i * wk1i; + wk2i = 2 * wk1i * wk1r; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j < l + k; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + x0r = wn4r * (wk1r - wk1i); + wk1i = wn4r * (wk1r + wk1i); + wk1r = x0r; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + for (j = k + m; j < l + (k + m); j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } +} + + + +void M_rftfsub(int n, double *a) +{ + int i, i0, j, k; + double ec, w1r, w1i, wkr, wki, wdr, wdi, ss, xr, xi, yr, yi; + + ec = 2 * MM_PI_2 / n; + wkr = 0; + wki = 0; + wdi = cos(ec); + wdr = sin(ec); + wdi *= wdr; + wdr *= wdr; + w1r = 1 - 2 * wdr; + w1i = 2 * wdi; + ss = 2 * w1i; + i = n >> 1; + while (1) { + i0 = i - 4 * RDFT_LOOP_DIV; + if (i0 < 4) { + i0 = 4; + } + for (j = i - 4; j >= i0; j -= 4) { + k = n - j; + xr = a[j + 2] - a[k - 2]; + xi = a[j + 3] + a[k - 1]; + yr = wdr * xr - wdi * xi; + yi = wdr * xi + wdi * xr; + a[j + 2] -= yr; + a[j + 3] -= yi; + a[k - 2] += yr; + a[k - 1] -= yi; + wkr += ss * wdi; + wki += ss * (0.5 - wdr); + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + wdr += ss * wki; + wdi += ss * (0.5 - wkr); + } + if (i0 == 4) { + break; + } + wkr = 0.5 * sin(ec * i0); + wki = 0.5 * cos(ec * i0); + wdr = 0.5 - (wkr * w1r - wki * w1i); + wdi = wkr * w1i + wki * w1r; + wkr = 0.5 - wkr; + i = i0; + } + xr = a[2] - a[n - 2]; + xi = a[3] + a[n - 1]; + yr = wdr * xr - wdi * xi; + yi = wdr * xi + wdi * xr; + a[2] -= yr; + a[3] -= yi; + a[n - 2] += yr; + a[n - 1] -= yi; +} + + + +void M_rftbsub(int n, double *a) +{ + int i, i0, j, k; + double ec, w1r, w1i, wkr, wki, wdr, wdi, ss, xr, xi, yr, yi; + + ec = 2 * MM_PI_2 / n; + wkr = 0; + wki = 0; + wdi = cos(ec); + wdr = sin(ec); + wdi *= wdr; + wdr *= wdr; + w1r = 1 - 2 * wdr; + w1i = 2 * wdi; + ss = 2 * w1i; + i = n >> 1; + a[i + 1] = -a[i + 1]; + while (1) { + i0 = i - 4 * RDFT_LOOP_DIV; + if (i0 < 4) { + i0 = 4; + } + for (j = i - 4; j >= i0; j -= 4) { + k = n - j; + xr = a[j + 2] - a[k - 2]; + xi = a[j + 3] + a[k - 1]; + yr = wdr * xr + wdi * xi; + yi = wdr * xi - wdi * xr; + a[j + 2] -= yr; + a[j + 3] = yi - a[j + 3]; + a[k - 2] += yr; + a[k - 1] = yi - a[k - 1]; + wkr += ss * wdi; + wki += ss * (0.5 - wdr); + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] = yi - a[j + 1]; + a[k] += yr; + a[k + 1] = yi - a[k + 1]; + wdr += ss * wki; + wdi += ss * (0.5 - wkr); + } + if (i0 == 4) { + break; + } + wkr = 0.5 * sin(ec * i0); + wki = 0.5 * cos(ec * i0); + wdr = 0.5 - (wkr * w1r - wki * w1i); + wdi = wkr * w1i + wki * w1r; + wkr = 0.5 - wkr; + i = i0; + } + xr = a[2] - a[n - 2]; + xi = a[3] + a[n - 1]; + yr = wdr * xr + wdi * xi; + yi = wdr * xi - wdi * xr; + a[2] -= yr; + a[3] = yi - a[3]; + a[n - 2] += yr; + a[n - 1] = yi - a[n - 1]; + a[1] = -a[1]; +} + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_flr.c b/src/apps/deskcalc/mapm_4.9.5/mapm_flr.c new file mode 100644 index 0000000000..ac6c3f0715 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_flr.c @@ -0,0 +1,132 @@ + +/* + * M_APM - mapm_flr.c + * + * Copyright (C) 2001 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_flr.c,v 1.4 2007/12/03 01:39:12 mike Exp $ + * + * This file contains the floor and ceil functions + * + * $Log: mapm_flr.c,v $ + * Revision 1.4 2007/12/03 01:39:12 mike + * Update license + * + * Revision 1.3 2002/11/05 23:25:30 mike + * use new set_to_zero function instead of copy + * + * Revision 1.2 2002/11/03 21:47:43 mike + * Updated function parameters to use the modern style + * + * Revision 1.1 2001/03/25 20:53:29 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/* + * input floor ceil + * ----- ------ ------ + * 329.0 329.0 329.0 + * -837.0 -837.0 -837.0 + * 372.64 372.0 373.0 + * -237.52 -238.0 -237.0 + */ + +/****************************************************************************/ +/* + * return the nearest integer <= input + */ +void m_apm_floor(M_APM bb, M_APM aa) +{ +M_APM mtmp; + +m_apm_copy(bb, aa); + +if (m_apm_is_integer(bb)) /* if integer, we're done */ + return; + +if (bb->m_apm_exponent <= 0) /* if |bb| < 1, result is -1 or 0 */ + { + if (bb->m_apm_sign < 0) + m_apm_negate(bb, MM_One); + else + M_set_to_zero(bb); + + return; + } + +if (bb->m_apm_sign < 0) + { + mtmp = M_get_stack_var(); + m_apm_negate(mtmp, bb); + + mtmp->m_apm_datalength = mtmp->m_apm_exponent; + M_apm_normalize(mtmp); + + m_apm_add(bb, mtmp, MM_One); + bb->m_apm_sign = -1; + M_restore_stack(1); + } +else + { + bb->m_apm_datalength = bb->m_apm_exponent; + M_apm_normalize(bb); + } +} +/****************************************************************************/ +/* + * return the nearest integer >= input + */ +void m_apm_ceil(M_APM bb, M_APM aa) +{ +M_APM mtmp; + +m_apm_copy(bb, aa); + +if (m_apm_is_integer(bb)) /* if integer, we're done */ + return; + +if (bb->m_apm_exponent <= 0) /* if |bb| < 1, result is 0 or 1 */ + { + if (bb->m_apm_sign < 0) + M_set_to_zero(bb); + else + m_apm_copy(bb, MM_One); + + return; + } + +if (bb->m_apm_sign < 0) + { + bb->m_apm_datalength = bb->m_apm_exponent; + M_apm_normalize(bb); + } +else + { + mtmp = M_get_stack_var(); + m_apm_copy(mtmp, bb); + + mtmp->m_apm_datalength = mtmp->m_apm_exponent; + M_apm_normalize(mtmp); + + m_apm_add(bb, mtmp, MM_One); + M_restore_stack(1); + } +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_fpf.c b/src/apps/deskcalc/mapm_4.9.5/mapm_fpf.c new file mode 100644 index 0000000000..4aab157dc3 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_fpf.c @@ -0,0 +1,444 @@ + +/* + * M_APM - mapm_fpf.c + * + * Copyright (C) 2001 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_fpf.c,v 1.10 2007/12/03 01:39:57 mike Exp $ + * + * This file contains the Fixed Point Formatting functions + * + * $Log: mapm_fpf.c,v $ + * Revision 1.10 2007/12/03 01:39:57 mike + * Update license + * + * Revision 1.9 2003/07/21 20:15:12 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.8 2003/03/31 22:11:14 mike + * call generic error handling function + * + * Revision 1.7 2002/11/05 23:31:00 mike + * use new set_to_zero call instead of copy + * + * Revision 1.6 2002/11/03 22:33:24 mike + * Updated function parameters to use the modern style + * + * Revision 1.5 2002/02/14 19:31:44 mike + * eliminate need for conditional compile + * + * Revision 1.4 2001/08/26 22:35:50 mike + * no LCC conditional needed on fixpt_string + * + * Revision 1.3 2001/08/26 22:11:10 mike + * add new 'stringexp' function + * + * Revision 1.2 2001/08/25 22:30:09 mike + * fix LCC-WIN32 compile problem + * + * Revision 1.1 2001/08/25 16:50:59 mike + * Initial revision + */ + +#include "m_apm_lc.h" +#include + +/****************************************************************************/ +char *m_apm_to_fixpt_stringexp(int dplaces, M_APM atmp, + char ch_radx, char ch_sep, int ct_sep) +{ +int places, xp, dl, ii; +char *cpr; + +places = dplaces; + +dl = atmp->m_apm_datalength; +xp = atmp->m_apm_exponent; + +if (places < 0) /* show ALL digits */ + { + if (xp < 0) + ii = dl - xp; + else + { + if (dl > xp) + ii = dl; + else + ii = xp; + } + } +else + { + ii = places; + + if (xp > 0) + ii += xp; + } + +if (ct_sep != 0 && ch_sep != 0 && xp > 0) + ii += xp / ct_sep; + +if ((cpr = (char *)MAPM_MALLOC((ii + 32) * sizeof(char))) == NULL) + return(NULL); + +m_apm_to_fixpt_stringex(cpr,places,atmp,ch_radx,ch_sep,ct_sep); + +return(cpr); +} +/****************************************************************************/ +void m_apm_to_fixpt_stringex(char *s, int dplaces, M_APM atmp, + char ch_radix, char ch_sep, int count_sep) +{ +M_APM btmp; +char ch, *cpd, *cps; +int ii, jj, kk, ct, dl, xp, no_sep_flg, places; + +btmp = M_get_stack_var(); +places = dplaces; +cpd = s; +no_sep_flg = FALSE; + +m_apm_absolute_value(btmp, atmp); /* do conversion of positive number */ + +if (ch_sep == 0 || count_sep == 0) /* no separator char OR count */ + no_sep_flg = TRUE; + +/* determine how much memory to get for the temp string */ + +dl = btmp->m_apm_datalength; +xp = btmp->m_apm_exponent; + +if (places < 0) /* show ALL digits */ + { + if (xp < 0) + ii = dl - xp; + else + { + if (dl > xp) + ii = dl; + else + ii = xp; + } + } +else + { + ii = places; + + if (xp > 0) + ii += xp; + } + +if ((cps = (char *)MAPM_MALLOC((ii + 32) * sizeof(char))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, + "\'m_apm_to_fixpt_stringex\', Out of memory"); + } + +m_apm_to_fixpt_string(cps, places, btmp); + +/* + * the converted string may be all 'zero', 0.0000... + * if so and the original number is negative, + * do NOT set the '-' sign of our output string. + */ + +if (atmp->m_apm_sign == -1) /* if input number negative */ + { + kk = 0; + jj = 0; + + while (TRUE) + { + ch = cps[kk++]; + if ((ch == '\0') || (jj != 0)) + break; + + if (isdigit((int)ch)) + { + if (ch != '0') + jj = 1; + } + } + + if (jj) + *cpd++ = '-'; + } + +ct = M_strposition(cps, "."); /* find the default (.) radix char */ + +if (ct == -1) /* if not found .. */ + { + strcat(cps, "."); /* add one */ + ct = M_strposition(cps, "."); /* and then find it */ + } + +if (places == 0) /* int format, terminate at radix char */ + cps[ct] = '\0'; +else + cps[ct] = ch_radix; /* assign the radix char */ + +/* + * if the number is small enough to not have any separator char's ... + */ + +if (ct <= count_sep) + no_sep_flg = TRUE; + +if (no_sep_flg) + { + strcpy(cpd, cps); + } +else + { + jj = 0; + kk = count_sep; + ii = ct / count_sep; + + if ((ii = ct - ii * count_sep) == 0) + ii = count_sep; + + while (TRUE) /* write out the first 1,2 */ + { /* (up to count_sep) digits */ + *cpd++ = cps[jj++]; + + if (--ii == 0) + break; + } + + while (TRUE) /* write rest of the string */ + { + if (kk == count_sep) /* write a new separator char */ + { + if (jj != ct) /* unless we're at the radix */ + { + *cpd++ = ch_sep; /* note that this also disables */ + kk = 0; /* the separator char AFTER */ + } /* the radix char */ + } + + if ((*cpd++ = cps[jj++]) == '\0') + break; + + kk++; + } + } + +MAPM_FREE(cps); +M_restore_stack(1); +} +/****************************************************************************/ +void m_apm_to_fixpt_string(char *ss, int dplaces, M_APM mtmp) +{ +M_APM ctmp; +void *vp; +int places, i2, ii, jj, kk, xp, dl, numb; +UCHAR *ucp, numdiv, numrem; +char *cpw, *cpd, sbuf[128]; + +ctmp = M_get_stack_var(); +vp = NULL; +cpd = ss; +places = dplaces; + +/* just want integer portion if places == 0 */ + +if (places == 0) + { + if (mtmp->m_apm_sign >= 0) + m_apm_add(ctmp, mtmp, MM_0_5); + else + m_apm_subtract(ctmp, mtmp, MM_0_5); + + m_apm_to_integer_string(cpd, ctmp); + + M_restore_stack(1); + return; + } + +if (places > 0) + M_apm_round_fixpt(ctmp, places, mtmp); +else + m_apm_copy(ctmp, mtmp); /* show ALL digits */ + +if (ctmp->m_apm_sign == 0) /* result is 0 */ + { + if (places < 0) + { + cpd[0] = '0'; /* "0.0" */ + cpd[1] = '.'; + cpd[2] = '0'; + cpd[3] = '\0'; + } + else + { + memset(cpd, '0', (places + 2)); /* pre-load string with all '0' */ + cpd[1] = '.'; + cpd[places + 2] = '\0'; + } + + M_restore_stack(1); + return; + } + +xp = ctmp->m_apm_exponent; +dl = ctmp->m_apm_datalength; +numb = (dl + 1) >> 1; + +if (places < 0) + { + if (dl > xp) + jj = dl + 16; + else + jj = xp + 16; + } +else + { + jj = places + 16; + + if (xp > 0) + jj += xp; + } + +if (jj > 112) + { + if ((vp = (void *)MAPM_MALLOC((jj + 16) * sizeof(char))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, + "\'m_apm_to_fixpt_string\', Out of memory"); + } + + cpw = (char *)vp; + } +else + { + cpw = sbuf; + } + +/* + * at this point, the number is non-zero and the the output + * string will contain at least 1 significant digit. + */ + +if (ctmp->m_apm_sign == -1) /* negative number */ + { + *cpd++ = '-'; + } + +ucp = ctmp->m_apm_data; +ii = 0; + +/* convert MAPM num to ASCII digits and store in working char array */ + +while (TRUE) + { + M_get_div_rem_10((int)(*ucp++), &numdiv, &numrem); + + cpw[ii++] = numdiv + '0'; + cpw[ii++] = numrem + '0'; + + if (--numb == 0) + break; + } + +i2 = ii; /* save for later */ + +if (places < 0) /* show ALL digits */ + { + places = dl - xp; + + if (places < 1) + places = 1; + } + +/* pad with trailing zeros if needed */ + +kk = xp + places + 2 - ii; + +if (kk > 0) + memset(&cpw[ii], '0', kk); + +if (xp > 0) /* |num| >= 1, NO lead-in "0.nnn" */ + { + ii = xp + places + 1; + jj = 0; + + for (kk=0; kk < ii; kk++) + { + if (kk == xp) + cpd[jj++] = '.'; + + cpd[jj++] = cpw[kk]; + } + + cpd[ii] = '\0'; + } +else /* |num| < 1, have lead-in "0.nnn" */ + { + jj = 2 - xp; + ii = 2 + places; + memset(cpd, '0', (ii + 1)); /* pre-load string with all '0' */ + cpd[1] = '.'; /* assign decimal point */ + + for (kk=0; kk < i2; kk++) + { + cpd[jj++] = cpw[kk]; + } + + cpd[ii] = '\0'; + } + +if (vp != NULL) + MAPM_FREE(vp); + +M_restore_stack(1); +} +/****************************************************************************/ +void M_apm_round_fixpt(M_APM btmp, int places, M_APM atmp) +{ +int xp, ii; + +xp = atmp->m_apm_exponent; +ii = xp + places - 1; + +M_set_to_zero(btmp); /* assume number is too small so the net result is 0 */ + +if (ii >= 0) + { + m_apm_round(btmp, ii, atmp); + } +else + { + if (ii == -1) /* next digit is significant which may round up */ + { + if (atmp->m_apm_data[0] >= 50) /* digit >= 5, round up */ + { + m_apm_copy(btmp, atmp); + btmp->m_apm_data[0] = 10; + btmp->m_apm_exponent += 1; + btmp->m_apm_datalength = 1; + M_apm_normalize(btmp); + } + } + } +} +/****************************************************************************/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_gcd.c b/src/apps/deskcalc/mapm_4.9.5/mapm_gcd.c new file mode 100644 index 0000000000..0c3914b42f --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_gcd.c @@ -0,0 +1,284 @@ + +/* + * M_APM - mapm_gcd.c + * + * Copyright (C) 2001 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_gcd.c,v 1.8 2007/12/03 01:41:05 mike Exp $ + * + * This file contains the GCD and LCM functions + * + * $Log: mapm_gcd.c,v $ + * Revision 1.8 2007/12/03 01:41:05 mike + * Update license + * + * Revision 1.7 2003/07/21 20:16:43 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.6 2003/03/31 22:12:33 mike + * call generic error handling function + * + * Revision 1.5 2002/11/03 22:44:21 mike + * Updated function parameters to use the modern style + * + * Revision 1.4 2002/05/17 22:17:47 mike + * fix comment + * + * Revision 1.3 2002/05/17 22:16:36 mike + * move even/odd util functions to mapmutl2 + * + * Revision 1.2 2001/07/15 20:55:20 mike + * add comments + * + * Revision 1.1 2001/07/15 20:48:27 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + * From Knuth, The Art of Computer Programming: + * + * This is the binary GCD algorithm as described + * in the book (Algorithm B) + */ +void m_apm_gcd(M_APM r, M_APM u, M_APM v) +{ +M_APM tmpM, tmpN, tmpT, tmpU, tmpV; +int kk, kr, mm; +long pow_2; + +/* 'is_integer' will return 0 || 1 */ + +if ((m_apm_is_integer(u) + m_apm_is_integer(v)) != 2) + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_gcd\', Non-integer input"); + + M_set_to_zero(r); + return; + } + +if (u->m_apm_sign == 0) + { + m_apm_absolute_value(r, v); + return; + } + +if (v->m_apm_sign == 0) + { + m_apm_absolute_value(r, u); + return; + } + +tmpM = M_get_stack_var(); +tmpN = M_get_stack_var(); +tmpT = M_get_stack_var(); +tmpU = M_get_stack_var(); +tmpV = M_get_stack_var(); + +m_apm_absolute_value(tmpU, u); +m_apm_absolute_value(tmpV, v); + +/* Step B1 */ + +kk = 0; + +while (TRUE) + { + mm = 1; + if (m_apm_is_odd(tmpU)) + break; + + mm = 0; + if (m_apm_is_odd(tmpV)) + break; + + m_apm_multiply(tmpN, MM_0_5, tmpU); + m_apm_copy(tmpU, tmpN); + + m_apm_multiply(tmpN, MM_0_5, tmpV); + m_apm_copy(tmpV, tmpN); + + kk++; + } + +/* Step B2 */ + +if (mm) + { + m_apm_negate(tmpT, tmpV); + goto B4; + } + +m_apm_copy(tmpT, tmpU); + +/* Step: */ + +B3: + +m_apm_multiply(tmpN, MM_0_5, tmpT); +m_apm_copy(tmpT, tmpN); + +/* Step: */ + +B4: + +if (m_apm_is_even(tmpT)) + goto B3; + +/* Step B5 */ + +if (tmpT->m_apm_sign == 1) + m_apm_copy(tmpU, tmpT); +else + m_apm_negate(tmpV, tmpT); + +/* Step B6 */ + +m_apm_subtract(tmpT, tmpU, tmpV); + +if (tmpT->m_apm_sign != 0) + goto B3; + +/* + * result = U * 2 ^ kk + */ + +if (kk == 0) + m_apm_copy(r, tmpU); +else + { + if (kk == 1) + m_apm_multiply(r, tmpU, MM_Two); + + if (kk == 2) + m_apm_multiply(r, tmpU, MM_Four); + + if (kk >= 3) + { + mm = kk / 28; + kr = kk % 28; + pow_2 = 1L << kr; + + if (mm == 0) + { + m_apm_set_long(tmpN, pow_2); + m_apm_multiply(r, tmpU, tmpN); + } + else + { + m_apm_copy(tmpN, MM_One); + m_apm_set_long(tmpM, 0x10000000L); /* 2 ^ 28 */ + + while (TRUE) + { + m_apm_multiply(tmpT, tmpN, tmpM); + m_apm_copy(tmpN, tmpT); + + if (--mm == 0) + break; + } + + if (kr == 0) + { + m_apm_multiply(r, tmpU, tmpN); + } + else + { + m_apm_set_long(tmpM, pow_2); + m_apm_multiply(tmpT, tmpN, tmpM); + m_apm_multiply(r, tmpU, tmpT); + } + } + } + } + +M_restore_stack(5); +} +/****************************************************************************/ +/* + * u * v + * LCM(u,v) = ------------ + * GCD(u,v) + */ + +void m_apm_lcm(M_APM r, M_APM u, M_APM v) +{ +M_APM tmpN, tmpG; + +tmpN = M_get_stack_var(); +tmpG = M_get_stack_var(); + +m_apm_multiply(tmpN, u, v); +m_apm_gcd(tmpG, u, v); +m_apm_integer_divide(r, tmpN, tmpG); + +M_restore_stack(2); +} +/****************************************************************************/ + +#ifdef BIG_COMMENT_BLOCK + +/* + * traditional GCD included for reference + * (also useful for testing ...) + */ + +/* + * From Knuth, The Art of Computer Programming: + * + * To compute GCD(u,v) + * + * A1: + * if (v == 0) return (u) + * A2: + * t = u mod v + * u = v + * v = t + * goto A1 + */ +void m_apm_gcd_traditional(M_APM r, M_APM u, M_APM v) +{ +M_APM tmpD, tmpN, tmpU, tmpV; + +tmpD = M_get_stack_var(); +tmpN = M_get_stack_var(); +tmpU = M_get_stack_var(); +tmpV = M_get_stack_var(); + +m_apm_absolute_value(tmpU, u); +m_apm_absolute_value(tmpV, v); + +while (TRUE) + { + if (tmpV->m_apm_sign == 0) + break; + + m_apm_integer_div_rem(tmpD, tmpN, tmpU, tmpV); + m_apm_copy(tmpU, tmpV); + m_apm_copy(tmpV, tmpN); + } + +m_apm_copy(r, tmpU); +M_restore_stack(4); +} +/****************************************************************************/ + +#endif + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_lg2.c b/src/apps/deskcalc/mapm_4.9.5/mapm_lg2.c new file mode 100644 index 0000000000..dc8eee2cc9 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_lg2.c @@ -0,0 +1,180 @@ + +/* + * M_APM - mapm_lg2.c + * + * Copyright (C) 2003 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_lg2.c,v 1.9 2007/12/03 01:42:06 mike Exp $ + * + * This file contains the iterative function to compute the LOG + * This is an internal function to the library and is not intended + * to be called directly by the user. + * + * $Log: mapm_lg2.c,v $ + * Revision 1.9 2007/12/03 01:42:06 mike + * Update license + * + * Revision 1.8 2003/05/12 17:52:15 mike + * rearrange some logic + * + * Revision 1.7 2003/05/03 11:24:51 mike + * optimize decimal places + * + * Revision 1.6 2003/05/01 21:58:27 mike + * remove math.h + * + * Revision 1.5 2003/05/01 20:53:38 mike + * implement a new algorithm for log + * + * Revision 1.4 2003/04/09 20:21:29 mike + * fix rare corner condition by intentionally inducing a + * 10 ^ -5 error in the initial guess. + * + * Revision 1.3 2003/03/31 22:13:15 mike + * call generic error handling function + * + * Revision 1.2 2003/03/30 21:27:22 mike + * add comments + * + * Revision 1.1 2003/03/30 21:18:07 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ + +/* + * compute rr = log(nn) + * + * input is assumed to not exceed the exponent range of a normal + * 'C' double ( |exponent| must be < 308) + */ + +/****************************************************************************/ +void M_log_solve_cubic(M_APM rr, int places, M_APM nn) +{ +M_APM tmp0, tmp1, tmp2, tmp3, guess; +int ii, maxp, tolerance, local_precision; + +guess = M_get_stack_var(); +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); + +M_get_log_guess(guess, nn); + +tolerance = -(places + 4); +maxp = places + 16; +local_precision = 18; + +/* Use the following iteration to solve for log : + + exp(X) - N + X = X - 2 * ------------ + n+1 exp(X) + N + + + this is a cubically convergent algorithm + (each iteration yields 3X more digits) +*/ + +ii = 0; + +while (TRUE) + { + m_apm_exp(tmp1, local_precision, guess); + + m_apm_subtract(tmp3, tmp1, nn); + m_apm_add(tmp2, tmp1, nn); + + m_apm_divide(tmp1, local_precision, tmp3, tmp2); + m_apm_multiply(tmp0, MM_Two, tmp1); + m_apm_subtract(tmp3, guess, tmp0); + + if (ii != 0) + { + if (((3 * tmp0->m_apm_exponent) < tolerance) || (tmp0->m_apm_sign == 0)) + break; + } + + m_apm_round(guess, local_precision, tmp3); + + local_precision *= 3; + + if (local_precision > maxp) + local_precision = maxp; + + ii = 1; + } + +m_apm_round(rr, places, tmp3); +M_restore_stack(5); +} +/****************************************************************************/ +/* + * find log(N) + * + * if places < 360 + * solve with cubically convergent algorithm above + * + * else + * + * let 'X' be 'close' to the solution (we use ~110 decimal places) + * + * let Y = N * exp(-X) - 1 + * + * then + * + * log(N) = X + log(1 + Y) + * + * since 'Y' will be small, we can use the efficient log_near_1 algorithm. + * + */ +void M_log_basic_iteration(M_APM rr, int places, M_APM nn) +{ +M_APM tmp0, tmp1, tmp2, tmpX; + +if (places < 360) + { + M_log_solve_cubic(rr, places, nn); + } +else + { + tmp0 = M_get_stack_var(); + tmp1 = M_get_stack_var(); + tmp2 = M_get_stack_var(); + tmpX = M_get_stack_var(); + + M_log_solve_cubic(tmpX, 110, nn); + + m_apm_negate(tmp0, tmpX); + m_apm_exp(tmp1, (places + 8), tmp0); + m_apm_multiply(tmp2, tmp1, nn); + m_apm_subtract(tmp1, tmp2, MM_One); + + M_log_near_1(tmp0, (places - 104), tmp1); + + m_apm_add(tmp1, tmpX, tmp0); + m_apm_round(rr, places, tmp1); + + M_restore_stack(4); + } +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_lg3.c b/src/apps/deskcalc/mapm_4.9.5/mapm_lg3.c new file mode 100644 index 0000000000..6b83da5bfc --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_lg3.c @@ -0,0 +1,226 @@ + +/* + * M_APM - mapm_lg3.c + * + * Copyright (C) 2003 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_lg3.c,v 1.7 2007/12/03 01:42:59 mike Exp $ + * + * This file contains the function to compute log(2), log(10), + * and 1/log(10) to the desired precision using an AGM algorithm. + * + * $Log: mapm_lg3.c,v $ + * Revision 1.7 2007/12/03 01:42:59 mike + * Update license + * + * Revision 1.6 2003/12/09 01:25:06 mike + * actually compute the first term of the AGM iteration instead + * of assuming the inputs a=1 and b=10^-N. + * + * Revision 1.5 2003/12/04 03:19:16 mike + * rearrange logic in AGM to be more straight-forward + * + * Revision 1.4 2003/05/01 22:04:37 mike + * rearrange some code + * + * Revision 1.3 2003/05/01 21:58:31 mike + * remove math.h + * + * Revision 1.2 2003/03/30 22:14:58 mike + * add comments + * + * Revision 1.1 2003/03/30 21:18:04 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/* + * using the 'R' function (defined below) for 'N' decimal places : + * + * + * -N -N + * log(2) = R(1, 0.5 * 10 ) - R(1, 10 ) + * + * + * -N -N + * log(10) = R(1, 0.1 * 10 ) - R(1, 10 ) + * + * + * In general: + * + * -N -N + * log(x) = R(1, 10 / x) - R(1, 10 ) + * + * + * I found this on a web site which went into considerable detail + * on the history of log(2). This formula is algebraically identical + * to the formula specified in J. Borwein and P. Borwein's book + * "PI and the AGM". (reference algorithm 7.2) + */ + +/****************************************************************************/ +/* + * check if our local copy of log(2) & log(10) is precise + * enough for our purpose. if not, calculate them so it's + * as precise as desired, accurate to at least 'places'. + */ +void M_check_log_places(int places) +{ +M_APM tmp6, tmp7, tmp8, tmp9; +int dplaces; + +dplaces = places + 4; + +if (dplaces > MM_lc_log_digits) + { + MM_lc_log_digits = dplaces + 4; + + tmp6 = M_get_stack_var(); + tmp7 = M_get_stack_var(); + tmp8 = M_get_stack_var(); + tmp9 = M_get_stack_var(); + + dplaces += 6 + (int)log10((double)places); + + m_apm_copy(tmp7, MM_One); + tmp7->m_apm_exponent = -places; + + M_log_AGM_R_func(tmp8, dplaces, MM_One, tmp7); + + m_apm_multiply(tmp6, tmp7, MM_0_5); + + M_log_AGM_R_func(tmp9, dplaces, MM_One, tmp6); + + m_apm_subtract(MM_lc_log2, tmp9, tmp8); /* log(2) */ + + tmp7->m_apm_exponent -= 1; /* divide by 10 */ + + M_log_AGM_R_func(tmp9, dplaces, MM_One, tmp7); + + m_apm_subtract(MM_lc_log10, tmp9, tmp8); /* log(10) */ + m_apm_reciprocal(MM_lc_log10R, dplaces, MM_lc_log10); /* 1 / log(10) */ + + M_restore_stack(4); + } +} +/****************************************************************************/ + +/* + * define a notation for a function 'R' : + * + * + * + * 1 + * R (a0, b0) = ------------------------------ + * + * ---- + * \ + * \ n-1 2 2 + * 1 - | 2 * (a - b ) + * / n n + * / + * ---- + * n >= 0 + * + * + * where a, b are the classic AGM iteration : + * + * + * a = 0.5 * (a + b ) + * n+1 n n + * + * + * b = sqrt(a * b ) + * n+1 n n + * + * + * + * define a variable 'c' for more efficient computation : + * + * 2 2 2 + * c = 0.5 * (a - b ) , c = a - b + * n+1 n n n n n + * + */ + +/****************************************************************************/ +void M_log_AGM_R_func(M_APM rr, int places, M_APM aa, M_APM bb) +{ +M_APM tmp1, tmp2, tmp3, tmp4, tmpC2, sum, pow_2, tmpA0, tmpB0; +int tolerance, dplaces; + +tmpA0 = M_get_stack_var(); +tmpB0 = M_get_stack_var(); +tmpC2 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); +tmp4 = M_get_stack_var(); +sum = M_get_stack_var(); +pow_2 = M_get_stack_var(); + +tolerance = places + 8; +dplaces = places + 16; + +m_apm_copy(tmpA0, aa); +m_apm_copy(tmpB0, bb); +m_apm_copy(pow_2, MM_0_5); + +m_apm_multiply(tmp1, aa, aa); /* 0.5 * [ a ^ 2 - b ^ 2 ] */ +m_apm_multiply(tmp2, bb, bb); +m_apm_subtract(tmp3, tmp1, tmp2); +m_apm_multiply(sum, MM_0_5, tmp3); + +while (TRUE) + { + m_apm_subtract(tmp1, tmpA0, tmpB0); /* C n+1 = 0.5 * [ An - Bn ] */ + m_apm_multiply(tmp4, MM_0_5, tmp1); /* C n+1 */ + m_apm_multiply(tmpC2, tmp4, tmp4); /* C n+1 ^ 2 */ + + /* do the AGM */ + + m_apm_add(tmp1, tmpA0, tmpB0); + m_apm_multiply(tmp3, MM_0_5, tmp1); + + m_apm_multiply(tmp2, tmpA0, tmpB0); + m_apm_sqrt(tmpB0, dplaces, tmp2); + + m_apm_round(tmpA0, dplaces, tmp3); + + /* end AGM */ + + m_apm_multiply(tmp2, MM_Two, pow_2); + m_apm_copy(pow_2, tmp2); + + m_apm_multiply(tmp1, tmpC2, pow_2); + m_apm_add(tmp3, sum, tmp1); + + if ((tmp1->m_apm_sign == 0) || + ((-2 * tmp1->m_apm_exponent) > tolerance)) + break; + + m_apm_round(sum, dplaces, tmp3); + } + +m_apm_subtract(tmp4, MM_One, tmp3); +m_apm_reciprocal(rr, places, tmp4); + +M_restore_stack(9); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_lg4.c b/src/apps/deskcalc/mapm_4.9.5/mapm_lg4.c new file mode 100644 index 0000000000..8b20d252e9 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_lg4.c @@ -0,0 +1,102 @@ + +/* + * M_APM - mapm_lg4.c + * + * Copyright (C) 2003 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_lg4.c,v 1.3 2007/12/03 01:43:32 mike Exp $ + * + * This file contains the LOG_NEAR_1 function. + * + * $Log: mapm_lg4.c,v $ + * Revision 1.3 2007/12/03 01:43:32 mike + * Update license + * + * Revision 1.2 2003/06/02 18:08:45 mike + * tweak decimal places and add comments + * + * Revision 1.1 2003/06/02 17:27:26 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + calculate log (1 + x) with the following series: + + x + y = ----- ( |y| < 1 ) + x + 2 + + + [ 1 + y ] y^3 y^5 y^7 + log [-------] = 2 * [ y + --- + --- + --- ... ] + [ 1 - y ] 3 5 7 + +*/ +void M_log_near_1(M_APM rr, int places, M_APM xx) +{ +M_APM tmp0, tmp1, tmp2, tmpS, term; +int tolerance, dplaces, local_precision; +long m1; + +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmpS = M_get_stack_var(); +term = M_get_stack_var(); + +tolerance = xx->m_apm_exponent - (places + 6); +dplaces = (places + 12) - xx->m_apm_exponent; + +m_apm_add(tmp0, xx, MM_Two); +m_apm_divide(tmpS, (dplaces + 6), xx, tmp0); + +m_apm_copy(term, tmpS); +m_apm_multiply(tmp0, tmpS, tmpS); +m_apm_round(tmp2, (dplaces + 6), tmp0); + +m1 = 3L; + +while (TRUE) + { + m_apm_multiply(tmp0, term, tmp2); + + if ((tmp0->m_apm_exponent < tolerance) || (tmp0->m_apm_sign == 0)) + break; + + local_precision = dplaces + tmp0->m_apm_exponent; + + if (local_precision < 20) + local_precision = 20; + + m_apm_set_long(tmp1, m1); + m_apm_round(term, local_precision, tmp0); + m_apm_divide(tmp0, local_precision, term, tmp1); + m_apm_add(tmp1, tmpS, tmp0); + m_apm_copy(tmpS, tmp1); + m1 += 2; + } + +m_apm_multiply(tmp0, MM_Two, tmpS); +m_apm_round(rr, places, tmp0); + +M_restore_stack(5); /* restore the 5 locals we used here */ +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_log.c b/src/apps/deskcalc/mapm_4.9.5/mapm_log.c new file mode 100644 index 0000000000..5df8a2baa9 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_log.c @@ -0,0 +1,229 @@ + +/* + * M_APM - mapm_log.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_log.c,v 1.29 2007/12/03 01:44:19 mike Exp $ + * + * This file contains the LOG and LOG10 functions. + * + * $Log: mapm_log.c,v $ + * Revision 1.29 2007/12/03 01:44:19 mike + * Update license + * + * Revision 1.28 2003/07/21 20:18:06 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.27 2003/06/02 17:22:46 mike + * put 'log_near_1' into it's own separate module + * + * Revision 1.26 2003/05/12 17:42:46 mike + * only check for 'near 1' if exponent is 0 or 1 + * + * Revision 1.25 2003/05/04 21:08:25 mike + * *** empty log message *** + * + * Revision 1.24 2003/05/01 21:58:34 mike + * remove math.h + * + * Revision 1.23 2003/05/01 21:39:09 mike + * use 'abs' call + * + * Revision 1.22 2003/05/01 19:44:57 mike + * optimize log_near_1 by calculating fewer digits + * on subsequent iterations + * + * Revision 1.21 2003/03/31 22:00:56 mike + * call generic error handling function + * + * Revision 1.20 2003/03/30 22:57:13 mike + * call a new iterative log function which is cubically convergent + * + * Revision 1.19 2002/11/03 22:14:45 mike + * Updated function parameters to use the modern style + * + * Revision 1.18 2001/07/16 19:21:16 mike + * add function M_free_all_log + * + * Revision 1.17 2000/10/22 00:24:29 mike + * minor optimization + * + * Revision 1.16 2000/10/21 16:22:50 mike + * use an improved log_near_1 algorithm + * + * Revision 1.15 2000/10/20 16:49:33 mike + * update algorithm for basic log function and add new + * function when input is close to '1' + * + * Revision 1.14 2000/09/23 19:48:21 mike + * change divide call to reciprocal + * + * Revision 1.13 2000/07/11 18:58:35 mike + * do it right this time + * + * Revision 1.12 2000/07/11 18:19:27 mike + * estimate a better initial precision + * + * Revision 1.11 2000/05/19 16:14:15 mike + * update some comments + * + * Revision 1.10 2000/05/17 23:47:35 mike + * recompute a local copy of log E base 10 on the fly + * if more precision is needed. + * + * Revision 1.9 2000/03/27 21:44:12 mike + * determine how many iterations should be required at + * run time for log + * + * Revision 1.8 1999/07/21 02:56:18 mike + * added some comments + * + * Revision 1.7 1999/07/19 00:28:51 mike + * adjust local precision again + * + * Revision 1.6 1999/07/19 00:10:34 mike + * adjust local precision during iterative loop + * + * Revision 1.5 1999/07/18 23:15:54 mike + * change local precision dynamically and change + * tolerance to integers for faster iterative routine. + * + * Revision 1.4 1999/06/19 21:08:32 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.3 1999/05/15 01:34:50 mike + * add check for number of decimal places + * + * Revision 1.2 1999/05/10 21:42:32 mike + * added some comments + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + Calls the LOG function. The formula used is : + + log10(x) = A * log(x) where A = log (e) [0.43429448190325...] + 10 +*/ +void m_apm_log10(M_APM rr, int places, M_APM aa) +{ +int dplaces; +M_APM tmp8, tmp9; + +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +dplaces = places + 4; +M_check_log_places(dplaces + 45); + +m_apm_log(tmp9, dplaces, aa); +m_apm_multiply(tmp8, tmp9, MM_lc_log10R); +m_apm_round(rr, places, tmp8); +M_restore_stack(2); /* restore the 2 locals we used here */ +} +/****************************************************************************/ +void m_apm_log(M_APM r, int places, M_APM a) +{ +M_APM tmp0, tmp1, tmp2; +int mexp, dplaces; + +if (a->m_apm_sign <= 0) + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_log\', Negative argument"); + M_set_to_zero(r); + return; + } + +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +dplaces = places + 8; + +/* + * if the input is real close to 1, use the series expansion + * to compute the log. + * + * 0.9999 < a < 1.0001 + */ + +mexp = a->m_apm_exponent; + +if (mexp == 0 || mexp == 1) + { + m_apm_subtract(tmp0, a, MM_One); + + if (tmp0->m_apm_sign == 0) /* is input exactly 1 ?? */ + { /* if so, result is 0 */ + M_set_to_zero(r); + M_restore_stack(3); + return; + } + + if (tmp0->m_apm_exponent <= -4) + { + M_log_near_1(r, places, tmp0); + M_restore_stack(3); + return; + } + } + +/* make sure our log(10) is accurate enough for this calculation */ +/* (and log(2) which is called from M_log_basic_iteration) */ + +M_check_log_places(dplaces + 25); + +if (abs(mexp) <= 3) + { + M_log_basic_iteration(r, places, a); + } +else + { + /* + * use log (x * y) = log(x) + log(y) + * + * here we use y = exponent of our base 10 number. + * + * let 'C' = log(10) = 2.3025850929940.... + * + * then log(x * y) = log(x) + ( C * base_10_exponent ) + */ + + m_apm_copy(tmp2, a); + + mexp = tmp2->m_apm_exponent - 2; + tmp2->m_apm_exponent = 2; /* force number between 10 & 100 */ + + M_log_basic_iteration(tmp0, dplaces, tmp2); + + m_apm_set_long(tmp1, (long)mexp); + m_apm_multiply(tmp2, tmp1, MM_lc_log10); + m_apm_add(tmp1, tmp2, tmp0); + + m_apm_round(r, places, tmp1); + } + +M_restore_stack(3); /* restore the 3 locals we used here */ +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_mul.c b/src/apps/deskcalc/mapm_4.9.5/mapm_mul.c new file mode 100644 index 0000000000..d9d52ec402 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_mul.c @@ -0,0 +1,182 @@ + +/* + * M_APM - mapm_mul.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_mul.c,v 1.16 2007/12/03 01:45:27 mike Exp $ + * + * This file contains basic multiplication function. + * + * $Log: mapm_mul.c,v $ + * Revision 1.16 2007/12/03 01:45:27 mike + * Update license + * + * Revision 1.15 2004/02/21 04:30:35 mike + * minor optimization by using pointers instead of array indexes. + * + * Revision 1.14 2003/07/21 20:18:59 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.13 2003/03/31 22:14:05 mike + * call generic error handling function + * + * Revision 1.12 2002/11/03 22:25:36 mike + * Updated function parameters to use the modern style + * + * Revision 1.11 2001/07/24 18:24:26 mike + * access div/rem lookup table directly + * for speed + * + * Revision 1.10 2001/02/11 22:31:39 mike + * modify parameters to REALLOC + * + * Revision 1.9 2000/07/09 00:20:03 mike + * change break even point again .... + * + * Revision 1.8 2000/07/08 18:51:43 mike + * change break even point between this O(n^2) + * multiply and the FFT multiply + * + * Revision 1.7 2000/04/14 16:27:45 mike + * change the break even point between the 2 multiply + * functions since we made the fast one even faster. + * + * Revision 1.6 2000/02/03 22:46:40 mike + * use MAPM_* generic memory function + * + * Revision 1.5 1999/09/19 21:10:14 mike + * change the break even point between the 2 multiply choices + * + * Revision 1.4 1999/08/09 23:57:17 mike + * added more comments + * + * Revision 1.3 1999/08/09 02:38:17 mike + * tweak break even point and add comments + * + * Revision 1.2 1999/08/08 18:35:20 mike + * add call to fast algorithm if input numbers are large + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +extern void M_fast_multiply(M_APM, M_APM, M_APM); + +/****************************************************************************/ +void m_apm_multiply(M_APM r, M_APM a, M_APM b) +{ +int ai, itmp, sign, nexp, ii, jj, indexa, indexb, index0, numdigits; +UCHAR *cp, *cpr, *cp_div, *cp_rem; +void *vp; + +sign = a->m_apm_sign * b->m_apm_sign; +nexp = a->m_apm_exponent + b->m_apm_exponent; + +if (sign == 0) /* one number is zero, result is zero */ + { + M_set_to_zero(r); + return; + } + +numdigits = a->m_apm_datalength + b->m_apm_datalength; +indexa = (a->m_apm_datalength + 1) >> 1; +indexb = (b->m_apm_datalength + 1) >> 1; + +/* + * If we are multiplying 2 'big' numbers, use the fast algorithm. + * + * This is a **very** approx break even point between this algorithm + * and the FFT multiply. Note that different CPU's, operating systems, + * and compiler's may yield a different break even point. This point + * (~96 decimal digits) is how the test came out on the author's system. + */ + +if (indexa >= 48 && indexb >= 48) + { + M_fast_multiply(r, a, b); + return; + } + +ii = (numdigits + 1) >> 1; /* required size of result, in bytes */ + +if (ii > r->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(r->m_apm_data, (ii + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'m_apm_multiply\', Out of memory"); + } + + r->m_apm_malloclength = ii + 28; + r->m_apm_data = (UCHAR *)vp; + } + +M_get_div_rem_addr(&cp_div, &cp_rem); + +index0 = indexa + indexb; +cp = r->m_apm_data; +memset(cp, 0, index0); +ii = indexa; + +while (TRUE) + { + index0--; + cpr = cp + index0; + jj = indexb; + ai = (int)a->m_apm_data[--ii]; + + while (TRUE) + { + itmp = ai * b->m_apm_data[--jj]; + + *(cpr-1) += cp_div[itmp]; + *cpr += cp_rem[itmp]; + + if (*cpr >= 100) + { + *cpr -= 100; + *(cpr-1) += 1; + } + + cpr--; + + if (*cpr >= 100) + { + *cpr -= 100; + *(cpr-1) += 1; + } + + if (jj == 0) + break; + } + + if (ii == 0) + break; + } + +r->m_apm_sign = sign; +r->m_apm_exponent = nexp; +r->m_apm_datalength = numdigits; + +M_apm_normalize(r); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_pow.c b/src/apps/deskcalc/mapm_4.9.5/mapm_pow.c new file mode 100644 index 0000000000..0047b4941d --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_pow.c @@ -0,0 +1,178 @@ + +/* + * M_APM - mapm_pow.c + * + * Copyright (C) 2000 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_pow.c,v 1.10 2007/12/03 01:46:07 mike Exp $ + * + * This file contains the POW function. + * + * $Log: mapm_pow.c,v $ + * Revision 1.10 2007/12/03 01:46:07 mike + * Update license + * + * Revision 1.9 2002/11/05 23:39:42 mike + * use new set_to_zero call + * + * Revision 1.8 2002/11/03 22:20:59 mike + * Updated function parameters to use the modern style + * + * Revision 1.7 2001/07/16 19:24:26 mike + * add function M_free_all_pow + * + * Revision 1.6 2000/09/05 22:15:03 mike + * minor tweak + * + * Revision 1.5 2000/08/22 21:22:29 mike + * if parameter yy is an integer, call the more + * efficient _integer_pow function + * + * Revision 1.4 2000/08/22 20:42:08 mike + * compute more digits in the log calculation + * + * Revision 1.3 2000/05/24 20:08:21 mike + * update some comments + * + * Revision 1.2 2000/05/23 23:20:11 mike + * return 1 when input is 0^0. + * + * Revision 1.1 2000/05/18 22:10:43 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static M_APM M_last_xx_input; +static M_APM M_last_xx_log; +static int M_last_log_digits; +static int M_size_flag = 0; + +/****************************************************************************/ +void M_free_all_pow() +{ +if (M_size_flag != 0) + { + m_apm_free(M_last_xx_input); + m_apm_free(M_last_xx_log); + M_size_flag = 0; + } +} +/****************************************************************************/ +/* + Calculate the POW function by calling EXP : + + Y A + X = e where A = Y * log(X) +*/ +void m_apm_pow(M_APM rr, int places, M_APM xx, M_APM yy) +{ +int iflag, pflag; +char sbuf[64]; +M_APM tmp8, tmp9; + +/* if yy == 0, return 1 */ + +if (yy->m_apm_sign == 0) + { + m_apm_copy(rr, MM_One); + return; + } + +/* if xx == 0, return 0 */ + +if (xx->m_apm_sign == 0) + { + M_set_to_zero(rr); + return; + } + +if (M_size_flag == 0) /* init locals on first call */ + { + M_size_flag = M_get_sizeof_int(); + M_last_log_digits = 0; + M_last_xx_input = m_apm_init(); + M_last_xx_log = m_apm_init(); + } + +/* + * if 'yy' is a small enough integer, call the more + * efficient _integer_pow function. + */ + +if (m_apm_is_integer(yy)) + { + iflag = FALSE; + + if (M_size_flag == 2) /* 16 bit compilers */ + { + if (yy->m_apm_exponent <= 4) + iflag = TRUE; + } + else /* >= 32 bit compilers */ + { + if (yy->m_apm_exponent <= 7) + iflag = TRUE; + } + + if (iflag) + { + m_apm_to_integer_string(sbuf, yy); + m_apm_integer_pow(rr, places, xx, atoi(sbuf)); + return; + } + } + +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +/* + * If parameter 'X' is the same this call as it + * was the previous call, re-use the saved log + * calculation from last time. + */ + +pflag = FALSE; + +if (M_last_log_digits >= places) + { + if (m_apm_compare(xx, M_last_xx_input) == 0) + pflag = TRUE; + } + +if (pflag) + { + m_apm_round(tmp9, (places + 8), M_last_xx_log); + } +else + { + m_apm_log(tmp9, (places + 8), xx); + + M_last_log_digits = places + 2; + + /* save the 'X' input value and the log calculation */ + + m_apm_copy(M_last_xx_input, xx); + m_apm_copy(M_last_xx_log, tmp9); + } + +m_apm_multiply(tmp8, tmp9, yy); +m_apm_exp(rr, places, tmp8); +M_restore_stack(2); /* restore the 2 locals we used here */ +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_rcp.c b/src/apps/deskcalc/mapm_4.9.5/mapm_rcp.c new file mode 100644 index 0000000000..59a36a1c7e --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_rcp.c @@ -0,0 +1,189 @@ + +/* + * M_APM - mapm_rcp.c + * + * Copyright (C) 2000 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_rcp.c,v 1.7 2007/12/03 01:46:46 mike Exp $ + * + * This file contains the fast division and reciprocal functions + * + * $Log: mapm_rcp.c,v $ + * Revision 1.7 2007/12/03 01:46:46 mike + * Update license + * + * Revision 1.6 2003/07/21 20:20:17 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.5 2003/05/01 21:58:40 mike + * remove math.h + * + * Revision 1.4 2003/03/31 22:15:49 mike + * call generic error handling function + * + * Revision 1.3 2002/11/03 21:32:09 mike + * Updated function parameters to use the modern style + * + * Revision 1.2 2000/09/26 16:27:48 mike + * add some comments + * + * Revision 1.1 2000/09/26 16:16:00 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_divide(M_APM rr, int places, M_APM aa, M_APM bb) +{ +M_APM tmp0, tmp1; +int sn, nexp, dplaces; + +sn = aa->m_apm_sign * bb->m_apm_sign; + +if (sn == 0) /* one number is zero, result is zero */ + { + if (bb->m_apm_sign == 0) + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_divide\', Divide by 0"); + } + + M_set_to_zero(rr); + return; + } + +/* + * Use the original 'Knuth' method for smaller divides. On the + * author's system, this was the *approx* break even point before + * the reciprocal method used below became faster. + */ + +if (places < 250) + { + M_apm_sdivide(rr, places, aa, bb); + return; + } + +/* mimic the decimal place behavior of the original divide */ + +nexp = aa->m_apm_exponent - bb->m_apm_exponent; + +if (nexp > 0) + dplaces = nexp + places; +else + dplaces = places; + +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); + +m_apm_reciprocal(tmp0, (dplaces + 8), bb); +m_apm_multiply(tmp1, tmp0, aa); +m_apm_round(rr, dplaces, tmp1); + +M_restore_stack(2); +} +/****************************************************************************/ +void m_apm_reciprocal(M_APM rr, int places, M_APM aa) +{ +M_APM last_x, guess, tmpN, tmp1, tmp2; +char sbuf[32]; +int ii, bflag, dplaces, nexp, tolerance; + +if (aa->m_apm_sign == 0) + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_reciprocal\', Input = 0"); + + M_set_to_zero(rr); + return; + } + +last_x = M_get_stack_var(); +guess = M_get_stack_var(); +tmpN = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +m_apm_absolute_value(tmpN, aa); + +/* + normalize the input number (make the exponent 0) so + the 'guess' below will not over/under flow on large + magnitude exponents. +*/ + +nexp = aa->m_apm_exponent; +tmpN->m_apm_exponent -= nexp; + +m_apm_to_string(sbuf, 15, tmpN); +m_apm_set_double(guess, (1.0 / atof(sbuf))); + +tolerance = places + 4; +dplaces = places + 16; +bflag = FALSE; + +m_apm_negate(last_x, MM_Ten); + +/* Use the following iteration to calculate the reciprocal : + + + X = X * [ 2 - N * X ] + n+1 +*/ + +ii = 0; + +while (TRUE) + { + m_apm_multiply(tmp1, tmpN, guess); + m_apm_subtract(tmp2, MM_Two, tmp1); + m_apm_multiply(tmp1, tmp2, guess); + + if (bflag) + break; + + m_apm_round(guess, dplaces, tmp1); + + /* force at least 2 iterations so 'last_x' has valid data */ + + if (ii != 0) + { + m_apm_subtract(tmp2, guess, last_x); + + if (tmp2->m_apm_sign == 0) + break; + + /* + * if we are within a factor of 4 on the error term, + * we will be accurate enough after the *next* iteration + * is complete. + */ + + if ((-4 * tmp2->m_apm_exponent) > tolerance) + bflag = TRUE; + } + + m_apm_copy(last_x, guess); + ii++; + } + +m_apm_round(rr, places, tmp1); +rr->m_apm_exponent -= nexp; +rr->m_apm_sign = aa->m_apm_sign; +M_restore_stack(5); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_rnd.c b/src/apps/deskcalc/mapm_4.9.5/mapm_rnd.c new file mode 100644 index 0000000000..f9b809229d --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_rnd.c @@ -0,0 +1,396 @@ + +/* + * M_APM - mapm_rnd.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_rnd.c,v 1.12 2007/12/03 01:47:17 mike Exp $ + * + * This file contains the Random Number Generator function. + * + * $Log: mapm_rnd.c,v $ + * Revision 1.12 2007/12/03 01:47:17 mike + * Update license + * + * Revision 1.11 2003/10/25 22:55:43 mike + * add support for National Instruments LabWindows CVI + * + * Revision 1.10 2002/11/03 22:41:03 mike + * Updated function parameters to use the modern style + * + * Revision 1.9 2002/02/14 21:50:45 mike + * add _set_random_seed + * + * Revision 1.8 2001/07/16 19:30:32 mike + * add function M_free_all_rnd + * + * Revision 1.7 2001/03/20 17:19:45 mike + * use a new multiplier + * + * Revision 1.6 2000/08/20 23:46:07 mike + * add more possible multupliers (no code changes) + * + * Revision 1.5 1999/09/19 23:32:14 mike + * added comments + * + * Revision 1.4 1999/09/18 03:49:25 mike + * *** empty log message *** + * + * Revision 1.3 1999/09/18 03:35:36 mike + * only prototype get_microsec for non-DOS + * + * Revision 1.2 1999/09/18 02:35:36 mike + * delete debug printf's + * + * Revision 1.1 1999/09/18 02:26:52 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +#ifndef _HAVE_NI_LABWIN_CVI_ +#ifdef MSDOS +#include +#include +#else +#include +extern void M_get_microsec(unsigned long *, long *); +#endif +#endif + +#ifdef _HAVE_NI_LABWIN_CVI_ +#include +#include +#include +#endif + +extern void M_reverse_string(char *); +extern void M_get_rnd_seed(M_APM); + +static M_APM M_rnd_aa; +static M_APM M_rnd_mm; +static M_APM M_rnd_XX; +static M_APM M_rtmp0; +static M_APM M_rtmp1; + +static int M_firsttime2 = TRUE; + +/* + Used Knuth's The Art of Computer Programming, Volume 2 as + the basis. Assuming the random number is X, compute + (where all the math is performed on integers) : + + X = (a * X + c) MOD m + + From Knuth: + + 'm' should be large, at least 2^30 : we use 1.0E+15 + + 'a' should be between .01m and .99m and not have a simple + pattern. 'a' should not have any large factors in common + with 'm' and (since 'm' is a power of 10) if 'a' MOD 200 + = 21 then all 'm' different possible values will be + generated before 'X' starts to repeat. + + We use 'a' = 716805947629621. + + This is a prime number and also meets 'a' MOD 200 = 21. + Commented out below are many potential multipliers that + are all prime and meet 'a' MOD 200 = 21. + + There are few restrictions on 'c' except 'c' can have no + factor in common with 'm', hence we set 'c' = 'a'. + + On the first call, the system time is used to initialize X. +*/ + +/* + * the following constants are all potential multipliers. they are + * all prime numbers that also meet the criteria of NUM mod 200 = 21. + */ + +/* +439682071525421 439682071528421 439682071529221 439682071529821 +439682071530421 439682071532021 439682071538821 439682071539421 +439682071540021 439682071547021 439682071551221 439682071553821 +439682071555421 439682071557221 439682071558021 439682071558621 +439682071559821 439652381461621 439652381465221 439652381465621 +439652381466421 439652381467421 439652381468621 439652381470021 +439652381471221 439652381477021 439652381484221 439652381488421 +439652381491021 439652381492021 439652381494021 439652381496821 +617294387035621 617294387038621 617294387039221 617294387044421 +617294387045221 617294387048621 617294387051621 617294387051821 +617294387053621 617294387058421 617294387064221 617294387065621 +617294387068621 617294387069221 617294387069821 617294387070421 +617294387072021 617294387072621 617294387073821 617294387076821 +649378126517621 649378126517821 649378126518221 649378126520821 +649378126523821 649378126525621 649378126526621 649378126528421 +649378126529621 649378126530821 649378126532221 649378126533221 +649378126535221 649378126539421 649378126543621 649378126546021 +649378126546421 649378126549421 649378126550821 649378126555021 +649378126557421 649378126560221 649378126561621 649378126562021 +649378126564621 649378126565821 672091582360421 672091582364221 +672091582364621 672091582367021 672091582368421 672091582369021 +672091582370821 672091582371421 672091582376821 672091582380821 +716805243983221 716805243984821 716805947623621 716805947624621 +716805947629021 716805947629621 716805947630621 716805947633621 +716805947634221 716805947635021 716805947635621 716805947642221 +*/ + +/****************************************************************************/ +void M_free_all_rnd() +{ +if (M_firsttime2 == FALSE) + { + m_apm_free(M_rnd_aa); + m_apm_free(M_rnd_mm); + m_apm_free(M_rnd_XX); + m_apm_free(M_rtmp0); + m_apm_free(M_rtmp1); + + M_firsttime2 = TRUE; + } +} +/****************************************************************************/ +void m_apm_set_random_seed(char *ss) +{ +M_APM btmp; + +if (M_firsttime2) + { + btmp = M_get_stack_var(); + m_apm_get_random(btmp); + M_restore_stack(1); + } + +m_apm_set_string(M_rnd_XX, ss); +} +/****************************************************************************/ +/* + * compute X = (a * X + c) MOD m where c = a + */ +void m_apm_get_random(M_APM mrnd) +{ + +if (M_firsttime2) /* use the system time as the initial seed value */ + { + M_firsttime2 = FALSE; + + M_rnd_aa = m_apm_init(); + M_rnd_XX = m_apm_init(); + M_rnd_mm = m_apm_init(); + M_rtmp0 = m_apm_init(); + M_rtmp1 = m_apm_init(); + + /* set the multiplier M_rnd_aa and M_rnd_mm */ + + m_apm_set_string(M_rnd_aa, "716805947629621"); + m_apm_set_string(M_rnd_mm, "1.0E15"); + + M_get_rnd_seed(M_rnd_XX); + } + +m_apm_multiply(M_rtmp0, M_rnd_XX, M_rnd_aa); +m_apm_add(M_rtmp1, M_rtmp0, M_rnd_aa); +m_apm_integer_div_rem(M_rtmp0, M_rnd_XX, M_rtmp1, M_rnd_mm); +m_apm_copy(mrnd, M_rnd_XX); +mrnd->m_apm_exponent -= 15; +} +/****************************************************************************/ +void M_reverse_string(char *s) +{ +int ct; +char ch, *p1, *p2; + +if ((ct = strlen(s)) <= 1) + return; + +p1 = s; +p2 = s + ct - 1; +ct /= 2; + +while (TRUE) + { + ch = *p1; + *p1++ = *p2; + *p2-- = ch; + + if (--ct == 0) + break; + } +} +/****************************************************************************/ + +#ifndef _HAVE_NI_LABWIN_CVI_ + +#ifdef MSDOS + +/****************************************************************************/ +/* + * for DOS / Win 9x/NT systems : use 'ftime' + */ +void M_get_rnd_seed(M_APM mm) +{ +int millisec; +time_t timestamp; +unsigned long ul; +char ss[32], buf1[48], buf2[32]; +struct timeb timebuffer; +M_APM atmp; + +atmp = M_get_stack_var(); + +ftime(&timebuffer); + +millisec = (int)timebuffer.millitm; +timestamp = timebuffer.time; +ul = (unsigned long)(timestamp / 7); +ul += timestamp + 537; +strcpy(ss,ctime(×tamp)); /* convert to string and copy to ss */ + +sprintf(buf1,"%d",(millisec / 10)); +sprintf(buf2,"%lu",ul); + +ss[0] = ss[18]; +ss[1] = ss[17]; +ss[2] = ss[15]; +ss[3] = ss[14]; +ss[4] = ss[12]; +ss[5] = ss[11]; +ss[6] = ss[9]; +ss[7] = ss[23]; +ss[8] = ss[20]; +ss[9] = '\0'; + +M_reverse_string(buf2); +strcat(buf1,buf2); +strcat(buf1,ss); + +m_apm_set_string(atmp, buf1); +atmp->m_apm_exponent = 15; +m_apm_integer_divide(mm, atmp, MM_One); + +M_restore_stack(1); +} +/****************************************************************************/ + +#else + +/****************************************************************************/ +/* + * for unix systems : use 'gettimeofday' + */ +void M_get_rnd_seed(M_APM mm) +{ +unsigned long sec3; +long usec3; +char buf1[32], buf2[32]; +M_APM atmp; + +atmp = M_get_stack_var(); +M_get_microsec(&sec3,&usec3); + +sprintf(buf1,"%ld",usec3); +sprintf(buf2,"%lu",sec3); +M_reverse_string(buf2); +strcat(buf1,buf2); + +m_apm_set_string(atmp, buf1); +atmp->m_apm_exponent = 15; +m_apm_integer_divide(mm, atmp, MM_One); + +M_restore_stack(1); +} +/****************************************************************************/ +void M_get_microsec(unsigned long *sec, long *usec) +{ +struct timeval time_now; /* current time for elapsed time check */ +struct timezone time_zone; /* time zone for gettimeofday call */ + +gettimeofday(&time_now, &time_zone); /* get current time */ + +*sec = time_now.tv_sec; +*usec = time_now.tv_usec; +} +/****************************************************************************/ + +#endif +#endif + +#ifdef _HAVE_NI_LABWIN_CVI_ + +/****************************************************************************/ +/* + * for National Instruments LabWindows CVI + */ + +void M_get_rnd_seed(M_APM mm) +{ +double timer0; +int millisec; +char *cvi_time, *cvi_date, buf1[64], buf2[32]; +M_APM atmp; + +atmp = M_get_stack_var(); + +cvi_date = DateStr(); +cvi_time = TimeStr(); +timer0 = Timer(); + +/* + * note that Timer() is not syncronized to TimeStr(), + * but we don't care here since we are just looking + * for a random source of digits. + */ + +millisec = (int)(0.01 + 1000.0 * (timer0 - floor(timer0))); + +sprintf(buf1, "%d", millisec); + +buf2[0] = cvi_time[6]; /* time format: "HH:MM:SS" */ +buf2[1] = cvi_time[7]; +buf2[2] = cvi_time[3]; +buf2[3] = cvi_time[4]; +buf2[4] = cvi_time[0]; +buf2[5] = cvi_time[1]; + +buf2[6] = cvi_date[3]; /* date format: "MM-DD-YYYY" */ +buf2[7] = cvi_date[4]; +buf2[8] = cvi_date[0]; +buf2[9] = cvi_date[1]; +buf2[10] = cvi_date[8]; +buf2[11] = cvi_date[9]; +buf2[12] = cvi_date[7]; + +buf2[13] = '4'; +buf2[14] = '7'; +buf2[15] = '\0'; + +strcat(buf1, buf2); + +m_apm_set_string(atmp, buf1); +atmp->m_apm_exponent = 15; +m_apm_integer_divide(mm, atmp, MM_One); + +M_restore_stack(1); +} + +#endif + +/****************************************************************************/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_set.c b/src/apps/deskcalc/mapm_4.9.5/mapm_set.c new file mode 100644 index 0000000000..d7b5b743bd --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_set.c @@ -0,0 +1,412 @@ + +/* + * M_APM - mapm_set.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_set.c,v 1.18 2007/12/03 01:47:50 mike Exp $ + * + * This file contains the functions necessary to get C 'longs' and + * 'strings' into the MAPM number system. It also contains the function + * to get a string from a MAPM number. + * + * $Log: mapm_set.c,v $ + * Revision 1.18 2007/12/03 01:47:50 mike + * Update license + * + * Revision 1.17 2003/07/21 20:25:06 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.16 2003/03/31 21:59:52 mike + * call generic error handling function + * + * Revision 1.15 2002/11/05 23:31:54 mike + * use new set_to_zero call instead of copy + * + * Revision 1.14 2002/11/03 22:24:19 mike + * Updated function parameters to use the modern style + * + * Revision 1.13 2001/07/16 19:34:16 mike + * add function M_free_all_set + * + * Revision 1.12 2001/02/11 22:33:27 mike + * modify parameters to REALLOC + * + * Revision 1.11 2001/01/23 21:16:03 mike + * use dedicated call to long->ascii instead of sprintf + * + * Revision 1.10 2000/10/25 22:57:25 mike + * add cast which really wasn't needed + * + * Revision 1.9 2000/10/25 19:57:01 mike + * add free call to end of set string if the temp + * string gets too big + * + * Revision 1.8 2000/05/04 23:49:19 mike + * put in more efficient set_long function + * + * Revision 1.7 2000/02/03 22:47:15 mike + * use MAPM_* generic memory function + * + * Revision 1.6 1999/07/12 22:23:17 mike + * tweak output string when input == 0 + * + * Revision 1.5 1999/07/12 02:07:56 mike + * fix dec_places error (was == -1, should be < 0) + * + * Revision 1.4 1999/06/19 21:36:57 mike + * added some comments + * + * Revision 1.3 1999/06/19 21:35:19 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.2 1999/05/13 21:32:41 mike + * added check for illegal chars in string parse + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static char *M_buf = NULL; +static int M_lbuf = 0; +static char *M_set_string_error_msg = "\'m_apm_set_string\', Out of memory"; + +/****************************************************************************/ +void M_free_all_set() +{ +if (M_lbuf != 0) + { + MAPM_FREE(M_buf); + M_buf = NULL; + M_lbuf = 0; + } +} +/****************************************************************************/ +void m_apm_set_long(M_APM atmp, long mm) +{ +int len, ii, nbytes; +char *p, *buf, ch, buf2[64]; + +/* if zero, return right away */ + +if (mm == 0) + { + M_set_to_zero(atmp); + return; + } + +M_long_2_ascii(buf2, mm); /* convert long -> ascii in base 10 */ +buf = buf2; + +if (mm < 0) + { + atmp->m_apm_sign = -1; + buf++; /* get past '-' sign */ + } +else + { + atmp->m_apm_sign = 1; + } + +len = strlen(buf); +atmp->m_apm_exponent = len; + +/* least significant nibble of ODD data-length must be 0 */ + +if ((len & 1) != 0) + { + buf[len] = '0'; + } + +/* remove any trailing '0' ... */ + +while (TRUE) + { + if (buf[--len] != '0') + break; + } + +atmp->m_apm_datalength = ++len; + +nbytes = (len + 1) >> 1; +p = buf; + +for (ii=0; ii < nbytes; ii++) + { + ch = *p++ - '0'; + atmp->m_apm_data[ii] = 10 * ch + *p++ - '0'; + } +} +/****************************************************************************/ +void m_apm_set_string(M_APM ctmp, char *s_in) +{ +char ch, *cp, *s, *p; +void *vp; +int i, j, zflag, exponent, sign; + +if (M_lbuf == 0) + { + M_lbuf = 256; + if ((M_buf = (char *)MAPM_MALLOC(256)) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_set_string_error_msg); + } + } + +if ((i = strlen(s_in)) > (M_lbuf - 4)) + { + M_lbuf = i + 32; + if ((vp = MAPM_REALLOC(M_buf, M_lbuf)) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_set_string_error_msg); + } + + M_buf = (char *)vp; + } + +s = M_buf; +strcpy(s,s_in); + +/* default == zero ... */ + +M_set_to_zero(ctmp); + +p = s; + +while (TRUE) + { + if (*p == ' ' || *p == '\t') + p++; + else + break; + } + +if (*p == '\0') + return; + +sign = 1; /* assume number is positive */ + +if (*p == '+') /* scan by optional '+' sign */ + p++; +else + { + if (*p == '-') /* check if number negative */ + { + sign = -1; + p++; + } + } + +M_lowercase(p); /* convert string to lowercase */ +exponent = 0; /* default */ + +if ((cp = strstr(p,"e")) != NULL) + { + exponent = atoi(cp + sizeof(char)); + *cp = '\0'; /* erase the exponent now */ + } + +j = M_strposition(p,"."); /* is there a decimal point ?? */ +if (j == -1) + { + strcat(p,"."); /* if not, append one */ + j = M_strposition(p,"."); /* now find it ... */ + } + +if (j > 0) /* normalize number and adjust exponent */ + { + exponent += j; + memmove((p+1),p,(j * sizeof(char))); + } + +p++; /* scan past implied decimal point now in column 1 (index 0) */ + +i = strlen(p); +ctmp->m_apm_datalength = i; + +if ((i & 1) != 0) /* if odd number of digits, append a '0' to make it even */ + strcat(p,"0"); + +j = strlen(p) >> 1; /* number of bytes in encoded M_APM number */ + +/* do we need more memory to hold this number */ + +if (j > ctmp->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(ctmp->m_apm_data, (j + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_set_string_error_msg); + } + + ctmp->m_apm_malloclength = j + 28; + ctmp->m_apm_data = (UCHAR *)vp; + } + +zflag = TRUE; + +for (i=0; i < j; i++) + { + ch = *p++ - '0'; + if ((ch = (10 * ch + *p++ - '0')) != 0) + zflag = FALSE; + + if (((int)ch & 0xFF) >= 100) + { + M_apm_log_error_msg(M_APM_RETURN, + "\'m_apm_set_string\', Non-digit char found in parse"); + + M_apm_log_error_msg(M_APM_RETURN, "Text ="); + M_apm_log_error_msg(M_APM_RETURN, s_in); + + M_set_to_zero(ctmp); + return; + } + + ctmp->m_apm_data[i] = ch; + ctmp->m_apm_data[i+1] = 0; + } + +ctmp->m_apm_exponent = exponent; +ctmp->m_apm_sign = sign; + +if (zflag) + { + ctmp->m_apm_exponent = 0; + ctmp->m_apm_sign = 0; + ctmp->m_apm_datalength = 1; + } +else + { + M_apm_normalize(ctmp); + } + +/* + * if our local temp string is getting too big, + * release it's memory and start over next time. + * (this 1000 byte threshold is quite arbitrary, + * it may be more efficient in your app to make + * this number bigger). + */ + +if (M_lbuf > 1000) + { + MAPM_FREE(M_buf); + M_buf = NULL; + M_lbuf = 0; + } +} +/****************************************************************************/ +void m_apm_to_string(char *s, int places, M_APM mtmp) +{ +M_APM ctmp; +char *cp; +int i, index, first, max_i, num_digits, dec_places; +UCHAR numdiv, numrem; + +ctmp = M_get_stack_var(); +dec_places = places; + +if (dec_places < 0) + m_apm_copy(ctmp, mtmp); +else + m_apm_round(ctmp, dec_places, mtmp); + +if (ctmp->m_apm_sign == 0) + { + if (dec_places < 0) + strcpy(s,"0.0E+0"); + else + { + strcpy(s,"0"); + + if (dec_places > 0) + strcat(s,"."); + + for (i=0; i < dec_places; i++) + strcat(s,"0"); + + strcat(s,"E+0"); + } + + M_restore_stack(1); + return; + } + +max_i = (ctmp->m_apm_datalength + 1) >> 1; + +if (dec_places < 0) + num_digits = ctmp->m_apm_datalength; +else + num_digits = dec_places + 1; + +cp = s; + +if (ctmp->m_apm_sign == -1) + *cp++ = '-'; + +first = TRUE; + +i = 0; +index = 0; + +while (TRUE) + { + if (index >= max_i) + { + numdiv = 0; + numrem = 0; + } + else + M_get_div_rem_10((int)ctmp->m_apm_data[index],&numdiv,&numrem); + + index++; + + *cp++ = numdiv + '0'; + + if (++i == num_digits) + break; + + if (first) + { + first = FALSE; + *cp++ = '.'; + } + + *cp++ = numrem + '0'; + + if (++i == num_digits) + break; + } + +i = ctmp->m_apm_exponent - 1; +if (i >= 0) + sprintf(cp,"E+%d",i); +else + sprintf(cp,"E%d",i); + +M_restore_stack(1); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapm_sin.c b/src/apps/deskcalc/mapm_4.9.5/mapm_sin.c new file mode 100644 index 0000000000..cff855ff1d --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapm_sin.c @@ -0,0 +1,193 @@ + +/* + * M_APM - mapm_sin.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapm_sin.c,v 1.17 2007/12/03 01:48:31 mike Exp $ + * + * This file contains the top level (user callable) SIN / COS / TAN + * functions. + * + * $Log: mapm_sin.c,v $ + * Revision 1.17 2007/12/03 01:48:31 mike + * Update license + * + * Revision 1.16 2002/11/03 21:53:47 mike + * Updated function parameters to use the modern style + * + * Revision 1.15 2001/03/25 20:59:46 mike + * move PI stuff to new file + * + * Revision 1.14 2001/02/07 19:12:14 mike + * eliminate MM_skip_limit_PI_check + * + * Revision 1.13 2000/11/18 11:05:36 mike + * minor code re-arrangement in PI AGM + * + * Revision 1.12 2000/07/11 23:34:42 mike + * adjust loop break-out for AGM PI algorithm + * + * Revision 1.11 2000/07/11 20:19:47 mike + * use new algorithm to compute PI (AGM) + * + * Revision 1.10 2000/05/21 01:07:57 mike + * use _sin_cos in _tan function + * + * Revision 1.9 2000/05/19 17:13:56 mike + * use local copies of PI variables & recompute + * on the fly as needed + * + * Revision 1.8 1999/09/21 21:03:06 mike + * make sure the sign of 'sin' from M_cos_to_sin is non-zero + * before assigning it from the original angle. + * + * Revision 1.7 1999/09/18 03:27:27 mike + * added m_apm_sin_cos + * + * Revision 1.6 1999/07/09 22:50:33 mike + * skip limit to PI when not needed + * + * Revision 1.5 1999/06/20 23:42:29 mike + * use new function for COS function + * + * Revision 1.4 1999/06/20 19:27:12 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.3 1999/05/17 03:54:56 mike + * init globals in TAN function also + * + * Revision 1.2 1999/05/15 02:18:31 mike + * add check for number of decimal places + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_sin(M_APM r, int places, M_APM a) +{ +M_APM tmp3; + +tmp3 = M_get_stack_var(); +M_limit_angle_to_pi(tmp3, (places + 6), a); +M_5x_sin(r, places, tmp3); +M_restore_stack(1); +} +/****************************************************************************/ +void m_apm_cos(M_APM r, int places, M_APM a) +{ +M_APM tmp3; + +tmp3 = M_get_stack_var(); +M_limit_angle_to_pi(tmp3, (places + 6), a); +M_4x_cos(r, places, tmp3); +M_restore_stack(1); +} +/****************************************************************************/ +void m_apm_sin_cos(M_APM sinv, M_APM cosv, int places, M_APM aa) +{ +M_APM tmp5, tmp6, tmp7; + +tmp5 = M_get_stack_var(); +tmp6 = M_get_stack_var(); +tmp7 = M_get_stack_var(); + +M_limit_angle_to_pi(tmp5, (places + 6), aa); +M_4x_cos(tmp7, (places + 6), tmp5); + +/* + * compute sin(x) = sqrt(1 - cos(x) ^ 2). + * + * note that the sign of 'sin' will always be positive after the + * sqrt call. we need to adjust the sign based on what quadrant + * the original angle is in. + */ + +M_cos_to_sin(tmp6, (places + 6), tmp7); +if (tmp6->m_apm_sign != 0) + tmp6->m_apm_sign = tmp5->m_apm_sign; + +m_apm_round(sinv, places, tmp6); +m_apm_round(cosv, places, tmp7); +M_restore_stack(3); +} +/****************************************************************************/ +void m_apm_tan(M_APM r, int places, M_APM a) +{ +M_APM tmps, tmpc, tmp0; + +tmps = M_get_stack_var(); +tmpc = M_get_stack_var(); +tmp0 = M_get_stack_var(); + +m_apm_sin_cos(tmps, tmpc, (places + 4), a); + +/* tan(x) = sin(x) / cos(x) */ + +m_apm_divide(tmp0, (places + 4), tmps, tmpc); +m_apm_round(r, places, tmp0); +M_restore_stack(3); +} +/****************************************************************************/ +void M_limit_angle_to_pi(M_APM rr, int places, M_APM aa) +{ +M_APM tmp7, tmp8, tmp9; + +M_check_PI_places(places); + +tmp9 = M_get_stack_var(); +m_apm_copy(tmp9, MM_lc_PI); + +if (m_apm_compare(aa, tmp9) == 1) /* > PI */ + { + tmp7 = M_get_stack_var(); + tmp8 = M_get_stack_var(); + + m_apm_add(tmp7, aa, tmp9); + m_apm_integer_divide(tmp9, tmp7, MM_lc_2_PI); + m_apm_multiply(tmp8, tmp9, MM_lc_2_PI); + m_apm_subtract(tmp9, aa, tmp8); + m_apm_round(rr, places, tmp9); + + M_restore_stack(3); + return; + } + +tmp9->m_apm_sign = -1; +if (m_apm_compare(aa, tmp9) == -1) /* < -PI */ + { + tmp7 = M_get_stack_var(); + tmp8 = M_get_stack_var(); + + m_apm_add(tmp7, aa, tmp9); + m_apm_integer_divide(tmp9, tmp7, MM_lc_2_PI); + m_apm_multiply(tmp8, tmp9, MM_lc_2_PI); + m_apm_subtract(tmp9, aa, tmp8); + m_apm_round(rr, places, tmp9); + + M_restore_stack(3); + return; + } + +m_apm_copy(rr, aa); +M_restore_stack(1); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmasin.c b/src/apps/deskcalc/mapm_4.9.5/mapmasin.c new file mode 100644 index 0000000000..8b67a3f802 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmasin.c @@ -0,0 +1,520 @@ + +/* + * M_APM - mapmasin.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmasin.c,v 1.28 2007/12/03 01:49:10 mike Exp $ + * + * This file contains the 'ARC' family of functions; ARC-SIN, ARC-COS, + * ARC-TAN, and ARC-TAN2. + * + * $Log: mapmasin.c,v $ + * Revision 1.28 2007/12/03 01:49:10 mike + * Update license + * + * Revision 1.27 2003/07/24 16:34:02 mike + * update arctan_large_input + * + * Revision 1.26 2003/07/21 20:27:48 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.25 2003/07/21 19:19:26 mike + * add new arctan with large input value + * + * Revision 1.24 2003/05/01 21:58:49 mike + * remove math.h + * + * Revision 1.23 2003/04/09 21:43:00 mike + * optimize iterative asin & acos with lessons learned + * from the new log function + * + * Revision 1.22 2003/03/31 21:58:11 mike + * call generic error handling function + * + * Revision 1.21 2002/11/03 21:41:54 mike + * Updated function parameters to use the modern style + * + * Revision 1.20 2001/02/07 19:07:07 mike + * eliminate MM_skip_limit_PI_check + * + * Revision 1.19 2001/02/06 21:50:56 mike + * don't display accuracy when iteration count maxes out + * + * Revision 1.18 2000/12/02 20:10:09 mike + * add calls to more efficient functions if + * the input args are close to zero + * + * Revision 1.17 2000/09/05 22:18:02 mike + * re-arrange code to eliminate goto from atan2 + * + * Revision 1.16 2000/05/28 23:58:41 mike + * minor optimization to arc-tan2 + * + * Revision 1.15 2000/05/19 17:13:29 mike + * use local copies of PI variables & recompute + * on the fly as needed + * + * Revision 1.14 2000/03/27 21:43:23 mike + * dtermine how many iterations should be required at + * run time for arc-sin and arc-cos + * + * Revision 1.13 1999/09/21 21:00:33 mike + * make sure the sign of 'sin' from M_cos_to_sin is non-zero + * before assigning it from the original angle. + * + * Revision 1.12 1999/07/21 03:05:06 mike + * added some comments + * + * Revision 1.11 1999/07/19 02:33:39 mike + * reset local precision again + * + * Revision 1.10 1999/07/19 02:18:05 mike + * more fine tuning of local precision + * + * Revision 1.9 1999/07/19 00:08:34 mike + * adjust local precision during iterative loops + * + * Revision 1.8 1999/07/18 22:35:56 mike + * make arc-sin and arc-cos use dynamically changing + * precision to speed up iterative routines for large N + * + * Revision 1.7 1999/07/09 22:52:00 mike + * skip limit PI check when not needed + * + * Revision 1.6 1999/07/09 00:10:39 mike + * use better method for arc sin and arc cos + * + * Revision 1.5 1999/07/08 22:56:20 mike + * replace local MAPM constant with a global + * + * Revision 1.4 1999/06/20 16:55:01 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.3 1999/05/15 02:10:27 mike + * add check for number of decimal places + * + * Revision 1.2 1999/05/10 21:10:21 mike + * added some comments + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_arctan2(M_APM rr, int places, M_APM yy, M_APM xx) +{ +M_APM tmp5, tmp6, tmp7; +int ix, iy; + +iy = yy->m_apm_sign; +ix = xx->m_apm_sign; + +if (ix == 0) /* x == 0 */ + { + if (iy == 0) /* y == 0 */ + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_arctan2\', Both Inputs = 0"); + M_set_to_zero(rr); + return; + } + + M_check_PI_places(places); + m_apm_round(rr, places, MM_lc_HALF_PI); + rr->m_apm_sign = iy; + return; + } + +if (iy == 0) + { + if (ix == 1) + { + M_set_to_zero(rr); + } + else + { + M_check_PI_places(places); + m_apm_round(rr, places, MM_lc_PI); + } + + return; + } + +/* + * the special cases have been handled, now do the real work + */ + +tmp5 = M_get_stack_var(); +tmp6 = M_get_stack_var(); +tmp7 = M_get_stack_var(); + +m_apm_divide(tmp6, (places + 6), yy, xx); +m_apm_arctan(tmp5, (places + 6), tmp6); + +if (ix == 1) /* 'x' is positive */ + { + m_apm_round(rr, places, tmp5); + } +else /* 'x' is negative */ + { + M_check_PI_places(places); + + if (iy == 1) /* 'y' is positive */ + { + m_apm_add(tmp7, tmp5, MM_lc_PI); + m_apm_round(rr, places, tmp7); + } + else /* 'y' is negative */ + { + m_apm_subtract(tmp7, tmp5, MM_lc_PI); + m_apm_round(rr, places, tmp7); + } + } + +M_restore_stack(3); +} +/****************************************************************************/ +/* + Calculate arctan using the identity : + + x + arctan (x) == arcsin [ --------------- ] + sqrt(1 + x^2) + +*/ +void m_apm_arctan(M_APM rr, int places, M_APM xx) +{ +M_APM tmp8, tmp9; + +if (xx->m_apm_sign == 0) /* input == 0 ?? */ + { + M_set_to_zero(rr); + return; + } + +if (xx->m_apm_exponent <= -4) /* input close to 0 ?? */ + { + M_arctan_near_0(rr, places, xx); + return; + } + +if (xx->m_apm_exponent >= 4) /* large input */ + { + M_arctan_large_input(rr, places, xx); + return; + } + +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +m_apm_multiply(tmp9, xx, xx); +m_apm_add(tmp8, tmp9, MM_One); +m_apm_sqrt(tmp9, (places + 6), tmp8); +m_apm_divide(tmp8, (places + 6), xx, tmp9); +m_apm_arcsin(rr, places, tmp8); +M_restore_stack(2); +} +/****************************************************************************/ +/* + + for large input values use : + + arctan(x) = (PI / 2) - arctan(1 / |x|) + + and sign of result = sign of original input + +*/ +void M_arctan_large_input(M_APM rr, int places, M_APM xx) +{ +M_APM tmp1, tmp2; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +M_check_PI_places(places); + +m_apm_divide(tmp1, (places + 6), MM_One, xx); /* 1 / xx */ +tmp1->m_apm_sign = 1; /* make positive */ +m_apm_arctan(tmp2, (places + 6), tmp1); +m_apm_subtract(tmp1, MM_lc_HALF_PI, tmp2); +m_apm_round(rr, places, tmp1); + +rr->m_apm_sign = xx->m_apm_sign; /* fix final sign */ + +M_restore_stack(2); +} +/****************************************************************************/ +void m_apm_arcsin(M_APM r, int places, M_APM x) +{ +M_APM tmp0, tmp1, tmp2, tmp3, current_x; +int ii, maxiter, maxp, tolerance, local_precision; + +current_x = M_get_stack_var(); +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); + +m_apm_absolute_value(tmp0, x); + +ii = m_apm_compare(tmp0, MM_One); + +if (ii == 1) /* |x| > 1 */ + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_arcsin\', |Argument| > 1"); + M_set_to_zero(r); + M_restore_stack(5); + return; + } + +if (ii == 0) /* |x| == 1, arcsin = +/- PI / 2 */ + { + M_check_PI_places(places); + m_apm_round(r, places, MM_lc_HALF_PI); + r->m_apm_sign = x->m_apm_sign; + + M_restore_stack(5); + return; + } + +if (m_apm_compare(tmp0, MM_0_85) == 1) /* check if > 0.85 */ + { + M_cos_to_sin(tmp2, (places + 4), x); + m_apm_arccos(r, places, tmp2); + r->m_apm_sign = x->m_apm_sign; + + M_restore_stack(5); + return; + } + +if (x->m_apm_sign == 0) /* input == 0 ?? */ + { + M_set_to_zero(r); + M_restore_stack(5); + return; + } + +if (x->m_apm_exponent <= -4) /* input close to 0 ?? */ + { + M_arcsin_near_0(r, places, x); + M_restore_stack(5); + return; + } + +tolerance = -(places + 4); +maxp = places + 8 - x->m_apm_exponent; +local_precision = 20 - x->m_apm_exponent; + +/* + * compute the maximum number of iterations + * that should be needed to calculate to + * the desired accuracy. [ constant below ~= 1 / log(2) ] + */ + +maxiter = (int)(log((double)(places + 2)) * 1.442695) + 3; + +if (maxiter < 5) + maxiter = 5; + +M_get_asin_guess(current_x, x); + +/* Use the following iteration to solve for arc-sin : + + sin(X) - N + X = X - ------------ + n+1 cos(X) +*/ + +ii = 0; + +while (TRUE) + { + M_4x_cos(tmp1, local_precision, current_x); + + M_cos_to_sin(tmp2, local_precision, tmp1); + if (tmp2->m_apm_sign != 0) + tmp2->m_apm_sign = current_x->m_apm_sign; + + m_apm_subtract(tmp3, tmp2, x); + m_apm_divide(tmp0, local_precision, tmp3, tmp1); + + m_apm_subtract(tmp2, current_x, tmp0); + m_apm_copy(current_x, tmp2); + + if (ii != 0) + { + if (((2 * tmp0->m_apm_exponent) < tolerance) || (tmp0->m_apm_sign == 0)) + break; + } + + if (++ii == maxiter) + { + M_apm_log_error_msg(M_APM_RETURN, + "\'m_apm_arcsin\', max iteration count reached"); + break; + } + + local_precision *= 2; + + if (local_precision > maxp) + local_precision = maxp; + } + +m_apm_round(r, places, current_x); +M_restore_stack(5); +} +/****************************************************************************/ +void m_apm_arccos(M_APM r, int places, M_APM x) +{ +M_APM tmp0, tmp1, tmp2, tmp3, current_x; +int ii, maxiter, maxp, tolerance, local_precision; + +current_x = M_get_stack_var(); +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); + +m_apm_absolute_value(tmp0, x); + +ii = m_apm_compare(tmp0, MM_One); + +if (ii == 1) /* |x| > 1 */ + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_arccos\', |Argument| > 1"); + M_set_to_zero(r); + M_restore_stack(5); + return; + } + +if (ii == 0) /* |x| == 1, arccos = 0, PI */ + { + if (x->m_apm_sign == 1) + { + M_set_to_zero(r); + } + else + { + M_check_PI_places(places); + m_apm_round(r, places, MM_lc_PI); + } + + M_restore_stack(5); + return; + } + +if (m_apm_compare(tmp0, MM_0_85) == 1) /* check if > 0.85 */ + { + M_cos_to_sin(tmp2, (places + 4), x); + + if (x->m_apm_sign == 1) + { + m_apm_arcsin(r, places, tmp2); + } + else + { + M_check_PI_places(places); + m_apm_arcsin(tmp3, (places + 4), tmp2); + m_apm_subtract(tmp1, MM_lc_PI, tmp3); + m_apm_round(r, places, tmp1); + } + + M_restore_stack(5); + return; + } + +if (x->m_apm_sign == 0) /* input == 0 ?? */ + { + M_check_PI_places(places); + m_apm_round(r, places, MM_lc_HALF_PI); + M_restore_stack(5); + return; + } + +if (x->m_apm_exponent <= -4) /* input close to 0 ?? */ + { + M_arccos_near_0(r, places, x); + M_restore_stack(5); + return; + } + +tolerance = -(places + 4); +maxp = places + 8; +local_precision = 18; + +/* + * compute the maximum number of iterations + * that should be needed to calculate to + * the desired accuracy. [ constant below ~= 1 / log(2) ] + */ + +maxiter = (int)(log((double)(places + 2)) * 1.442695) + 3; + +if (maxiter < 5) + maxiter = 5; + +M_get_acos_guess(current_x, x); + +/* Use the following iteration to solve for arc-cos : + + cos(X) - N + X = X + ------------ + n+1 sin(X) +*/ + +ii = 0; + +while (TRUE) + { + M_4x_cos(tmp1, local_precision, current_x); + + M_cos_to_sin(tmp2, local_precision, tmp1); + if (tmp2->m_apm_sign != 0) + tmp2->m_apm_sign = current_x->m_apm_sign; + + m_apm_subtract(tmp3, tmp1, x); + m_apm_divide(tmp0, local_precision, tmp3, tmp2); + + m_apm_add(tmp2, current_x, tmp0); + m_apm_copy(current_x, tmp2); + + if (ii != 0) + { + if (((2 * tmp0->m_apm_exponent) < tolerance) || (tmp0->m_apm_sign == 0)) + break; + } + + if (++ii == maxiter) + { + M_apm_log_error_msg(M_APM_RETURN, + "\'m_apm_arccos\', max iteration count reached"); + break; + } + + local_precision *= 2; + + if (local_precision > maxp) + local_precision = maxp; + } + +m_apm_round(r, places, current_x); +M_restore_stack(5); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmasn0.c b/src/apps/deskcalc/mapm_4.9.5/mapmasn0.c new file mode 100644 index 0000000000..a10aa9d5da --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmasn0.c @@ -0,0 +1,182 @@ + +/* + * M_APM - mapmasn0.c + * + * Copyright (C) 2000 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmasn0.c,v 1.8 2007/12/03 01:49:49 mike Exp $ + * + * This file contains the 'ARC' family of functions; ARC-SIN, + * ARC-COS, ARC-TAN when the input arg is very close to 0 (zero). + * + * $Log: mapmasn0.c,v $ + * Revision 1.8 2007/12/03 01:49:49 mike + * Update license + * + * Revision 1.7 2003/06/02 16:51:13 mike + * *** empty log message *** + * + * Revision 1.6 2003/06/02 16:49:48 mike + * tweak the decimal places + * + * Revision 1.5 2003/06/02 16:47:39 mike + * tweak arctan algorithm some more + * + * Revision 1.4 2003/05/31 22:38:07 mike + * optimize arctan by using fewer digits as subsequent + * terms get smaller + * + * Revision 1.3 2002/11/03 21:36:43 mike + * Updated function parameters to use the modern style + * + * Revision 1.2 2000/12/02 20:11:37 mike + * add comments + * + * Revision 1.1 2000/12/02 20:08:27 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + Calculate arcsin using the identity : + + x + arcsin (x) == arctan [ --------------- ] + sqrt(1 - x^2) + +*/ +void M_arcsin_near_0(M_APM rr, int places, M_APM aa) +{ +M_APM tmp5, tmp6; + +tmp5 = M_get_stack_var(); +tmp6 = M_get_stack_var(); + +M_cos_to_sin(tmp5, (places + 8), aa); +m_apm_divide(tmp6, (places + 8), aa, tmp5); +M_arctan_near_0(rr, places, tmp6); + +M_restore_stack(2); +} +/****************************************************************************/ +/* + Calculate arccos using the identity : + + arccos (x) == PI / 2 - arcsin (x) + +*/ +void M_arccos_near_0(M_APM rr, int places, M_APM aa) +{ +M_APM tmp1, tmp2; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +M_check_PI_places(places); +M_arcsin_near_0(tmp1, (places + 4), aa); +m_apm_subtract(tmp2, MM_lc_HALF_PI, tmp1); +m_apm_round(rr, places, tmp2); + +M_restore_stack(2); +} +/****************************************************************************/ +/* + calculate arctan (x) with the following series: + + x^3 x^5 x^7 x^9 + arctan (x) = x - --- + --- - --- + --- ... + 3 5 7 9 + +*/ +void M_arctan_near_0(M_APM rr, int places, M_APM aa) +{ +M_APM tmp0, tmp2, tmpR, tmpS, digit, term; +int tolerance, dplaces, local_precision; +long m1; + +tmp0 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmpR = M_get_stack_var(); +tmpS = M_get_stack_var(); +term = M_get_stack_var(); +digit = M_get_stack_var(); + +tolerance = aa->m_apm_exponent - (places + 4); +dplaces = (places + 8) - aa->m_apm_exponent; + +m_apm_copy(term, aa); +m_apm_copy(tmpS, aa); +m_apm_multiply(tmp0, aa, aa); +m_apm_round(tmp2, (dplaces + 8), tmp0); + +m1 = 1L; + +while (TRUE) + { + /* + * do the subtraction term + */ + + m_apm_multiply(tmp0, term, tmp2); + + if ((tmp0->m_apm_exponent < tolerance) || (tmp0->m_apm_sign == 0)) + { + m_apm_round(rr, places, tmpS); + break; + } + + local_precision = dplaces + tmp0->m_apm_exponent; + + if (local_precision < 20) + local_precision = 20; + + m1 += 2; + m_apm_set_long(digit, m1); + m_apm_round(term, local_precision, tmp0); + m_apm_divide(tmp0, local_precision, term, digit); + m_apm_subtract(tmpR, tmpS, tmp0); + + /* + * do the addition term + */ + + m_apm_multiply(tmp0, term, tmp2); + + if ((tmp0->m_apm_exponent < tolerance) || (tmp0->m_apm_sign == 0)) + { + m_apm_round(rr, places, tmpR); + break; + } + + local_precision = dplaces + tmp0->m_apm_exponent; + + if (local_precision < 20) + local_precision = 20; + + m1 += 2; + m_apm_set_long(digit, m1); + m_apm_round(term, local_precision, tmp0); + m_apm_divide(tmp0, local_precision, term, digit); + m_apm_add(tmpS, tmpR, tmp0); + } + +M_restore_stack(6); /* restore the 6 locals we used here */ +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmcbrt.c b/src/apps/deskcalc/mapm_4.9.5/mapmcbrt.c new file mode 100644 index 0000000000..e696762a6a --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmcbrt.c @@ -0,0 +1,153 @@ + +/* + * M_APM - mapmcbrt.c + * + * Copyright (C) 2000 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmcbrt.c,v 1.8 2007/12/03 01:50:32 mike Exp $ + * + * This file contains the CBRT (cube root) function. + * + * $Log: mapmcbrt.c,v $ + * Revision 1.8 2007/12/03 01:50:32 mike + * Update license + * + * Revision 1.7 2003/05/05 18:17:38 mike + * simplify some logic + * + * Revision 1.6 2003/04/16 16:55:58 mike + * use new faster algorithm which finds 1 / cbrt(N) + * + * Revision 1.5 2002/11/03 21:34:34 mike + * Updated function parameters to use the modern style + * + * Revision 1.4 2000/10/30 16:42:22 mike + * minor speed optimization + * + * Revision 1.3 2000/07/11 18:03:39 mike + * make better estimate for initial precision + * + * Revision 1.2 2000/04/08 18:34:35 mike + * added some more comments + * + * Revision 1.1 2000/04/03 17:58:04 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_cbrt(M_APM rr, int places, M_APM aa) +{ +M_APM last_x, guess, tmpN, tmp7, tmp8, tmp9; +int ii, nexp, bflag, tolerance, maxp, local_precision; + +/* result is 0 if input is 0 */ + +if (aa->m_apm_sign == 0) + { + M_set_to_zero(rr); + return; + } + +last_x = M_get_stack_var(); +guess = M_get_stack_var(); +tmpN = M_get_stack_var(); +tmp7 = M_get_stack_var(); +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +/* compute the cube root of the positive number, we'll fix the sign later */ + +m_apm_absolute_value(tmpN, aa); + +/* + normalize the input number (make the exponent near 0) so + the 'guess' function will not over/under flow on large + magnitude exponents. +*/ + +nexp = aa->m_apm_exponent / 3; +tmpN->m_apm_exponent -= 3 * nexp; + +M_get_cbrt_guess(guess, tmpN); + +tolerance = places + 4; +maxp = places + 16; +bflag = FALSE; +local_precision = 14; + +m_apm_negate(last_x, MM_Ten); + +/* Use the following iteration to calculate 1 / cbrt(N) : + + 4 + X = [ 4 * X - N * X ] / 3 + n+1 +*/ + +ii = 0; + +while (TRUE) + { + m_apm_multiply(tmp8, guess, guess); + m_apm_multiply(tmp7, tmp8, tmp8); + m_apm_round(tmp8, local_precision, tmp7); + m_apm_multiply(tmp9, tmpN, tmp8); + + m_apm_multiply(tmp8, MM_Four, guess); + m_apm_subtract(tmp7, tmp8, tmp9); + m_apm_divide(guess, local_precision, tmp7, MM_Three); + + if (bflag) + break; + + /* force at least 2 iterations so 'last_x' has valid data */ + + if (ii != 0) + { + m_apm_subtract(tmp8, guess, last_x); + + if (tmp8->m_apm_sign == 0) + break; + + if ((-4 * tmp8->m_apm_exponent) > tolerance) + bflag = TRUE; + } + + local_precision *= 2; + + if (local_precision > maxp) + local_precision = maxp; + + m_apm_copy(last_x, guess); + ii = 1; + } + +/* final cbrt = N * guess ^ 2 */ + +m_apm_multiply(tmp9, guess, guess); +m_apm_multiply(tmp8, tmp9, tmpN); +m_apm_round(rr, places, tmp8); + +rr->m_apm_exponent += nexp; +rr->m_apm_sign = aa->m_apm_sign; +M_restore_stack(6); +} +/****************************************************************************/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmcnst.c b/src/apps/deskcalc/mapm_4.9.5/mapmcnst.c new file mode 100644 index 0000000000..f315eb6c09 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmcnst.c @@ -0,0 +1,365 @@ + +/* + * M_APM - mapmcnst.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmcnst.c,v 1.24 2007/12/03 01:51:16 mike Exp $ + * + * This file contains declarations and initializes the constants + * used throughout the library. + * + * $Log: mapmcnst.c,v $ + * Revision 1.24 2007/12/03 01:51:16 mike + * Update license + * + * Revision 1.23 2003/05/06 21:28:53 mike + * add lib version functions + * + * Revision 1.22 2003/03/30 21:14:16 mike + * add local copies of log(2) and log(10) + * + * Revision 1.21 2002/11/03 22:45:29 mike + * Updated function parameters to use the modern style + * + * Revision 1.20 2002/05/17 22:40:25 mike + * call m_apm_init from cpp_precision to init the library + * if it hasn't been done yet. + * + * Revision 1.19 2001/07/16 19:40:12 mike + * add function M_free_all_cnst + * + * Revision 1.18 2001/02/07 19:17:58 mike + * eliminate MM_skip_limit_PI_check + * + * Revision 1.17 2000/05/19 16:31:02 mike + * add local copies for PI variables + * + * Revision 1.16 2000/05/04 23:52:03 mike + * added new constant, 256R. + * renamed _008 to _125R + * + * Revision 1.15 2000/04/11 18:44:21 mike + * no longer need the constant 'Fifteen' + * + * Revision 1.14 2000/04/05 20:12:53 mike + * add C++ min precision function + * + * Revision 1.13 1999/07/09 22:47:48 mike + * add skip limit PI check + * + * Revision 1.12 1999/07/08 23:34:50 mike + * change constant + * + * Revision 1.11 1999/07/08 22:58:08 mike + * add new constant + * + * Revision 1.10 1999/06/23 01:09:53 mike + * added new constant 15 + * + * Revision 1.9 1999/06/20 23:32:30 mike + * added new constants + * + * Revision 1.8 1999/06/20 19:24:14 mike + * delete constants no longer needed + * + * Revision 1.7 1999/06/20 18:57:29 mike + * fixed missing init for new constants + * + * Revision 1.6 1999/06/20 18:53:44 mike + * added more constants + * + * Revision 1.5 1999/05/31 23:50:30 mike + * delete constants no longer needed + * + * Revision 1.4 1999/05/14 19:50:22 mike + * added more constants with more digits + * + * Revision 1.3 1999/05/12 20:53:08 mike + * added more constants + * + * Revision 1.2 1999/05/10 21:52:24 mike + * added some comments + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +int MM_lc_PI_digits = 0; +int MM_lc_log_digits; +int MM_cpp_min_precision; /* only used in C++ wrapper */ + +M_APM MM_Zero = NULL; +M_APM MM_One = NULL; +M_APM MM_Two = NULL; +M_APM MM_Three = NULL; +M_APM MM_Four = NULL; +M_APM MM_Five = NULL; +M_APM MM_Ten = NULL; +M_APM MM_0_5 = NULL; +M_APM MM_E = NULL; +M_APM MM_PI = NULL; +M_APM MM_HALF_PI = NULL; +M_APM MM_2_PI = NULL; +M_APM MM_lc_PI = NULL; +M_APM MM_lc_HALF_PI = NULL; +M_APM MM_lc_2_PI = NULL; +M_APM MM_lc_log2 = NULL; +M_APM MM_lc_log10 = NULL; +M_APM MM_lc_log10R = NULL; +M_APM MM_0_85 = NULL; +M_APM MM_5x_125R = NULL; +M_APM MM_5x_64R = NULL; +M_APM MM_5x_256R = NULL; +M_APM MM_5x_Eight = NULL; +M_APM MM_5x_Sixteen = NULL; +M_APM MM_5x_Twenty = NULL; +M_APM MM_LOG_E_BASE_10 = NULL; +M_APM MM_LOG_10_BASE_E = NULL; +M_APM MM_LOG_2_BASE_E = NULL; +M_APM MM_LOG_3_BASE_E = NULL; + + +static char MM_cnst_PI[] = +"3.1415926535897932384626433832795028841971693993751058209749445923078\ +1640628620899862803482534211706798214808651328230664709384460955"; + +static char MM_cnst_E[] = +"2.7182818284590452353602874713526624977572470936999595749669676277240\ +76630353547594571382178525166427427466391932003059921817413596629"; + +static char MM_cnst_log_2[] = +"0.6931471805599453094172321214581765680755001343602552541206800094933\ +93621969694715605863326996418687542001481020570685733685520235758"; + +static char MM_cnst_log_3[] = +"1.0986122886681096913952452369225257046474905578227494517346943336374\ +9429321860896687361575481373208878797002906595786574236800422593"; + +static char MM_cnst_log_10[] = +"2.3025850929940456840179914546843642076011014886287729760333279009675\ +7260967735248023599720508959829834196778404228624863340952546508"; + +static char MM_cnst_1_log_10[] = +"0.4342944819032518276511289189166050822943970058036665661144537831658\ +64649208870774729224949338431748318706106744766303733641679287159"; + +/* + * the following constants have ~520 digits each, if needed + */ + +/* +static char MM_cnst_PI[] = +"3.1415926535897932384626433832795028841971693993751058209749445923078\ +164062862089986280348253421170679821480865132823066470938446095505822\ +317253594081284811174502841027019385211055596446229489549303819644288\ +109756659334461284756482337867831652712019091456485669234603486104543\ +266482133936072602491412737245870066063155881748815209209628292540917\ +153643678925903600113305305488204665213841469519415116094330572703657\ +595919530921861173819326117931051185480744623799627495673518857527248\ +91227938183011949129833673362440656643"; + +static char MM_cnst_E[] = +"2.7182818284590452353602874713526624977572470936999595749669676277240\ +766303535475945713821785251664274274663919320030599218174135966290435\ +729003342952605956307381323286279434907632338298807531952510190115738\ +341879307021540891499348841675092447614606680822648001684774118537423\ +454424371075390777449920695517027618386062613313845830007520449338265\ +602976067371132007093287091274437470472306969772093101416928368190255\ +151086574637721112523897844250569536967707854499699679468644549059879\ +3163688923009879312773617821542499923"; + +static char MM_cnst_log_2[] = +"0.6931471805599453094172321214581765680755001343602552541206800094933\ +936219696947156058633269964186875420014810205706857336855202357581305\ +570326707516350759619307275708283714351903070386238916734711233501153\ +644979552391204751726815749320651555247341395258829504530070953263666\ +426541042391578149520437404303855008019441706416715186447128399681717\ +845469570262716310645461502572074024816377733896385506952606683411372\ +738737229289564935470257626520988596932019650585547647033067936544325\ +47632744951250406069438147104689946506"; + +static char MM_cnst_log_3[] = +"1.0986122886681096913952452369225257046474905578227494517346943336374\ +942932186089668736157548137320887879700290659578657423680042259305198\ +210528018707672774106031627691833813671793736988443609599037425703167\ +959115211455919177506713470549401667755802222031702529468975606901065\ +215056428681380363173732985777823669916547921318181490200301038236301\ +222486527481982259910974524908964580534670088459650857484441190188570\ +876474948670796130858294116021661211840014098255143919487688936798494\ +3022557315353296853452952514592138765"; + +static char MM_cnst_log_10[] = +"2.3025850929940456840179914546843642076011014886287729760333279009675\ +726096773524802359972050895982983419677840422862486334095254650828067\ +566662873690987816894829072083255546808437998948262331985283935053089\ +653777326288461633662222876982198867465436674744042432743651550489343\ +149393914796194044002221051017141748003688084012647080685567743216228\ +355220114804663715659121373450747856947683463616792101806445070648000\ +277502684916746550586856935673420670581136429224554405758925724208241\ +31469568901675894025677631135691929203"; + +static char MM_cnst_1_log_10[] = +"0.4342944819032518276511289189166050822943970058036665661144537831658\ +646492088707747292249493384317483187061067447663037336416792871589639\ +065692210646628122658521270865686703295933708696588266883311636077384\ +905142844348666768646586085135561482123487653435434357317253835622281\ +395603048646652366095539377356176323431916710991411597894962993512457\ +934926357655469077671082419150479910989674900103277537653570270087328\ +550951731440674697951899513594088040423931518868108402544654089797029\ +86328682876262414401345704354613292060"; +*/ + + +/****************************************************************************/ +char *m_apm_lib_version(char *v) +{ +strcpy(v, MAPM_LIB_VERSION); +return(v); +} +/****************************************************************************/ +char *m_apm_lib_short_version(char *v) +{ +strcpy(v, MAPM_LIB_SHORT_VERSION); +return(v); +} +/****************************************************************************/ +void M_free_all_cnst() +{ +if (MM_lc_PI_digits != 0) + { + m_apm_free(MM_Zero); + m_apm_free(MM_One); + m_apm_free(MM_Two); + m_apm_free(MM_Three); + m_apm_free(MM_Four); + m_apm_free(MM_Five); + m_apm_free(MM_Ten); + m_apm_free(MM_0_5); + m_apm_free(MM_LOG_2_BASE_E); + m_apm_free(MM_LOG_3_BASE_E); + m_apm_free(MM_E); + m_apm_free(MM_PI); + m_apm_free(MM_HALF_PI); + m_apm_free(MM_2_PI); + m_apm_free(MM_lc_PI); + m_apm_free(MM_lc_HALF_PI); + m_apm_free(MM_lc_2_PI); + m_apm_free(MM_lc_log2); + m_apm_free(MM_lc_log10); + m_apm_free(MM_lc_log10R); + m_apm_free(MM_0_85); + m_apm_free(MM_5x_125R); + m_apm_free(MM_5x_64R); + m_apm_free(MM_5x_256R); + m_apm_free(MM_5x_Eight); + m_apm_free(MM_5x_Sixteen); + m_apm_free(MM_5x_Twenty); + m_apm_free(MM_LOG_E_BASE_10); + m_apm_free(MM_LOG_10_BASE_E); + + MM_lc_PI_digits = 0; + } +} +/****************************************************************************/ +void M_init_trig_globals() +{ +MM_lc_PI_digits = VALID_DECIMAL_PLACES; +MM_lc_log_digits = VALID_DECIMAL_PLACES; +MM_cpp_min_precision = 30; + +MM_Zero = m_apm_init(); +MM_One = m_apm_init(); +MM_Two = m_apm_init(); +MM_Three = m_apm_init(); +MM_Four = m_apm_init(); +MM_Five = m_apm_init(); +MM_Ten = m_apm_init(); +MM_0_5 = m_apm_init(); +MM_LOG_2_BASE_E = m_apm_init(); +MM_LOG_3_BASE_E = m_apm_init(); +MM_E = m_apm_init(); +MM_PI = m_apm_init(); +MM_HALF_PI = m_apm_init(); +MM_2_PI = m_apm_init(); +MM_lc_PI = m_apm_init(); +MM_lc_HALF_PI = m_apm_init(); +MM_lc_2_PI = m_apm_init(); +MM_lc_log2 = m_apm_init(); +MM_lc_log10 = m_apm_init(); +MM_lc_log10R = m_apm_init(); +MM_0_85 = m_apm_init(); +MM_5x_125R = m_apm_init(); +MM_5x_64R = m_apm_init(); +MM_5x_256R = m_apm_init(); +MM_5x_Eight = m_apm_init(); +MM_5x_Sixteen = m_apm_init(); +MM_5x_Twenty = m_apm_init(); +MM_LOG_E_BASE_10 = m_apm_init(); +MM_LOG_10_BASE_E = m_apm_init(); + +m_apm_set_string(MM_One, "1"); +m_apm_set_string(MM_Two, "2"); +m_apm_set_string(MM_Three, "3"); +m_apm_set_string(MM_Four, "4"); +m_apm_set_string(MM_Five, "5"); +m_apm_set_string(MM_Ten, "10"); +m_apm_set_string(MM_0_5, "0.5"); +m_apm_set_string(MM_0_85, "0.85"); + +m_apm_set_string(MM_5x_125R, "8.0E-3"); +m_apm_set_string(MM_5x_64R, "1.5625E-2"); +m_apm_set_string(MM_5x_256R, "3.90625E-3"); +m_apm_set_string(MM_5x_Eight, "8"); +m_apm_set_string(MM_5x_Sixteen, "16"); +m_apm_set_string(MM_5x_Twenty, "20"); + +m_apm_set_string(MM_LOG_2_BASE_E, MM_cnst_log_2); +m_apm_set_string(MM_LOG_3_BASE_E, MM_cnst_log_3); +m_apm_set_string(MM_LOG_10_BASE_E, MM_cnst_log_10); +m_apm_set_string(MM_LOG_E_BASE_10, MM_cnst_1_log_10); + +m_apm_set_string(MM_lc_log2, MM_cnst_log_2); +m_apm_set_string(MM_lc_log10, MM_cnst_log_10); +m_apm_set_string(MM_lc_log10R, MM_cnst_1_log_10); + +m_apm_set_string(MM_E, MM_cnst_E); +m_apm_set_string(MM_PI, MM_cnst_PI); +m_apm_multiply(MM_HALF_PI, MM_PI, MM_0_5); +m_apm_multiply(MM_2_PI, MM_PI, MM_Two); + +m_apm_copy(MM_lc_PI, MM_PI); +m_apm_copy(MM_lc_HALF_PI, MM_HALF_PI); +m_apm_copy(MM_lc_2_PI, MM_2_PI); +} +/****************************************************************************/ +void m_apm_cpp_precision(int digits) +{ +if (MM_lc_PI_digits == 0) + { + m_apm_free(m_apm_init()); + } + +if (digits >= 2) + MM_cpp_min_precision = digits; +else + MM_cpp_min_precision = 2; +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmfact.c b/src/apps/deskcalc/mapm_4.9.5/mapmfact.c new file mode 100644 index 0000000000..d38de25b0b --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmfact.c @@ -0,0 +1,278 @@ + +/* + * M_APM - mapmfact.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmfact.c,v 1.11 2007/12/03 01:51:50 mike Exp $ + * + * This file contains the FACTORIAL function. + * + * $Log: mapmfact.c,v $ + * Revision 1.11 2007/12/03 01:51:50 mike + * Update license + * + * Revision 1.10 2003/07/21 21:05:31 mike + * facilitate 'gcov' code coverage tool by making an array smaller + * + * Revision 1.9 2002/11/03 21:27:28 mike + * Updated function parameters to use the modern style + * + * Revision 1.8 2000/06/14 20:36:16 mike + * increase size of DOS array + * + * Revision 1.7 2000/05/29 13:15:59 mike + * minor tweaks, fixed comment + * + * Revision 1.6 2000/05/26 16:39:03 mike + * minor update to comments and code + * + * Revision 1.5 2000/05/25 23:12:53 mike + * change 'nd' calculation + * + * Revision 1.4 2000/05/25 22:17:45 mike + * implement new algorithm for speed. approx 5 - 10X + * faster on my PC when N! is large (> 6000) + * + * Revision 1.3 1999/06/19 21:25:21 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.2 1999/05/23 18:21:12 mike + * minor variable name tweaks + * + * Revision 1.1 1999/05/15 21:06:11 mike + * Initial revision + */ + +/* + * Brief explanation of the factorial algorithm. + * ---------------------------------------------- + * + * The old algorithm simply multiplied N * (N-1) * (N-2) etc, until + * the number counted down to '2'. So one term of the multiplication + * kept getting bigger while multiplying by the next number in the + * sequence. + * + * The new algorithm takes advantage of the fast multiplication + * algorithm. The "ideal" setup for fast multiplication is when + * both numbers have approx the same number of significant digits + * and the number of digits is very near (but not over) an exact + * power of 2. + * + * So, we will multiply N * (N-1) * (N-2), etc until the number of + * significant digits is approx 256. + * + * Store this temp product into an array. + * + * Then we will multiply the next sequence until the number of + * significant digits is approx 256. + * + * Store this temp product into the next element of the array. + * + * Continue until we've counted down to 2. + * + * We now have an array of numbers with approx the same number + * of digits (except for the last element, depending on where it + * ended.) Now multiply each of the array elements together to + * get the final product. + * + * The array multiplies are done as follows (assume we used 11 + * array elements for this example, indicated by [0] - [10] ) : + * + * initial iter-1 iter-2 iter-3 iter-4 + * + * [0] + * * -> [0] + * [1] + * * -> [0] + * + * [2] + * * -> [1] + * [3] + * * -> [0] + * + * [4] + * * -> [2] + * [5] + * + * * -> [1] + * + * [6] + * * -> [3] * -> [0] + * [7] + * + * + * [8] + * * -> [4] + * [9] + * * -> [2] -> [1] + * + * + * [10] -> [5] + * + */ + +#include "m_apm_lc.h" + +/* define size of local array for temp storage */ + +#define NDIM 32 + +/****************************************************************************/ +void m_apm_factorial(M_APM moutput, M_APM minput) +{ +int ii, nmul, ndigits, nd, jj, kk, mm, ct; +M_APM array[NDIM]; +M_APM iprod1, iprod2, tmp1, tmp2; + +/* return 1 for any input <= 1 */ + +if (m_apm_compare(minput, MM_One) <= 0) + { + m_apm_copy(moutput, MM_One); + return; + } + +ct = 0; +mm = NDIM - 2; +ndigits = 256; +nd = ndigits - 20; +tmp1 = m_apm_init(); +tmp2 = m_apm_init(); +iprod1 = m_apm_init(); +iprod2 = m_apm_init(); +array[0] = m_apm_init(); + +m_apm_copy(tmp2, minput); + +/* loop until multiply count-down has reached '2' */ + +while (TRUE) + { + m_apm_copy(iprod1, MM_One); + + /* + * loop until the number of significant digits in this + * partial result is slightly less than 256 + */ + + while (TRUE) + { + m_apm_multiply(iprod2, iprod1, tmp2); + + m_apm_subtract(tmp1, tmp2, MM_One); + + m_apm_multiply(iprod1, iprod2, tmp1); + + /* + * I know, I know. There just isn't a *clean* way + * to break out of 2 nested loops. + */ + + if (m_apm_compare(tmp1, MM_Two) <= 0) + goto PHASE2; + + m_apm_subtract(tmp2, tmp1, MM_One); + + if (iprod1->m_apm_datalength > nd) + break; + } + + if (ct == (NDIM - 1)) + { + /* + * if the array has filled up, start multiplying + * some of the partial products now. + */ + + m_apm_copy(tmp1, array[mm]); + m_apm_multiply(array[mm], iprod1, tmp1); + + if (mm == 0) + { + mm = NDIM - 2; + ndigits = ndigits << 1; + nd = ndigits - 20; + } + else + mm--; + } + else + { + /* + * store this partial product in the array + * and allocate the next array element + */ + + m_apm_copy(array[ct], iprod1); + array[++ct] = m_apm_init(); + } + } + +PHASE2: + +m_apm_copy(array[ct], iprod1); + +kk = ct; + +while (kk != 0) + { + ii = 0; + jj = 0; + nmul = (kk + 1) >> 1; + + while (TRUE) + { + /* must use tmp var when ii,jj point to same element */ + + if (ii == 0) + { + m_apm_copy(tmp1, array[ii]); + m_apm_multiply(array[jj], tmp1, array[ii+1]); + } + else + m_apm_multiply(array[jj], array[ii], array[ii+1]); + + if (++jj == nmul) + break; + + ii += 2; + } + + if ((kk & 1) == 0) + { + jj = kk >> 1; + m_apm_copy(array[jj], array[kk]); + } + + kk = kk >> 1; + } + +m_apm_copy(moutput, array[0]); + +for (ii=0; ii <= ct; ii++) + { + m_apm_free(array[ii]); + } + +m_apm_free(tmp1); +m_apm_free(tmp2); +m_apm_free(iprod1); +m_apm_free(iprod2); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmfmul.c b/src/apps/deskcalc/mapm_4.9.5/mapmfmul.c new file mode 100644 index 0000000000..3862a843bc --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmfmul.c @@ -0,0 +1,798 @@ + +/* + * M_APM - mapmfmul.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmfmul.c,v 1.33 2007/12/03 01:52:22 mike Exp $ + * + * This file contains the divide-and-conquer FAST MULTIPLICATION + * function as well as its support functions. + * + * $Log: mapmfmul.c,v $ + * Revision 1.33 2007/12/03 01:52:22 mike + * Update license + * + * Revision 1.32 2004/02/18 03:16:15 mike + * optimize 4 byte multiply (when FFT is disabled) + * + * Revision 1.31 2003/12/04 01:14:06 mike + * redo math on 'borrow' + * + * Revision 1.30 2003/07/21 20:34:18 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.29 2003/03/31 21:55:07 mike + * call generic error handling function + * + * Revision 1.28 2002/11/03 22:38:15 mike + * Updated function parameters to use the modern style + * + * Revision 1.27 2002/02/14 19:53:32 mike + * add conditional compiler option to disable use + * of FFT multiply if the user so chooses. + * + * Revision 1.26 2001/07/26 20:56:38 mike + * fix comment, no code change + * + * Revision 1.25 2001/07/16 19:43:45 mike + * add function M_free_all_fmul + * + * Revision 1.24 2001/02/11 22:34:47 mike + * modify parameters to REALLOC + * + * Revision 1.23 2000/10/20 19:23:26 mike + * adjust power_of_2 function so it should work with + * 64 bit processors and beyond. + * + * Revision 1.22 2000/08/23 22:27:34 mike + * no real code change, re-named 2 local functions + * so they make more sense. + * + * Revision 1.21 2000/08/01 22:24:38 mike + * use sizeof(int) function call to stop some + * compilers from complaining. + * + * Revision 1.20 2000/07/19 17:12:00 mike + * lower the number of bytes that the FFT can handle. worst case + * testing indicated math overflow when >= 1048576 + * + * Revision 1.19 2000/07/08 18:29:03 mike + * increase define so FFT can handle bigger numbers + * + * Revision 1.18 2000/07/06 23:20:12 mike + * changed my mind. use static local MAPM numbers + * for temp data storage + * + * Revision 1.17 2000/07/06 20:52:34 mike + * use init function to get local writable copies + * instead of using the stack + * + * Revision 1.16 2000/07/04 17:25:09 mike + * guarantee 16 bit compilers still work OK + * + * Revision 1.15 2000/07/04 15:40:02 mike + * add call to use FFT algorithm + * + * Revision 1.14 2000/05/05 21:10:46 mike + * add comment indicating availability of assembly language + * version of M_4_byte_multiply for Linux on x86 platforms. + * + * Revision 1.13 2000/04/20 19:30:45 mike + * minor optimization to 4 byte multiply + * + * Revision 1.12 2000/04/14 15:39:30 mike + * optimize the fast multiply function. don't re-curse down + * to a size of 1. recurse down to a size of '4' and then + * call a special 4 byte multiply function. + * + * Revision 1.11 2000/02/03 23:02:13 mike + * put in RCS for real... + * + * Revision 1.10 2000/02/03 22:59:08 mike + * remove the extra recursive function. not needed any + * longer since all current compilers should not have + * any problem with true recursive calls. + * + * Revision 1.9 2000/02/03 22:47:39 mike + * use MAPM_* generic memory function + * + * Revision 1.8 1999/09/19 21:13:44 mike + * eliminate unneeded local int in _split + * + * Revision 1.7 1999/08/12 22:36:23 mike + * move the 3 'simple' function to the top of file + * so GCC can in-line the code. + * + * Revision 1.6 1999/08/12 22:01:14 mike + * more minor optimizations + * + * Revision 1.5 1999/08/12 02:02:06 mike + * minor optimization + * + * Revision 1.4 1999/08/10 22:51:59 mike + * minor tweak + * + * Revision 1.3 1999/08/10 00:45:47 mike + * added more comments and a few minor tweaks + * + * Revision 1.2 1999/08/09 02:50:02 mike + * add some comments + * + * Revision 1.1 1999/08/08 18:27:57 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static int M_firsttimef = TRUE; + +/* + * specify the max size the FFT routine can handle + * (in MAPM, #digits = 2 * #bytes) + * + * this number *must* be an exact power of 2. + * + * **WORST** case input numbers (all 9's) has shown that + * the FFT math will overflow if the #define here is + * >= 1048576. On my system, 524,288 worked OK. I will + * factor down another factor of 2 to safeguard against + * other computers have less precise floating point math. + * If you are confident in your system, 524288 will + * theoretically work fine. + * + * the define here allows the FFT algorithm to multiply two + * 524,288 digit numbers yielding a 1,048,576 digit result. + */ + +#define MAX_FFT_BYTES 262144 + +/* + * the Divide-and-Conquer multiplication kicks in when the size of + * the numbers exceed the capability of the FFT (#define just above). + * + * #bytes D&C call depth + * ------ -------------- + * 512K 1 + * 1M 2 + * 2M 3 + * 4M 4 + * ... ... + * 2.1990E+12 23 + * + * the following stack sizes are sized to meet the + * above 2.199E+12 example, though I wouldn't want to + * wait for it to finish... + * + * Each call requires 7 stack variables to be saved so + * we need a stack depth of 23 * 7 + PAD. (we use 164) + * + * For 'exp_stack', 3 integers also are required to be saved + * for each recursive call so we need a stack depth of + * 23 * 3 + PAD. (we use 72) + * + * + * If the FFT multiply is disabled, resize the arrays + * as follows: + * + * the following stack sizes are sized to meet the + * worst case expected assuming we are multiplying + * numbers with 2.14E+9 (2 ^ 31) digits. + * + * For sizeof(int) == 4 (32 bits) there may be up to 32 recursive + * calls. Each call requires 7 stack variables so we need a + * stack depth of 32 * 7 + PAD. (we use 240) + * + * For 'exp_stack', 3 integers also are required to be saved + * for each recursive call so we need a stack depth of + * 32 * 3 + PAD. (we use 100) + */ + +#ifdef NO_FFT_MULTIPLY +#define M_STACK_SIZE 240 +#define M_ISTACK_SIZE 100 +#else +#define M_STACK_SIZE 164 +#define M_ISTACK_SIZE 72 +#endif + +static int exp_stack[M_ISTACK_SIZE]; +static int exp_stack_ptr; + +static UCHAR *mul_stack_data[M_STACK_SIZE]; +static int mul_stack_data_size[M_STACK_SIZE]; +static int M_mul_stack_ptr; + +static UCHAR *fmul_a1, *fmul_a0, *fmul_a9, *fmul_b1, *fmul_b0, + *fmul_b9, *fmul_t0; + +static int size_flag, bit_limit, stmp, itmp, mii; + +static M_APM M_ain; +static M_APM M_bin; + +static char *M_stack_ptr_error_msg = "\'M_get_stack_ptr\', Out of memory"; + +extern void M_fast_multiply(M_APM, M_APM, M_APM); +extern void M_fmul_div_conq(UCHAR *, UCHAR *, UCHAR *, int); +extern void M_fmul_add(UCHAR *, UCHAR *, int, int); +extern int M_fmul_subtract(UCHAR *, UCHAR *, UCHAR *, int); +extern void M_fmul_split(UCHAR *, UCHAR *, UCHAR *, int); +extern int M_next_power_of_2(int); +extern int M_get_stack_ptr(int); +extern void M_push_mul_int(int); +extern int M_pop_mul_int(void); + +#ifdef NO_FFT_MULTIPLY +extern void M_4_byte_multiply(UCHAR *, UCHAR *, UCHAR *); +#else +extern void M_fast_mul_fft(UCHAR *, UCHAR *, UCHAR *, int); +#endif + +/* + * the following algorithm is used in this fast multiply routine + * (sometimes called the divide-and-conquer technique.) + * + * assume we have 2 numbers (a & b) with 2N digits. + * + * let : a = (2^N) * A1 + A0 , b = (2^N) * B1 + B0 + * + * where 'A1' is the 'most significant half' of 'a' and + * 'A0' is the 'least significant half' of 'a'. Same for + * B1 and B0. + * + * Now use the identity : + * + * 2N N N N + * ab = (2 + 2 ) A1B1 + 2 (A1-A0)(B0-B1) + (2 + 1)A0B0 + * + * + * The original problem of multiplying 2 (2N) digit numbers has + * been reduced to 3 multiplications of N digit numbers plus some + * additions, subtractions, and shifts. + * + * The fast multiplication algorithm used here uses the above + * identity in a recursive process. This algorithm results in + * O(n ^ 1.585) growth. + */ + + +/****************************************************************************/ +void M_free_all_fmul() +{ +int k; + +if (M_firsttimef == FALSE) + { + m_apm_free(M_ain); + m_apm_free(M_bin); + + for (k=0; k < M_STACK_SIZE; k++) + { + if (mul_stack_data_size[k] != 0) + { + MAPM_FREE(mul_stack_data[k]); + } + } + + M_firsttimef = TRUE; + } +} +/****************************************************************************/ +void M_push_mul_int(int val) +{ +exp_stack[++exp_stack_ptr] = val; +} +/****************************************************************************/ +int M_pop_mul_int() +{ +return(exp_stack[exp_stack_ptr--]); +} +/****************************************************************************/ +void M_fmul_split(UCHAR *x1, UCHAR *x0, UCHAR *xin, int nbytes) +{ +memcpy(x1, xin, nbytes); +memcpy(x0, (xin + nbytes), nbytes); +} +/****************************************************************************/ +void M_fast_multiply(M_APM rr, M_APM aa, M_APM bb) +{ +void *vp; +int ii, k, nexp, sign; + +if (M_firsttimef) + { + M_firsttimef = FALSE; + + for (k=0; k < M_STACK_SIZE; k++) + mul_stack_data_size[k] = 0; + + size_flag = M_get_sizeof_int(); + bit_limit = 8 * size_flag + 1; + + M_ain = m_apm_init(); + M_bin = m_apm_init(); + } + +exp_stack_ptr = -1; +M_mul_stack_ptr = -1; + +m_apm_copy(M_ain, aa); +m_apm_copy(M_bin, bb); + +sign = M_ain->m_apm_sign * M_bin->m_apm_sign; +nexp = M_ain->m_apm_exponent + M_bin->m_apm_exponent; + +if (M_ain->m_apm_datalength >= M_bin->m_apm_datalength) + ii = M_ain->m_apm_datalength; +else + ii = M_bin->m_apm_datalength; + +ii = (ii + 1) >> 1; +ii = M_next_power_of_2(ii); + +/* Note: 'ii' must be >= 4 here. this is guaranteed + by the caller: m_apm_multiply +*/ + +k = 2 * ii; /* required size of result, in bytes */ + +M_apm_pad(M_ain, k); /* fill out the data so the number of */ +M_apm_pad(M_bin, k); /* bytes is an exact power of 2 */ + +if (k > rr->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(rr->m_apm_data, (k + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'M_fast_multiply\', Out of memory"); + } + + rr->m_apm_malloclength = k + 28; + rr->m_apm_data = (UCHAR *)vp; + } + +#ifdef NO_FFT_MULTIPLY + +M_fmul_div_conq(rr->m_apm_data, M_ain->m_apm_data, + M_bin->m_apm_data, ii); +#else + +/* + * if the numbers are *really* big, use the divide-and-conquer + * routine first until the numbers are small enough to be handled + * by the FFT algorithm. If the numbers are already small enough, + * call the FFT multiplication now. + * + * Note that 'ii' here is (and must be) an exact power of 2. + */ + +if (size_flag == 2) /* if still using 16 bit compilers .... */ + { + M_fast_mul_fft(rr->m_apm_data, M_ain->m_apm_data, + M_bin->m_apm_data, ii); + } +else /* >= 32 bit compilers */ + { + if (ii > (MAX_FFT_BYTES + 2)) + { + M_fmul_div_conq(rr->m_apm_data, M_ain->m_apm_data, + M_bin->m_apm_data, ii); + } + else + { + M_fast_mul_fft(rr->m_apm_data, M_ain->m_apm_data, + M_bin->m_apm_data, ii); + } + } + +#endif + +rr->m_apm_sign = sign; +rr->m_apm_exponent = nexp; +rr->m_apm_datalength = 4 * ii; + +M_apm_normalize(rr); +} +/****************************************************************************/ +/* + * This is the recursive function to perform the multiply. The + * design intent here is to have no local variables. Any local + * data that needs to be saved is saved on one of the two stacks. + */ +void M_fmul_div_conq(UCHAR *rr, UCHAR *aa, UCHAR *bb, int sz) +{ + +#ifdef NO_FFT_MULTIPLY + +if (sz == 4) /* multiply 4x4 yielding an 8 byte result */ + { + M_4_byte_multiply(rr, aa, bb); + return; + } + +#else + +/* + * if the numbers are now small enough, let the FFT algorithm + * finish up. + */ + +if (sz == MAX_FFT_BYTES) + { + M_fast_mul_fft(rr, aa, bb, sz); + return; + } + +#endif + +memset(rr, 0, (2 * sz)); /* zero out the result */ +mii = sz >> 1; + +itmp = M_get_stack_ptr(mii); +M_push_mul_int(itmp); + +fmul_a1 = mul_stack_data[itmp]; + +itmp = M_get_stack_ptr(mii); +fmul_a0 = mul_stack_data[itmp]; + +itmp = M_get_stack_ptr(2 * sz); +fmul_a9 = mul_stack_data[itmp]; + +itmp = M_get_stack_ptr(mii); +fmul_b1 = mul_stack_data[itmp]; + +itmp = M_get_stack_ptr(mii); +fmul_b0 = mul_stack_data[itmp]; + +itmp = M_get_stack_ptr(2 * sz); +fmul_b9 = mul_stack_data[itmp]; + +itmp = M_get_stack_ptr(2 * sz); +fmul_t0 = mul_stack_data[itmp]; + +M_fmul_split(fmul_a1, fmul_a0, aa, mii); +M_fmul_split(fmul_b1, fmul_b0, bb, mii); + +stmp = M_fmul_subtract(fmul_a9, fmul_a1, fmul_a0, mii); +stmp *= M_fmul_subtract(fmul_b9, fmul_b0, fmul_b1, mii); + +M_push_mul_int(stmp); +M_push_mul_int(mii); + +M_fmul_div_conq(fmul_t0, fmul_a0, fmul_b0, mii); + +mii = M_pop_mul_int(); +stmp = M_pop_mul_int(); +itmp = M_pop_mul_int(); + +M_push_mul_int(itmp); +M_push_mul_int(stmp); +M_push_mul_int(mii); + +/* to restore all stack variables ... +fmul_a1 = mul_stack_data[itmp]; +fmul_a0 = mul_stack_data[itmp+1]; +fmul_a9 = mul_stack_data[itmp+2]; +fmul_b1 = mul_stack_data[itmp+3]; +fmul_b0 = mul_stack_data[itmp+4]; +fmul_b9 = mul_stack_data[itmp+5]; +fmul_t0 = mul_stack_data[itmp+6]; +*/ + +fmul_a1 = mul_stack_data[itmp]; +fmul_b1 = mul_stack_data[itmp+3]; +fmul_t0 = mul_stack_data[itmp+6]; + +memcpy((rr + sz), fmul_t0, sz); /* first 'add', result is now zero */ + /* so we just copy in the bytes */ +M_fmul_add(rr, fmul_t0, mii, sz); + +M_fmul_div_conq(fmul_t0, fmul_a1, fmul_b1, mii); + +mii = M_pop_mul_int(); +stmp = M_pop_mul_int(); +itmp = M_pop_mul_int(); + +M_push_mul_int(itmp); +M_push_mul_int(stmp); +M_push_mul_int(mii); + +fmul_a9 = mul_stack_data[itmp+2]; +fmul_b9 = mul_stack_data[itmp+5]; +fmul_t0 = mul_stack_data[itmp+6]; + +M_fmul_add(rr, fmul_t0, 0, sz); +M_fmul_add(rr, fmul_t0, mii, sz); + +if (stmp != 0) + M_fmul_div_conq(fmul_t0, fmul_a9, fmul_b9, mii); + +mii = M_pop_mul_int(); +stmp = M_pop_mul_int(); +itmp = M_pop_mul_int(); + +fmul_t0 = mul_stack_data[itmp+6]; + +/* + * if the sign of (A1 - A0)(B0 - B1) is positive, ADD to + * the result. if it is negative, SUBTRACT from the result. + */ + +if (stmp < 0) + { + fmul_a9 = mul_stack_data[itmp+2]; + fmul_b9 = mul_stack_data[itmp+5]; + + memset(fmul_b9, 0, (2 * sz)); + memcpy((fmul_b9 + mii), fmul_t0, sz); + M_fmul_subtract(fmul_a9, rr, fmul_b9, (2 * sz)); + memcpy(rr, fmul_a9, (2 * sz)); + } + +if (stmp > 0) + M_fmul_add(rr, fmul_t0, mii, sz); + +M_mul_stack_ptr -= 7; +} +/****************************************************************************/ +/* + * special addition function for use with the fast multiply operation + */ +void M_fmul_add(UCHAR *r, UCHAR *a, int offset, int sz) +{ +int i, j; +UCHAR carry; + +carry = 0; +j = offset + sz; +i = sz; + +while (TRUE) + { + r[--j] += carry + a[--i]; + + if (r[j] >= 100) + { + r[j] -= 100; + carry = 1; + } + else + carry = 0; + + if (i == 0) + break; + } + +if (carry) + { + while (TRUE) + { + r[--j] += 1; + + if (r[j] < 100) + break; + + r[j] -= 100; + } + } +} +/****************************************************************************/ +/* + * special subtraction function for use with the fast multiply operation + */ +int M_fmul_subtract(UCHAR *r, UCHAR *a, UCHAR *b, int sz) +{ +int k, jtmp, sflag, nb, borrow; + +nb = sz; +sflag = 0; /* sign flag: assume the numbers are equal */ + +/* + * find if a > b (so we perform a-b) + * or a < b (so we perform b-a) + */ + +for (k=0; k < nb; k++) + { + if (a[k] < b[k]) + { + sflag = -1; + break; + } + + if (a[k] > b[k]) + { + sflag = 1; + break; + } + } + +if (sflag == 0) + { + memset(r, 0, nb); /* zero out the result */ + } +else + { + k = nb; + borrow = 0; + + while (TRUE) + { + k--; + + if (sflag == 1) + jtmp = (int)a[k] - ((int)b[k] + borrow); + else + jtmp = (int)b[k] - ((int)a[k] + borrow); + + if (jtmp >= 0) + { + r[k] = (UCHAR)jtmp; + borrow = 0; + } + else + { + r[k] = (UCHAR)(100 + jtmp); + borrow = 1; + } + + if (k == 0) + break; + } + } + +return(sflag); +} +/****************************************************************************/ +int M_next_power_of_2(int n) +{ +int ct, k; + +if (n <= 2) + return(n); + +k = 2; +ct = 0; + +while (TRUE) + { + if (k >= n) + break; + + k = k << 1; + + if (++ct == bit_limit) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, + "\'M_next_power_of_2\', ERROR :sizeof(int) too small ??"); + } + } + +return(k); +} +/****************************************************************************/ +int M_get_stack_ptr(int sz) +{ +int i, k; +UCHAR *cp; + +k = ++M_mul_stack_ptr; + +/* if size is 0, just need to malloc and return */ +if (mul_stack_data_size[k] == 0) + { + if ((i = sz) < 16) + i = 16; + + if ((cp = (UCHAR *)MAPM_MALLOC(i + 4)) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_stack_ptr_error_msg); + } + + mul_stack_data[k] = cp; + mul_stack_data_size[k] = i; + } +else /* it has been malloc'ed, see if it's big enough */ + { + if (sz > mul_stack_data_size[k]) + { + cp = mul_stack_data[k]; + + if ((cp = (UCHAR *)MAPM_REALLOC(cp, (sz + 4))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_stack_ptr_error_msg); + } + + mul_stack_data[k] = cp; + mul_stack_data_size[k] = sz; + } + } + +return(k); +} +/****************************************************************************/ + +#ifdef NO_FFT_MULTIPLY + +/* + * multiply a 4 byte number by a 4 byte number + * yielding an 8 byte result. each byte contains + * a base 100 'digit', i.e.: range from 0-99. + * + * MSB LSB + * + * a,b [0] [1] [2] [3] + * result [0] ..... [7] + */ + +void M_4_byte_multiply(UCHAR *r, UCHAR *a, UCHAR *b) +{ +int jj; +unsigned int *ip, t1, rr[8]; + +memset(rr, 0, (8 * sizeof(int))); /* zero out result */ +jj = 3; +ip = rr + 5; + +/* + * loop for one number [b], un-roll the inner 'loop' [a] + * + * accumulate partial sums in UINT array, release carries + * and convert back to base 100 at the end + */ + +while (1) + { + t1 = (unsigned int)b[jj]; + ip += 2; + + *ip-- += t1 * a[3]; + *ip-- += t1 * a[2]; + *ip-- += t1 * a[1]; + *ip += t1 * a[0]; + + if (jj-- == 0) + break; + } + +jj = 7; + +while (1) + { + t1 = rr[jj] / 100; + r[jj] = (UCHAR)(rr[jj] - 100 * t1); + + if (jj == 0) + break; + + rr[--jj] += t1; + } +} + +#endif + +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmgues.c b/src/apps/deskcalc/mapm_4.9.5/mapmgues.c new file mode 100644 index 0000000000..3a9f257770 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmgues.c @@ -0,0 +1,209 @@ + +/* + * M_APM - mapmgues.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmgues.c,v 1.20 2007/12/03 01:52:55 mike Exp $ + * + * This file contains the functions that generate the initial + * 'guesses' for the sqrt, cbrt, log, arcsin, and arccos functions. + * + * $Log: mapmgues.c,v $ + * Revision 1.20 2007/12/03 01:52:55 mike + * Update license + * + * Revision 1.19 2003/07/21 20:03:49 mike + * check for invalid inputs to _set_double + * + * Revision 1.18 2003/05/01 21:58:45 mike + * remove math.h + * + * Revision 1.17 2003/04/16 16:52:47 mike + * change cbrt guess to use reciprocal value for new cbrt algorithm + * + * Revision 1.16 2003/04/11 14:18:13 mike + * add comments + * + * Revision 1.15 2003/04/10 22:28:35 mike + * . + * + * Revision 1.14 2003/04/09 21:33:19 mike + * induce same error for asin and acos + * + * Revision 1.13 2003/04/09 20:11:38 mike + * induce error of 10 ^ -5 in log guess for known starting + * point in the iterative algorithm + * + * Revision 1.12 2003/03/27 19:32:59 mike + * simplify log guess since caller guarantee's limited input magnitude + * + * Revision 1.11 2002/11/03 21:45:53 mike + * Updated function parameters to use the modern style + * + * Revision 1.10 2001/03/20 22:08:27 mike + * delete unneeded logic in asin guess + * + * Revision 1.9 2000/09/26 17:05:11 mike + * guess 1/sqrt instead of sqrt due to new sqrt algorithm + * + * Revision 1.8 2000/04/10 21:13:13 mike + * minor tweaks to log_guess + * + * Revision 1.7 2000/04/03 17:25:45 mike + * added function to estimate the cube root (cbrt) + * + * Revision 1.6 1999/07/18 01:57:35 mike + * adjust arc-sin guess for small exponents + * + * Revision 1.5 1999/07/09 22:32:50 mike + * optimize some functions + * + * Revision 1.4 1999/05/12 21:22:27 mike + * add more comments + * + * Revision 1.3 1999/05/12 21:00:51 mike + * added new sqrt guess function + * + * Revision 1.2 1999/05/11 02:10:12 mike + * added some comments + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void M_get_sqrt_guess(M_APM r, M_APM a) +{ +char buf[48]; +double dd; + +m_apm_to_string(buf, 15, a); +dd = atof(buf); /* sqrt algorithm actually finds 1/sqrt */ +m_apm_set_double(r, (1.0 / sqrt(dd))); +} +/****************************************************************************/ +/* + * for cbrt, log, asin, and acos we induce an error of 10 ^ -5. + * this enables the iterative routine to be more efficient + * by knowing exactly how accurate the initial guess is. + * + * this also prevents some corner conditions where the iterative + * functions may terminate too soon. + */ +/****************************************************************************/ +void M_get_cbrt_guess(M_APM r, M_APM a) +{ +char buf[48]; +double dd; + +m_apm_to_string(buf, 15, a); +dd = atof(buf); +dd = log(dd) / 3.0; /* cbrt algorithm actually finds 1/cbrt */ +m_apm_set_double(r, (1.00001 / exp(dd))); +} +/****************************************************************************/ +void M_get_log_guess(M_APM r, M_APM a) +{ +char buf[48]; +double dd; + +m_apm_to_string(buf, 15, a); +dd = atof(buf); +m_apm_set_double(r, (1.00001 * log(dd))); /* induce error of 10 ^ -5 */ +} +/****************************************************************************/ +/* + * the implementation of the asin & acos functions + * guarantee that 'a' is always < 0.85, so it is + * safe to multiply by a number > 1 + */ +void M_get_asin_guess(M_APM r, M_APM a) +{ +char buf[48]; +double dd; + +m_apm_to_string(buf, 15, a); +dd = atof(buf); +m_apm_set_double(r, (1.00001 * asin(dd))); /* induce error of 10 ^ -5 */ +} +/****************************************************************************/ +void M_get_acos_guess(M_APM r, M_APM a) +{ +char buf[48]; +double dd; + +m_apm_to_string(buf, 15, a); +dd = atof(buf); +m_apm_set_double(r, (1.00001 * acos(dd))); /* induce error of 10 ^ -5 */ +} +/****************************************************************************/ +/* + convert a C 'double' into an M_APM value. +*/ +void m_apm_set_double(M_APM atmp, double dd) +{ +char *cp, *p, *ps, buf[64]; + +if (dd == 0.0) /* special case for 0 exactly */ + M_set_to_zero(atmp); +else + { + sprintf(buf, "%.14E", dd); + + if ((cp = strstr(buf, "E")) == NULL) + { + M_apm_log_error_msg(M_APM_RETURN, + "\'m_apm_set_double\', Invalid double input (likely a NAN or +/- INF)"); + + M_set_to_zero(atmp); + return; + } + + if (atoi(cp + sizeof(char)) == 0) + *cp = '\0'; + + p = cp; + + while (TRUE) + { + p--; + if (*p == '0' || *p == '.') + *p = ' '; + else + break; + } + + ps = buf; + p = buf; + + while (TRUE) + { + if ((*p = *ps) == '\0') + break; + + if (*ps++ != ' ') + p++; + } + + m_apm_set_string(atmp, buf); + } +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmhasn.c b/src/apps/deskcalc/mapm_4.9.5/mapmhasn.c new file mode 100644 index 0000000000..99aae88c33 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmhasn.c @@ -0,0 +1,155 @@ + +/* + * M_APM - mapmhasn.c + * + * Copyright (C) 2000 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmhasn.c,v 1.7 2007/12/03 01:53:33 mike Exp $ + * + * This file contains the Inverse Hyperbolic SIN, COS, & TAN functions. + * + * $Log: mapmhasn.c,v $ + * Revision 1.7 2007/12/03 01:53:33 mike + * Update license + * + * Revision 1.6 2003/07/24 16:28:50 mike + * update arcsinh + * + * Revision 1.5 2003/07/23 23:08:27 mike + * fix problem with arcsinh when input is a very large + * negative number. + * + * Revision 1.4 2003/07/21 20:36:33 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.3 2003/03/31 21:53:21 mike + * call generic error handling function + * + * Revision 1.2 2002/11/03 21:25:03 mike + * Updated function parameters to use the modern style + * + * Revision 1.1 2000/04/03 18:16:29 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + * arcsinh(x) == log [ x + sqrt(x^2 + 1) ] + * + * also, use arcsinh(-x) == -arcsinh(x) + */ +void m_apm_arcsinh(M_APM rr, int places, M_APM aa) +{ +M_APM tmp0, tmp1, tmp2; + +/* result is 0 if input is 0 */ + +if (aa->m_apm_sign == 0) + { + M_set_to_zero(rr); + return; + } + +tmp0 = M_get_stack_var(); +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +m_apm_absolute_value(tmp0, aa); +m_apm_multiply(tmp1, tmp0, tmp0); +m_apm_add(tmp2, tmp1, MM_One); +m_apm_sqrt(tmp1, (places + 6), tmp2); +m_apm_add(tmp2, tmp0, tmp1); +m_apm_log(rr, places, tmp2); + +rr->m_apm_sign = aa->m_apm_sign; /* fix final sign */ + +M_restore_stack(3); +} +/****************************************************************************/ +/* + * arccosh(x) == log [ x + sqrt(x^2 - 1) ] + * + * x >= 1.0 + */ +void m_apm_arccosh(M_APM rr, int places, M_APM aa) +{ +M_APM tmp1, tmp2; +int ii; + +ii = m_apm_compare(aa, MM_One); + +if (ii == -1) /* x < 1 */ + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_arccosh\', Argument < 1"); + M_set_to_zero(rr); + return; + } + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); + +m_apm_multiply(tmp1, aa, aa); +m_apm_subtract(tmp2, tmp1, MM_One); +m_apm_sqrt(tmp1, (places + 6), tmp2); +m_apm_add(tmp2, aa, tmp1); +m_apm_log(rr, places, tmp2); + +M_restore_stack(2); +} +/****************************************************************************/ +/* + * arctanh(x) == 0.5 * log [ (1 + x) / (1 - x) ] + * + * |x| < 1.0 + */ +void m_apm_arctanh(M_APM rr, int places, M_APM aa) +{ +M_APM tmp1, tmp2, tmp3; +int ii, local_precision; + +tmp1 = M_get_stack_var(); + +m_apm_absolute_value(tmp1, aa); + +ii = m_apm_compare(tmp1, MM_One); + +if (ii >= 0) /* |x| >= 1.0 */ + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_arctanh\', |Argument| >= 1"); + M_set_to_zero(rr); + M_restore_stack(1); + return; + } + +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); + +local_precision = places + 8; + +m_apm_add(tmp1, MM_One, aa); +m_apm_subtract(tmp2, MM_One, aa); +m_apm_divide(tmp3, local_precision, tmp1, tmp2); +m_apm_log(tmp2, local_precision, tmp3); +m_apm_multiply(tmp1, tmp2, MM_0_5); +m_apm_round(rr, places, tmp1); + +M_restore_stack(3); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmhsin.c b/src/apps/deskcalc/mapm_4.9.5/mapmhsin.c new file mode 100644 index 0000000000..db715249cb --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmhsin.c @@ -0,0 +1,113 @@ + +/* + * M_APM - mapmhsin.c + * + * Copyright (C) 2000 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmhsin.c,v 1.4 2007/12/03 01:54:06 mike Exp $ + * + * This file contains the Hyperbolic SIN, COS, & TAN functions. + * + * $Log: mapmhsin.c,v $ + * Revision 1.4 2007/12/03 01:54:06 mike + * Update license + * + * Revision 1.3 2002/11/03 21:29:20 mike + * Updated function parameters to use the modern style + * + * Revision 1.2 2000/09/23 19:52:56 mike + * change divide call to reciprocal + * + * Revision 1.1 2000/04/03 18:16:26 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + * sinh(x) == 0.5 * [ exp(x) - exp(-x) ] + */ +void m_apm_sinh(M_APM rr, int places, M_APM aa) +{ +M_APM tmp1, tmp2, tmp3; +int local_precision; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); + +local_precision = places + 4; + +m_apm_exp(tmp1, local_precision, aa); +m_apm_reciprocal(tmp2, local_precision, tmp1); +m_apm_subtract(tmp3, tmp1, tmp2); +m_apm_multiply(tmp1, tmp3, MM_0_5); +m_apm_round(rr, places, tmp1); + +M_restore_stack(3); +} +/****************************************************************************/ +/* + * cosh(x) == 0.5 * [ exp(x) + exp(-x) ] + */ +void m_apm_cosh(M_APM rr, int places, M_APM aa) +{ +M_APM tmp1, tmp2, tmp3; +int local_precision; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); + +local_precision = places + 4; + +m_apm_exp(tmp1, local_precision, aa); +m_apm_reciprocal(tmp2, local_precision, tmp1); +m_apm_add(tmp3, tmp1, tmp2); +m_apm_multiply(tmp1, tmp3, MM_0_5); +m_apm_round(rr, places, tmp1); + +M_restore_stack(3); +} +/****************************************************************************/ +/* + * tanh(x) == [ exp(x) - exp(-x) ] / [ exp(x) + exp(-x) ] + */ +void m_apm_tanh(M_APM rr, int places, M_APM aa) +{ +M_APM tmp1, tmp2, tmp3, tmp4; +int local_precision; + +tmp1 = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp3 = M_get_stack_var(); +tmp4 = M_get_stack_var(); + +local_precision = places + 4; + +m_apm_exp(tmp1, local_precision, aa); +m_apm_reciprocal(tmp2, local_precision, tmp1); +m_apm_subtract(tmp3, tmp1, tmp2); +m_apm_add(tmp4, tmp1, tmp2); +m_apm_divide(tmp1, local_precision, tmp3, tmp4); +m_apm_round(rr, places, tmp1); + +M_restore_stack(4); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmipwr.c b/src/apps/deskcalc/mapm_4.9.5/mapmipwr.c new file mode 100644 index 0000000000..e761ff2bce --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmipwr.c @@ -0,0 +1,117 @@ + +/* + * M_APM - mapmipwr.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmipwr.c,v 1.6 2007/12/03 01:54:39 mike Exp $ + * + * This file contains the Integer Power function. + * + * $Log: mapmipwr.c,v $ + * Revision 1.6 2007/12/03 01:54:39 mike + * Update license + * + * Revision 1.5 2002/11/03 21:10:32 mike + * Updated function parameters to use the modern style + * + * Revision 1.4 2000/09/23 19:46:04 mike + * change divide call to reciprocal + * + * Revision 1.3 2000/05/24 17:03:35 mike + * return 1 when input is 0^0 + * + * Revision 1.2 1999/09/18 01:34:35 mike + * minor tweaks + * + * Revision 1.1 1999/09/18 01:33:09 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_integer_pow(M_APM rr, int places, M_APM aa, int mexp) +{ +M_APM tmp0, tmpy, tmpz; +int nexp, ii, signflag, local_precision; + +if (mexp == 0) + { + m_apm_copy(rr, MM_One); + return; + } +else + { + if (mexp > 0) + { + signflag = 0; + nexp = mexp; + } + else + { + signflag = 1; + nexp = -mexp; + } + } + +if (aa->m_apm_sign == 0) + { + M_set_to_zero(rr); + return; + } + +tmp0 = M_get_stack_var(); +tmpy = M_get_stack_var(); +tmpz = M_get_stack_var(); + +local_precision = places + 8; + +m_apm_copy(tmpy, MM_One); +m_apm_copy(tmpz, aa); + +while (TRUE) + { + ii = nexp & 1; + nexp = nexp >> 1; + + if (ii != 0) /* exponent -was- odd */ + { + m_apm_multiply(tmp0, tmpy, tmpz); + m_apm_round(tmpy, local_precision, tmp0); + + if (nexp == 0) + break; + } + + m_apm_multiply(tmp0, tmpz, tmpz); + m_apm_round(tmpz, local_precision, tmp0); + } + +if (signflag) + { + m_apm_reciprocal(rr, places, tmpy); + } +else + { + m_apm_round(rr, places, tmpy); + } + +M_restore_stack(3); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmistr.c b/src/apps/deskcalc/mapm_4.9.5/mapmistr.c new file mode 100644 index 0000000000..ee50fd5acf --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmistr.c @@ -0,0 +1,140 @@ + +/* + * M_APM - mapmistr.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmistr.c,v 1.9 2007/12/03 01:55:27 mike Exp $ + * + * This file contains M_APM -> integer string function + * + * $Log: mapmistr.c,v $ + * Revision 1.9 2007/12/03 01:55:27 mike + * Update license + * + * Revision 1.8 2003/07/21 20:37:09 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.7 2003/03/31 21:52:07 mike + * call generic error handling function + * + * Revision 1.6 2002/11/03 22:28:02 mike + * Updated function parameters to use the modern style + * + * Revision 1.5 2001/08/06 16:58:20 mike + * improve the new function + * + * Revision 1.4 2001/08/05 23:18:48 mike + * fix function when input is not an integer but the + * number is close to rounding upwards (NNN.9999999999....) + * + * Revision 1.3 2000/02/03 22:48:38 mike + * use MAPM_* generic memory function + * + * Revision 1.2 1999/07/18 01:33:04 mike + * minor tweak to code alignment + * + * Revision 1.1 1999/07/12 02:06:08 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_to_integer_string(char *s, M_APM mtmp) +{ +void *vp; +UCHAR *ucp, numdiv, numrem; +char *cp, *p, sbuf[128]; +int ct, dl, numb, ii; + +vp = NULL; +ct = mtmp->m_apm_exponent; +dl = mtmp->m_apm_datalength; + +/* + * if |input| < 1, result is "0" + */ + +if (ct <= 0 || mtmp->m_apm_sign == 0) + { + s[0] = '0'; + s[1] = '\0'; + return; + } + +if (ct > 112) + { + if ((vp = (void *)MAPM_MALLOC((ct + 32) * sizeof(char))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, + "\'m_apm_to_integer_string\', Out of memory"); + } + + cp = (char *)vp; + } +else + { + cp = sbuf; + } + +p = cp; +ii = 0; + +/* handle a negative number */ + +if (mtmp->m_apm_sign == -1) + { + ii = 1; + *p++ = '-'; + } + +/* get num-bytes of data (#digits / 2) to use in the string */ + +if (ct > dl) + numb = (dl + 1) >> 1; +else + numb = (ct + 1) >> 1; + +ucp = mtmp->m_apm_data; + +while (TRUE) + { + M_get_div_rem_10((int)(*ucp++), &numdiv, &numrem); + + *p++ = numdiv + '0'; + *p++ = numrem + '0'; + + if (--numb == 0) + break; + } + +/* pad with trailing zeros if the exponent > datalength */ + +if (ct > dl) + memset(p, '0', (ct + 1 - dl)); + +cp[ct + ii] = '\0'; +strcpy(s, cp); + +if (vp != NULL) + MAPM_FREE(vp); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmpwr2.c b/src/apps/deskcalc/mapm_4.9.5/mapmpwr2.c new file mode 100644 index 0000000000..a05b065f2f --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmpwr2.c @@ -0,0 +1,120 @@ + +/* + * M_APM - mapmpwr2.c + * + * Copyright (C) 2002 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmpwr2.c,v 1.4 2007/12/03 01:56:21 mike Exp $ + * + * This file contains the Integer Power function and the result + * is NOT ROUNDED. The exponent must be an integer >= zero. + * + * This will typically be used in an application where full integer + * precision is required to be maintained. + * + * $Log: mapmpwr2.c,v $ + * Revision 1.4 2007/12/03 01:56:21 mike + * Update license + * + * Revision 1.3 2003/07/21 20:38:06 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.2 2003/03/31 21:51:23 mike + * call generic error handling function + * + * Revision 1.1 2002/11/03 21:02:04 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_integer_pow_nr(M_APM rr, M_APM aa, int mexp) +{ +M_APM tmp0, tmpy, tmpz; +int nexp, ii; + +if (mexp == 0) + { + m_apm_copy(rr, MM_One); + return; + } +else + { + if (mexp < 0) + { + M_apm_log_error_msg(M_APM_RETURN, + "\'m_apm_integer_pow_nr\', Negative exponent"); + + M_set_to_zero(rr); + return; + } + } + +if (mexp == 1) + { + m_apm_copy(rr, aa); + return; + } + +if (mexp == 2) + { + m_apm_multiply(rr, aa, aa); + return; + } + +nexp = mexp; + +if (aa->m_apm_sign == 0) + { + M_set_to_zero(rr); + return; + } + +tmp0 = M_get_stack_var(); +tmpy = M_get_stack_var(); +tmpz = M_get_stack_var(); + +m_apm_copy(tmpy, MM_One); +m_apm_copy(tmpz, aa); + +while (TRUE) + { + ii = nexp & 1; + nexp = nexp >> 1; + + if (ii != 0) /* exponent -was- odd */ + { + m_apm_multiply(tmp0, tmpy, tmpz); + + if (nexp == 0) + break; + + m_apm_copy(tmpy, tmp0); + } + + m_apm_multiply(tmp0, tmpz, tmpz); + m_apm_copy(tmpz, tmp0); + } + +m_apm_copy(rr, tmp0); + +M_restore_stack(3); +} +/****************************************************************************/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmrsin.c b/src/apps/deskcalc/mapm_4.9.5/mapmrsin.c new file mode 100644 index 0000000000..48d310b2ce --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmrsin.c @@ -0,0 +1,191 @@ + +/* + * M_APM - mapmrsin.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmrsin.c,v 1.8 2007/12/03 01:57:00 mike Exp $ + * + * This file contains the basic series expansion functions for + * the SIN / COS functions. + * + * $Log: mapmrsin.c,v $ + * Revision 1.8 2007/12/03 01:57:00 mike + * Update license + * + * Revision 1.7 2003/06/08 18:22:09 mike + * optimize the raw sin algorithm + * + * Revision 1.6 2002/11/03 21:58:27 mike + * Updated function parameters to use the modern style + * + * Revision 1.5 2001/07/10 22:14:43 mike + * optimize raw_sin & cos by using fewer digits + * as subsequent terms get smaller + * + * Revision 1.4 2000/03/30 21:53:48 mike + * change compare to terminate series expansion using ints instead + * of MAPM numbers + * + * Revision 1.3 1999/06/20 16:23:10 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.2 1999/05/12 21:06:36 mike + * changed global var names + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +/* + x^3 x^5 x^7 x^9 + sin(x) = x - --- + --- - --- + --- ... + 3! 5! 7! 9! +*/ +void M_raw_sin(M_APM rr, int places, M_APM xx) +{ +M_APM sum, term, tmp2, tmp7, tmp8; +int tolerance, flag, local_precision, dplaces; +long m1, m2; + +sum = M_get_stack_var(); +term = M_get_stack_var(); +tmp2 = M_get_stack_var(); +tmp7 = M_get_stack_var(); +tmp8 = M_get_stack_var(); + +m_apm_copy(sum, xx); +m_apm_copy(term, xx); +m_apm_multiply(tmp8, xx, xx); +m_apm_round(tmp2, (places + 6), tmp8); + +dplaces = (places + 8) - xx->m_apm_exponent; +tolerance = xx->m_apm_exponent - (places + 4); + +m1 = 2L; +flag = 0; + +while (TRUE) + { + m_apm_multiply(tmp8, term, tmp2); + + if ((tmp8->m_apm_exponent < tolerance) || (tmp8->m_apm_sign == 0)) + break; + + local_precision = dplaces + term->m_apm_exponent; + + if (local_precision < 20) + local_precision = 20; + + m2 = m1 * (m1 + 1); + m_apm_set_long(tmp7, m2); + + m_apm_divide(term, local_precision, tmp8, tmp7); + + if (flag == 0) + { + m_apm_subtract(tmp7, sum, term); + m_apm_copy(sum, tmp7); + } + else + { + m_apm_add(tmp7, sum, term); + m_apm_copy(sum, tmp7); + } + + m1 += 2; + flag = 1 - flag; + } + +m_apm_round(rr, places, sum); +M_restore_stack(5); +} +/****************************************************************************/ +/* + x^2 x^4 x^6 x^8 + cos(x) = 1 - --- + --- - --- + --- ... + 2! 4! 6! 8! +*/ +void M_raw_cos(M_APM rr, int places, M_APM xx) +{ +M_APM sum, term, tmp7, tmp8, tmp9; +int tolerance, flag, local_precision, prev_exp; +long m1, m2; + +sum = M_get_stack_var(); +term = M_get_stack_var(); +tmp7 = M_get_stack_var(); +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +m_apm_copy(sum, MM_One); +m_apm_copy(term, MM_One); + +m_apm_multiply(tmp8, xx, xx); +m_apm_round(tmp9, (places + 6), tmp8); + +local_precision = places + 8; +tolerance = -(places + 4); +prev_exp = 0; + +m1 = 1L; +flag = 0; + +while (TRUE) + { + m2 = m1 * (m1 + 1); + m_apm_set_long(tmp7, m2); + + m_apm_multiply(tmp8, term, tmp9); + m_apm_divide(term, local_precision, tmp8, tmp7); + + if (flag == 0) + { + m_apm_subtract(tmp7, sum, term); + m_apm_copy(sum, tmp7); + } + else + { + m_apm_add(tmp7, sum, term); + m_apm_copy(sum, tmp7); + } + + if ((term->m_apm_exponent < tolerance) || (term->m_apm_sign == 0)) + break; + + if (m1 != 1L) + { + local_precision = local_precision + term->m_apm_exponent - prev_exp; + + if (local_precision < 20) + local_precision = 20; + } + + prev_exp = term->m_apm_exponent; + + m1 += 2; + flag = 1 - flag; + } + +m_apm_round(rr, places, sum); +M_restore_stack(5); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmsqrt.c b/src/apps/deskcalc/mapm_4.9.5/mapmsqrt.c new file mode 100644 index 0000000000..4394e73eac --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmsqrt.c @@ -0,0 +1,190 @@ + +/* + * M_APM - mapmsqrt.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmsqrt.c,v 1.19 2007/12/03 01:57:31 mike Exp $ + * + * This file contains the SQRT function. + * + * $Log: mapmsqrt.c,v $ + * Revision 1.19 2007/12/03 01:57:31 mike + * Update license + * + * Revision 1.18 2003/07/21 20:39:00 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.17 2003/05/07 16:36:04 mike + * simplify 'nexp' logic + * + * Revision 1.16 2003/03/31 21:50:14 mike + * call generic error handling function + * + * Revision 1.15 2003/03/11 21:29:00 mike + * round an intermediate result for faster runtime. + * + * Revision 1.14 2002/11/03 22:00:46 mike + * Updated function parameters to use the modern style + * + * Revision 1.13 2001/07/10 22:50:31 mike + * minor optimization + * + * Revision 1.12 2000/09/26 18:32:04 mike + * use new algorithm which only uses multiply and subtract + * (avoids the slower version which used division) + * + * Revision 1.11 2000/07/11 17:56:22 mike + * make better estimate for initial precision + * + * Revision 1.10 1999/07/21 02:48:45 mike + * added some comments + * + * Revision 1.9 1999/07/19 00:25:44 mike + * adjust local precision again + * + * Revision 1.8 1999/07/19 00:09:41 mike + * adjust local precision during loop + * + * Revision 1.7 1999/07/18 22:57:08 mike + * change to dynamically changing local precision and + * change tolerance checks using integers + * + * Revision 1.6 1999/06/19 21:18:00 mike + * changed local static variables to MAPM stack variables + * + * Revision 1.5 1999/05/31 01:40:39 mike + * minor update to normalizing the exponent + * + * Revision 1.4 1999/05/31 01:21:41 mike + * optimize for large exponents + * + * Revision 1.3 1999/05/12 20:59:35 mike + * use a better 'guess' function + * + * Revision 1.2 1999/05/10 21:15:26 mike + * added some comments + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void m_apm_sqrt(M_APM rr, int places, M_APM aa) +{ +M_APM last_x, guess, tmpN, tmp7, tmp8, tmp9; +int ii, bflag, nexp, tolerance, dplaces; + +if (aa->m_apm_sign <= 0) + { + if (aa->m_apm_sign == -1) + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_sqrt\', Negative argument"); + } + + M_set_to_zero(rr); + return; + } + +last_x = M_get_stack_var(); +guess = M_get_stack_var(); +tmpN = M_get_stack_var(); +tmp7 = M_get_stack_var(); +tmp8 = M_get_stack_var(); +tmp9 = M_get_stack_var(); + +m_apm_copy(tmpN, aa); + +/* + normalize the input number (make the exponent near 0) so + the 'guess' function will not over/under flow on large + magnitude exponents. +*/ + +nexp = aa->m_apm_exponent / 2; +tmpN->m_apm_exponent -= 2 * nexp; + +M_get_sqrt_guess(guess, tmpN); /* actually gets 1/sqrt guess */ + +tolerance = places + 4; +dplaces = places + 16; +bflag = FALSE; + +m_apm_negate(last_x, MM_Ten); + +/* Use the following iteration to calculate 1 / sqrt(N) : + + X = 0.5 * X * [ 3 - N * X^2 ] + n+1 +*/ + +ii = 0; + +while (TRUE) + { + m_apm_multiply(tmp9, tmpN, guess); + m_apm_multiply(tmp8, tmp9, guess); + m_apm_round(tmp7, dplaces, tmp8); + m_apm_subtract(tmp9, MM_Three, tmp7); + m_apm_multiply(tmp8, tmp9, guess); + m_apm_multiply(tmp9, tmp8, MM_0_5); + + if (bflag) + break; + + m_apm_round(guess, dplaces, tmp9); + + /* force at least 2 iterations so 'last_x' has valid data */ + + if (ii != 0) + { + m_apm_subtract(tmp7, guess, last_x); + + if (tmp7->m_apm_sign == 0) + break; + + /* + * if we are within a factor of 4 on the error term, + * we will be accurate enough after the *next* iteration + * is complete. (note that the sign of the exponent on + * the error term will be a negative number). + */ + + if ((-4 * tmp7->m_apm_exponent) > tolerance) + bflag = TRUE; + } + + m_apm_copy(last_x, guess); + ii++; + } + +/* + * multiply by the starting number to get the final + * sqrt and then adjust the exponent since we found + * the sqrt of the normalized number. + */ + +m_apm_multiply(tmp8, tmp9, tmpN); +m_apm_round(rr, places, tmp8); +rr->m_apm_exponent += nexp; + +M_restore_stack(6); +} +/****************************************************************************/ diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmstck.c b/src/apps/deskcalc/mapm_4.9.5/mapmstck.c new file mode 100644 index 0000000000..e2c50e837b --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmstck.c @@ -0,0 +1,142 @@ + +/* + * M_APM - mapmstck.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmstck.c,v 1.11 2007/12/03 01:58:05 mike Exp $ + * + * This file contains the stack implementation for using + * local M_APM variables. + * + * $Log: mapmstck.c,v $ + * Revision 1.11 2007/12/03 01:58:05 mike + * Update license + * + * Revision 1.10 2003/07/21 20:39:38 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.9 2003/03/31 21:49:08 mike + * call generic error handling function + * + * Revision 1.8 2002/11/03 22:42:05 mike + * Updated function parameters to use the modern style + * + * Revision 1.7 2002/05/17 22:05:00 mike + * the stack is now dynamically allocated and will grow + * at run-time if needed + * + * Revision 1.6 2001/07/16 19:47:04 mike + * add function M_free_all_stck + * + * Revision 1.5 2000/09/23 19:27:52 mike + * increase stack size for new functionality + * + * Revision 1.4 1999/07/09 00:04:47 mike + * tweak stack again + * + * Revision 1.3 1999/07/09 00:02:24 mike + * increase stack size for new functions + * + * Revision 1.2 1999/06/20 21:13:18 mike + * comment out printf debug and set max stack depth + * + * Revision 1.1 1999/06/19 20:32:43 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static int M_stack_ptr = -1; +static int M_last_init = -1; +static int M_stack_size = 0; + +static char *M_stack_err_msg = "\'M_get_stack_var\', Out of memory"; + +static M_APM *M_stack_array; + +/****************************************************************************/ +void M_free_all_stck() +{ +int k; + +if (M_last_init >= 0) + { + for (k=0; k <= M_last_init; k++) + m_apm_free(M_stack_array[k]); + + M_stack_ptr = -1; + M_last_init = -1; + M_stack_size = 0; + + MAPM_FREE(M_stack_array); + } +} +/****************************************************************************/ +M_APM M_get_stack_var() +{ +void *vp; + +if (++M_stack_ptr > M_last_init) + { + if (M_stack_size == 0) + { + M_stack_size = 18; + if ((vp = MAPM_MALLOC(M_stack_size * sizeof(M_APM))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_stack_err_msg); + } + + M_stack_array = (M_APM *)vp; + } + + if ((M_last_init + 4) >= M_stack_size) + { + M_stack_size += 12; + if ((vp = MAPM_REALLOC(M_stack_array, + (M_stack_size * sizeof(M_APM)))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_stack_err_msg); + } + + M_stack_array = (M_APM *)vp; + } + + M_stack_array[M_stack_ptr] = m_apm_init(); + M_stack_array[M_stack_ptr + 1] = m_apm_init(); + M_stack_array[M_stack_ptr + 2] = m_apm_init(); + M_stack_array[M_stack_ptr + 3] = m_apm_init(); + + M_last_init = M_stack_ptr + 3; + + /* printf("M_last_init = %d \n",M_last_init); */ + } + +return(M_stack_array[M_stack_ptr]); +} +/****************************************************************************/ +void M_restore_stack(int count) +{ +M_stack_ptr -= count; +} +/****************************************************************************/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmutil.c b/src/apps/deskcalc/mapm_4.9.5/mapmutil.c new file mode 100644 index 0000000000..443ea8fbc6 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmutil.c @@ -0,0 +1,555 @@ + +/* + * M_APM - mapmutil.c + * + * Copyright (C) 1999 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmutil.c,v 1.26 2007/12/03 01:58:49 mike Exp $ + * + * This file contains various utility functions needed by the + * library in addition to some basic user callable functions. + * + * $Log: mapmutil.c,v $ + * Revision 1.26 2007/12/03 01:58:49 mike + * Update license + * + * Revision 1.25 2003/07/21 20:51:34 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.24 2003/03/31 22:03:54 mike + * call generic error handling function + * + * Revision 1.23 2002/11/04 20:47:02 mike + * change m_apm_init so it compiles clean with a real C++ compiler + * + * Revision 1.22 2002/11/03 22:50:58 mike + * Updated function parameters to use the modern style + * + * Revision 1.21 2002/05/17 22:26:49 mike + * move some functions into another file + * + * Revision 1.20 2002/02/12 20:21:53 mike + * eliminate unneeded working arrays in _scale + * by processing the scaling operation in reverse + * + * Revision 1.19 2001/07/24 18:29:18 mike + * add util function to get address of + * the div/rem lookup tables + * + * Revision 1.18 2001/07/20 16:14:05 mike + * optimize normalize yet again + * + * Revision 1.17 2001/07/17 18:17:56 mike + * another optimization to _normalize + * + * Revision 1.16 2001/07/16 22:33:43 mike + * update free_all_util + * + * Revision 1.15 2001/07/16 19:56:26 mike + * add function M_free_all_util + * + * Revision 1.14 2001/07/16 18:10:21 mike + * optimize M_apm_normalize when moving multiple '00' bytes + * + * Revision 1.13 2001/02/11 22:36:43 mike + * modify parameters to REALLOC + * + * Revision 1.12 2001/01/23 21:17:38 mike + * add dedicated long->ascii conversion (instead of sprintf) + * + * Revision 1.11 2000/08/22 20:21:54 mike + * fix m_apm_exponent with exactly 0 as the input + * + * Revision 1.10 2000/08/22 00:01:26 mike + * add zero check in is_integer + * + * Revision 1.9 2000/08/21 23:34:44 mike + * add new function _is_integer + * + * Revision 1.8 2000/08/01 22:29:02 mike + * add sizeof int function call + * + * Revision 1.7 2000/05/19 16:21:03 mike + * delete M_check_dec_places, no longer needed + * + * Revision 1.6 2000/04/04 17:06:37 mike + * initialize C++ refcount struct element to 1 + * + * Revision 1.5 2000/02/03 22:49:56 mike + * use MAPM_* generic memory function + * + * Revision 1.4 1999/09/18 03:06:41 mike + * fix m_apm_exponent + * + * Revision 1.3 1999/09/18 02:59:11 mike + * added new functions + * + * Revision 1.2 1999/05/15 02:21:14 mike + * add check for number of decimal places + * + * Revision 1.1 1999/05/10 20:56:31 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +static UCHAR *M_mul_div = NULL; +static UCHAR *M_mul_rem = NULL; + +static UCHAR M_mul_div_10[100]; +static UCHAR M_mul_rem_10[100]; + +static int M_util_firsttime = TRUE; +static int M_firsttime3 = TRUE; + +static M_APM M_work_0_5; + +static char *M_init_error_msg = "\'m_apm_init\', Out of memory"; + +/****************************************************************************/ +M_APM m_apm_init() +{ +M_APM atmp; + +if (M_firsttime3) + { + M_firsttime3 = FALSE; + M_init_util_data(); + M_init_trig_globals(); + } + +if ((atmp = (M_APM)MAPM_MALLOC(sizeof(M_APM_struct))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_init_error_msg); + } + +atmp->m_apm_id = M_APM_IDENT; +atmp->m_apm_malloclength = 80; +atmp->m_apm_datalength = 1; +atmp->m_apm_refcount = 1; /* not for us, for MAPM C++ class */ +atmp->m_apm_exponent = 0; +atmp->m_apm_sign = 0; + +if ((atmp->m_apm_data = (UCHAR *)MAPM_MALLOC(84)) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, M_init_error_msg); + } + +atmp->m_apm_data[0] = 0; +return(atmp); +} +/****************************************************************************/ +void m_apm_free(M_APM atmp) +{ +if (atmp->m_apm_id == M_APM_IDENT) + { + atmp->m_apm_id = 0x0FFFFFF0L; + MAPM_FREE(atmp->m_apm_data); + MAPM_FREE(atmp); + } +else + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_free\', Invalid M_APM variable"); + } +} +/****************************************************************************/ +void M_free_all_util() +{ +if (M_util_firsttime == FALSE) + { + m_apm_free(M_work_0_5); + M_util_firsttime = TRUE; + } + +if (M_firsttime3 == FALSE) + { + MAPM_FREE(M_mul_div); + MAPM_FREE(M_mul_rem); + + M_mul_div = NULL; + M_mul_rem = NULL; + M_firsttime3 = TRUE; + } +} +/****************************************************************************/ +/* + * just a dummy wrapper to keep some compilers from complaining + */ +int M_get_sizeof_int() +{ +return(sizeof(int)); +} +/****************************************************************************/ +void M_init_util_data() +{ +int k; +UCHAR ndiv, nrem; + +if (M_mul_div != NULL) + return; + +M_mul_div = (UCHAR *)MAPM_MALLOC(10000 * sizeof(UCHAR)); +M_mul_rem = (UCHAR *)MAPM_MALLOC(10000 * sizeof(UCHAR)); + +if (M_mul_div == NULL || M_mul_rem == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'M_init_util_data\', Out of memory"); + } + +ndiv = 0; +nrem = 0; + +for (k=0; k < 100; k++) + { + M_mul_div_10[k] = ndiv; + M_mul_rem_10[k] = nrem; + + if (++nrem == 10) + { + nrem = 0; + ndiv++; + } + } + +ndiv = 0; +nrem = 0; + +for (k=0; k < 10000; k++) + { + M_mul_div[k] = ndiv; + M_mul_rem[k] = nrem; + + if (++nrem == 100) + { + nrem = 0; + ndiv++; + } + } +} +/****************************************************************************/ +void M_get_div_rem_addr(UCHAR **ndivp, UCHAR **nremp) +{ +*ndivp = M_mul_div; +*nremp = M_mul_rem; +} +/****************************************************************************/ +void M_get_div_rem(int tbl_lookup, UCHAR *ndiv, UCHAR *nrem) +{ +*ndiv = M_mul_div[tbl_lookup]; +*nrem = M_mul_rem[tbl_lookup]; +} +/****************************************************************************/ +void M_get_div_rem_10(int tbl_lookup, UCHAR *ndiv, UCHAR *nrem) +{ +*ndiv = M_mul_div_10[tbl_lookup]; +*nrem = M_mul_rem_10[tbl_lookup]; +} +/****************************************************************************/ +void m_apm_round(M_APM btmp, int places, M_APM atmp) +{ +int ii; + +if (M_util_firsttime) + { + M_util_firsttime = FALSE; + + M_work_0_5 = m_apm_init(); + m_apm_set_string(M_work_0_5, "5"); + } + +ii = places + 1; + +if (atmp->m_apm_datalength <= ii) + { + m_apm_copy(btmp,atmp); + return; + } + +M_work_0_5->m_apm_exponent = atmp->m_apm_exponent - ii; + +if (atmp->m_apm_sign > 0) + m_apm_add(btmp, atmp, M_work_0_5); +else + m_apm_subtract(btmp, atmp, M_work_0_5); + +btmp->m_apm_datalength = ii; +M_apm_normalize(btmp); +} +/****************************************************************************/ +void M_apm_normalize(M_APM atmp) +{ +int i, index, datalength, exponent; +UCHAR *ucp, numdiv, numrem, numrem2; + +if (atmp->m_apm_sign == 0) + return; + +datalength = atmp->m_apm_datalength; +exponent = atmp->m_apm_exponent; + +/* make sure trailing bytes/chars are 0 */ +/* the following function will adjust the 'datalength' */ +/* we want the original value and will fix it later */ + +M_apm_pad(atmp, (datalength + 3)); + +while (TRUE) /* remove lead-in '0' if any */ + { + M_get_div_rem_10((int)atmp->m_apm_data[0], &numdiv, &numrem); + + if (numdiv >= 1) /* number is normalized, done here */ + break; + + index = (datalength + 1) >> 1; + + if (numrem == 0) /* both nibbles are 0, we can move full bytes */ + { + i = 0; + ucp = atmp->m_apm_data; + + while (TRUE) /* find out how many '00' bytes we can move */ + { + if (*ucp != 0) + break; + + ucp++; + i++; + } + + memmove(atmp->m_apm_data, ucp, (index + 1 - i)); + datalength -= 2 * i; + exponent -= 2 * i; + } + else + { + for (i=0; i < index; i++) + { + M_get_div_rem_10((int)atmp->m_apm_data[i+1], &numdiv, &numrem2); + atmp->m_apm_data[i] = 10 * numrem + numdiv; + numrem = numrem2; + } + + datalength--; + exponent--; + } + } + +while (TRUE) /* remove trailing '0' if any */ + { + index = ((datalength + 1) >> 1) - 1; + + if ((datalength & 1) == 0) /* back-up full bytes at a time if the */ + { /* current length is an even number */ + ucp = atmp->m_apm_data + index; + if (*ucp == 0) + { + while (TRUE) + { + datalength -= 2; + index--; + ucp--; + + if (*ucp != 0) + break; + } + } + } + + M_get_div_rem_10((int)atmp->m_apm_data[index], &numdiv, &numrem); + + if (numrem != 0) /* last digit non-zero, all done */ + break; + + if ((datalength & 1) != 0) /* if odd, then first char must be non-zero */ + { + if (numdiv != 0) + break; + } + + if (datalength == 1) + { + atmp->m_apm_sign = 0; + exponent = 0; + break; + } + + datalength--; + } + +atmp->m_apm_datalength = datalength; +atmp->m_apm_exponent = exponent; +} +/****************************************************************************/ +void M_apm_scale(M_APM ctmp, int count) +{ +int ii, numb, ct; +UCHAR *chp, numdiv, numdiv2, numrem; +void *vp; + +ct = count; + +ii = (ctmp->m_apm_datalength + ct + 1) >> 1; +if (ii > ctmp->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(ctmp->m_apm_data, (ii + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_scale\', Out of memory"); + } + + ctmp->m_apm_malloclength = ii + 28; + ctmp->m_apm_data = (UCHAR *)vp; + } + +if ((ct & 1) != 0) /* move odd number first */ + { + ct--; + chp = ctmp->m_apm_data; + ii = ((ctmp->m_apm_datalength + 1) >> 1) - 1; + + if ((ctmp->m_apm_datalength & 1) == 0) + { + /* + * original datalength is even: + * + * uv wx yz becomes --> 0u vw xy z0 + */ + + numdiv = 0; + + while (TRUE) + { + M_get_div_rem_10((int)chp[ii], &numdiv2, &numrem); + + chp[ii + 1] = 10 * numrem + numdiv; + numdiv = numdiv2; + + if (ii == 0) + break; + + ii--; + } + + chp[0] = numdiv2; + } + else + { + /* + * original datalength is odd: + * + * uv wx y0 becomes --> 0u vw xy + */ + + M_get_div_rem_10((int)chp[ii], &numdiv2, &numrem); + + if (ii == 0) + { + chp[0] = numdiv2; + } + else + { + while (TRUE) + { + M_get_div_rem_10((int)chp[ii - 1], &numdiv, &numrem); + + chp[ii] = 10 * numrem + numdiv2; + numdiv2 = numdiv; + + if (--ii == 0) + break; + } + + chp[0] = numdiv; + } + } + + ctmp->m_apm_exponent++; + ctmp->m_apm_datalength++; + } + +/* ct is even here */ + +if (ct > 0) + { + numb = (ctmp->m_apm_datalength + 1) >> 1; + ii = ct >> 1; + + memmove((ctmp->m_apm_data + ii), ctmp->m_apm_data, numb); + memset(ctmp->m_apm_data, 0, ii); + + ctmp->m_apm_datalength += ct; + ctmp->m_apm_exponent += ct; + } +} +/****************************************************************************/ +void M_apm_pad(M_APM ctmp, int new_length) +{ +int num1, numb, ct; +UCHAR numdiv, numrem; +void *vp; + +ct = new_length; +if (ctmp->m_apm_datalength >= ct) + return; + +numb = (ct + 1) >> 1; +if (numb > ctmp->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(ctmp->m_apm_data, (numb + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_pad\', Out of memory"); + } + + ctmp->m_apm_malloclength = numb + 28; + ctmp->m_apm_data = (UCHAR *)vp; + } + +num1 = (ctmp->m_apm_datalength + 1) >> 1; + +if ((ctmp->m_apm_datalength & 1) != 0) + { + M_get_div_rem_10((int)ctmp->m_apm_data[num1 - 1], &numdiv, &numrem); + ctmp->m_apm_data[num1 - 1] = 10 * numdiv; + } + +memset((ctmp->m_apm_data + num1), 0, (numb - num1)); +ctmp->m_apm_datalength = ct; +} +/****************************************************************************/ + +/* + debug_dsp(cc) + M_APM cc; + { +static char buffer[8192]; + +m_apm_to_string(buffer, -1, cc); +printf("(dsp func) = [%s]\n",buffer); + + } +*/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmutl1.c b/src/apps/deskcalc/mapm_4.9.5/mapmutl1.c new file mode 100644 index 0000000000..bc775f9b26 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmutl1.c @@ -0,0 +1,59 @@ + +/* + * M_APM - mapmutl1.c + * + * Copyright (C) 2003 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmutl1.c,v 1.4 2007/12/03 01:59:27 mike Exp $ + * + * This file contains the utility function 'M_apm_log_error_msg' + * + * This is the only function in this file so a user can supply + * their own custom version easily without changing the base library. + * + * $Log: mapmutl1.c,v $ + * Revision 1.4 2007/12/03 01:59:27 mike + * Update license + * + * Revision 1.3 2003/07/21 21:00:34 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.2 2003/05/05 18:38:27 mike + * fix comment + * + * Revision 1.1 2003/05/04 18:19:14 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +void M_apm_log_error_msg(int fatal, char *message) +{ +if (fatal) + { + fprintf(stderr, "MAPM Error: %s\n", message); + exit(100); + } +else + { + fprintf(stderr, "MAPM Warning: %s\n", message); + } +} +/****************************************************************************/ + diff --git a/src/apps/deskcalc/mapm_4.9.5/mapmutl2.c b/src/apps/deskcalc/mapm_4.9.5/mapmutl2.c new file mode 100644 index 0000000000..5dbf41e336 --- /dev/null +++ b/src/apps/deskcalc/mapm_4.9.5/mapmutl2.c @@ -0,0 +1,350 @@ + +/* + * M_APM - mapmutl2.c + * + * Copyright (C) 2002 - 2007 Michael C. Ring + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted. Permission to distribute + * the modified code is granted. Modifications are to be distributed by + * using the file 'license.txt' as a template to modify the file header. + * 'license.txt' is available in the official MAPM distribution. + * + * This software is provided "as is" without express or implied warranty. + */ + +/* + * $Id: mapmutl2.c,v 1.7 2007/12/03 02:00:04 mike Exp $ + * + * This file contains various utility functions + * + * $Log: mapmutl2.c,v $ + * Revision 1.7 2007/12/03 02:00:04 mike + * Update license + * + * Revision 1.6 2003/07/21 20:53:10 mike + * Modify error messages to be in a consistent format. + * + * Revision 1.5 2003/05/04 18:14:32 mike + * move generic error handling function into a dedicated module + * + * Revision 1.4 2003/03/31 22:02:22 mike + * call generic error handling function + * + * Revision 1.3 2002/11/03 21:19:40 mike + * Updated function parameters to use the modern style + * + * Revision 1.2 2002/05/17 22:29:46 mike + * update some comments + * + * Revision 1.1 2002/05/17 22:28:27 mike + * Initial revision + */ + +#include "m_apm_lc.h" + +/****************************************************************************/ +int m_apm_sign(M_APM atmp) +{ +return(atmp->m_apm_sign); +} +/****************************************************************************/ +int m_apm_exponent(M_APM atmp) +{ +if (atmp->m_apm_sign == 0) + return(0); +else + return(atmp->m_apm_exponent - 1); +} +/****************************************************************************/ +int m_apm_significant_digits(M_APM atmp) +{ +return(atmp->m_apm_datalength); +} +/****************************************************************************/ +int m_apm_is_integer(M_APM atmp) +{ +if (atmp->m_apm_sign == 0) + return(1); + +if (atmp->m_apm_exponent >= atmp->m_apm_datalength) + return(1); +else + return(0); +} +/****************************************************************************/ +int m_apm_is_even(M_APM aa) +{ +int ii, jj; + +if (aa->m_apm_sign == 0) + return(1); + +ii = aa->m_apm_datalength; +jj = aa->m_apm_exponent; + +if (jj < ii) + { + M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_is_even\', Non-integer input"); + return(0); + } + +if (jj > ii) + return(1); + +ii = ((ii + 1) >> 1) - 1; +ii = (int)aa->m_apm_data[ii]; + +if ((jj & 1) != 0) /* exponent is odd */ + ii = ii / 10; + +if ((ii & 1) == 0) + return(1); +else + return(0); +} +/****************************************************************************/ +int m_apm_is_odd(M_APM bb) +{ +if (m_apm_is_even(bb)) + return(0); +else + return(1); +} +/****************************************************************************/ +void M_set_to_zero(M_APM z) +{ +z->m_apm_datalength = 1; +z->m_apm_sign = 0; +z->m_apm_exponent = 0; +z->m_apm_data[0] = 0; +} +/****************************************************************************/ +void m_apm_negate(M_APM d, M_APM s) +{ +m_apm_copy(d,s); +if (d->m_apm_sign != 0) + d->m_apm_sign = -(d->m_apm_sign); +} +/****************************************************************************/ +void m_apm_absolute_value(M_APM d, M_APM s) +{ +m_apm_copy(d,s); +if (d->m_apm_sign != 0) + d->m_apm_sign = 1; +} +/****************************************************************************/ +void m_apm_copy(M_APM dest, M_APM src) +{ +int j; +void *vp; + +j = (src->m_apm_datalength + 1) >> 1; +if (j > dest->m_apm_malloclength) + { + if ((vp = MAPM_REALLOC(dest->m_apm_data, (j + 32))) == NULL) + { + /* fatal, this does not return */ + + M_apm_log_error_msg(M_APM_FATAL, "\'m_apm_copy\', Out of memory"); + } + + dest->m_apm_malloclength = j + 28; + dest->m_apm_data = (UCHAR *)vp; + } + +dest->m_apm_datalength = src->m_apm_datalength; +dest->m_apm_exponent = src->m_apm_exponent; +dest->m_apm_sign = src->m_apm_sign; + +memcpy(dest->m_apm_data, src->m_apm_data, j); +} +/****************************************************************************/ +int m_apm_compare(M_APM ltmp, M_APM rtmp) +{ +int llen, rlen, lsign, rsign, i, j, lexp, rexp; + +llen = ltmp->m_apm_datalength; +rlen = rtmp->m_apm_datalength; + +lsign = ltmp->m_apm_sign; +rsign = rtmp->m_apm_sign; + +lexp = ltmp->m_apm_exponent; +rexp = rtmp->m_apm_exponent; + +if (rsign == 0) + return(lsign); + +if (lsign == 0) + return(-rsign); + +if (lsign == -rsign) + return(lsign); + +/* signs are the same, check the exponents */ + +if (lexp > rexp) + goto E1; + +if (lexp < rexp) + goto E2; + +/* signs and exponents are the same, check the data */ + +if (llen < rlen) + j = (llen + 1) >> 1; +else + j = (rlen + 1) >> 1; + +for (i=0; i < j; i++) + { + if (ltmp->m_apm_data[i] > rtmp->m_apm_data[i]) + goto E1; + + if (ltmp->m_apm_data[i] < rtmp->m_apm_data[i]) + goto E2; + } + +if (llen == rlen) + return(0); +else + { + if (llen > rlen) + goto E1; + else + goto E2; + } + +E1: + +if (lsign == 1) + return(1); +else + return(-1); + +E2: + +if (lsign == 1) + return(-1); +else + return(1); +} +/****************************************************************************/ +/* + * + * convert a signed long int to ASCII in base 10 + * + */ +void M_long_2_ascii(char *output, long input) +{ +long t, m; +int i, j; +char *p, tbuf[64]; + +m = input; +p = output; +i = 0; +t = 2147000000L; /* something < 2^31 */ + +if ((m > t) || (m < -t)) /* handle the bigger numbers with 'sprintf'. */ + { /* let them worry about wrap-around problems */ + sprintf(p, "%ld", m); /* at 'LONG_MIN', etc. */ + } +else + { + if (m < 0) /* handle the sign */ + { + *p++ = '-'; + m = -m; + } + + while (TRUE) /* build the digits in reverse order */ + { + t = m / 10; + j = (int)(m - (10 * t)); + tbuf[i++] = (char)(j + '0'); + m = t; + + if (t == 0) + break; + } + + while (TRUE) /* fill output string in the correct order */ + { + *p++ = tbuf[--i]; + if (i == 0) + break; + } + + *p = '\0'; + } +} +/****************************************************************************/ +/* + * this function will convert a string to lowercase + */ +char *M_lowercase(char *s) +{ +char *p; + +p = s; + +while (TRUE) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + + if (*p++ == '\0') break; + } +return(s); +} +/****************************************************************************/ +/* returns char position of first occurence of s2 in s1 + or -1 if no match found +*/ +int M_strposition(char *s1, char *s2) +{ +register char ch1, ch2; +char *p0, *p1, *p2; +int ct; + +ct = -1; +p0 = s1; + +if (*s2 == '\0') return(-1); + +while (TRUE) + { + ct++; + p1 = p0; + p2 = s2; + ch2 = *p2; + + while (TRUE) /* scan until first char matches */ + { + if ((ch1 = *p1) == '\0') return(-1); + if (ch1 == ch2) break; + p1++; + ct++; + } + + p2++; /* check remainder of 2 strings */ + p1++; + p0 = p1; + + while (TRUE) + { + if ((ch2 = *p2) == '\0') return(ct); + if (*p1 != ch2) break; + p1++; + p2++; + } + } +} +/****************************************************************************/