/* * Copyright (c) 2002-2006 Samit Basu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Core.hpp" #include "Exception.hpp" #include "Array.hpp" #include "Malloc.hpp" #include #include "Utils.hpp" #include "IEEEFP.hpp" //! //@Module COS Trigonometric Cosine Function //@@Section MATHFUNCTIONS //@@Usage //Computes the @|cos| function for its argument. The general //syntax for its use is //@[ // y = cos(x) //@] //where @|x| is an @|n|-dimensional array of numerical type. //Integer types are promoted to the @|double| type prior to //calculation of the @|cos| function. Output @|y| is of the //same size and type as the input @|x|, (unless @|x| is an //integer, in which case @|y| is a @|double| type). //@@Function Internals //Mathematically, the @|cos| function is defined for all real //valued arguments @|x| by the infinite summation //\[ // \cos x \equiv \sum_{n=0}^{\infty} \frac{(-1)^n x^{2n}}{(2n)!}. //\] //For complex valued arguments @|z|, the cosine is computed via //\[ // \cos z \equiv \cos \Re z \cosh \Im z - \sin \Re z // \sinh \Im z. //\] //@@Example //The following piece of code plots the real-valued @|cos(2 pi x)| //function over one period of @|[0,1]|: //@< //x = linspace(0,1); //plot(x,cos(2*pi*x)) //mprint('cosplot'); //@> //@figure cosplot //! ArrayVector CosFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Cosine Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (argType > FM_DCOMPLEX) throw Exception("argument to cosine must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure sinplot //! ArrayVector SinFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Sin Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (argType > FM_DCOMPLEX) throw Exception("argument to sine must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure tanplot //! ArrayVector TanFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Tangent Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (argType > FM_DCOMPLEX) throw Exception("argument to tangent must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure cscplot //! ArrayVector CscFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Cosecant Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (argType > FM_DCOMPLEX) throw Exception("argument to cosecant must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure secplot //! ArrayVector SecFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Secant Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (argType > FM_DCOMPLEX) throw Exception("argument to secant must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure cotplot //! ArrayVector CotFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Cotangent Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (argType > FM_DCOMPLEX) throw Exception("argument to cotangent must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure acosplot //! ArrayVector ArccosFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Arccosine Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } // Check the range if (argType == FM_FLOAT) { int i; float rngeVal; int cnt; bool init; const float *dp = (const float *) input.getDataPointer(); cnt = input.getLength(); init = false; for (i=0;i rngeVal) ? fabs(dp[i]) : rngeVal; } else { rngeVal = fabs(dp[i]); init = true; } } } if (!init) { ArrayVector retval; retval.push_back(input); return retval; } if (rngeVal > 1.0f) { input.promoteType(FM_COMPLEX); argType = FM_COMPLEX; } } else if (argType == FM_DOUBLE) { int i; double rngeVal; int cnt; bool init; const double *dp = (const double *) input.getDataPointer(); cnt = input.getLength(); init = false; for (i=0;i rngeVal) ? fabs(dp[i]) : rngeVal; } else { rngeVal = fabs(dp[i]); init = true; } } } if (!init) { ArrayVector retval; retval.push_back(input); return retval; } if (rngeVal > 1.0) { input.promoteType(FM_DCOMPLEX); argType = FM_DCOMPLEX; } } if (argType > FM_DCOMPLEX) throw Exception("argument to arccosine must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure asinplot //! ArrayVector ArcsinFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Arcsine Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } // Check the range if (argType == FM_FLOAT) { int i; float rngeVal; int cnt; bool init; const float *dp = (const float *) input.getDataPointer(); cnt = input.getLength(); init = false; for (i=0;i rngeVal) ? fabs(dp[i]) : rngeVal; } else { rngeVal = fabs(dp[i]); init = true; } } } if (!init) { ArrayVector retval; retval.push_back(input); return retval; } if (rngeVal > 1.0f) { input.promoteType(FM_COMPLEX); argType = FM_COMPLEX; } } else if (argType == FM_DOUBLE) { int i; double rngeVal; int cnt; bool init; const double *dp = (const double *) input.getDataPointer(); cnt = input.getLength(); init = false; for (i=0;i rngeVal) ? fabs(dp[i]) : rngeVal; } else { rngeVal = fabs(dp[i]); init = true; } } } if (!init) { ArrayVector retval; retval.push_back(input); return retval; } if (rngeVal > 1.0) { input.promoteType(FM_DCOMPLEX); argType = FM_DCOMPLEX; } } if (argType > FM_DCOMPLEX) throw Exception("argument to arcsine must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure atanplot //! ArrayVector ArctanFunction(int nargout, const ArrayVector& arg) { if (arg.size() != 1) throw Exception("Arctan Function takes exactly one argument"); Array input(arg[0]); if (input.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argType(input.dataClass()); if (argType < FM_FLOAT) { input.promoteType(FM_DOUBLE); argType = FM_DOUBLE; } if (input.isEmpty()) { ArrayVector retval; retval.push_back(input); return retval; } if (argType > FM_DCOMPLEX) throw Exception("argument to arctan must be numeric"); switch (argType) { case FM_FLOAT: { const float *dp = ((const float *)input.getDataPointer()); int len(input.getLength()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i //@figure atan2plot //Note how the two-argument @|atan2| function (green line) //correctly ``unwraps'' the phase of the angle, while the @|atan| //function (red line) wraps the angle to the interval @|[-\pi/2,\pi/2]|. //! ArrayVector Arctan2Function(int nargout, const ArrayVector& arg) { if (arg.size() != 2) throw Exception("Arctan2 Function takes exactly two arguments"); Array y(arg[0]); Array x(arg[1]); if (x.isEmpty() || y.isEmpty()) { ArrayVector retval; retval.push_back(Array::emptyConstructor()); return retval; } Array output; Class argTypex(x.dataClass()); Class argTypey(y.dataClass()); if (argTypex < FM_FLOAT) { x.promoteType(FM_DOUBLE); argTypex = FM_DOUBLE; } if (argTypey < FM_FLOAT) { y.promoteType(FM_DOUBLE); argTypey = FM_DOUBLE; } if (argTypex > FM_DCOMPLEX) throw Exception("arguments to arctan2 must be numeric"); if (argTypey > FM_DCOMPLEX) throw Exception("arguments to arctan2 must be numeric"); // Check for complex bool isComplex; isComplex = x.isComplex() || y.isComplex(); // Check for 32 bits bool is32bits; is32bits = (argTypex == FM_FLOAT || argTypex == FM_COMPLEX); if (isComplex && is32bits) { x.promoteType(FM_COMPLEX); y.promoteType(FM_COMPLEX); } else if (!isComplex && is32bits) { x.promoteType(FM_FLOAT); y.promoteType(FM_FLOAT); } else if (isComplex && !is32bits) { x.promoteType(FM_DCOMPLEX); y.promoteType(FM_DCOMPLEX); } else { x.promoteType(FM_DOUBLE); y.promoteType(FM_DOUBLE); } Class argType(x.dataClass()); // Next check the sizes. Dimensions outputSize; Dimensions xDim(x.dimensions()); Dimensions yDim(y.dimensions()); int xStride, yStride; if (xDim.isScalar()) { outputSize = yDim; xStride = 0; yStride = 1; } else if (yDim.isScalar()) { outputSize = xDim; xStride = 1; yStride = 0; } else if (xDim.equals(yDim)) { outputSize = xDim; xStride = 1; yStride = 1; } else throw Exception("Illegal combination of sizes for input to atan2 - either both arguments must be the same size, or one must be a scalar"); switch (argType) { case FM_FLOAT: { const float *dpx = ((const float *)x.getDataPointer()); const float *dpy = ((const float *)y.getDataPointer()); int len(outputSize.getElementCount()); float *op = (float *)Malloc(len*sizeof(float)); for (int i=0;i