package jmathlib.core.tokens; import jmathlib.core.interpreter.*; import jmathlib.core.tokens.numbertokens.DoubleNumberToken; import java.text.NumberFormat; /**Class representing numbers used in expression holds a 2D array of complex numers in a 3d array values[y][x][REAL/IMAGINARY] All operations on a DoubleNumberToken create a new DoubleNumberToken*/ public class SparseNumberToken extends DataToken { /**Complex values of the token*/ private double values[][][]; /**Constant value set to 1*/ public static final DoubleNumberToken one = new DoubleNumberToken(1); /**Constant value set to 0*/ public static final DoubleNumberToken zero = new DoubleNumberToken(0); /**Constant value set to 2*/ public static final DoubleNumberToken two = new DoubleNumberToken(2); /**Constant value set to j*/ public static final DoubleNumberToken j = new DoubleNumberToken(0,1); /**stores the number format for displaying the number*/ private static NumberFormat numFormat = NumberFormat.getInstance(); /**Index for real values within array*/ private static final int REAL = 0; /**Index for Imaginary values within array*/ private static final int IMAGINARY = 1; /** Constructor creating empty number token */ public SparseNumberToken() { super(5, "sparse"); sizeY = 0; sizeX = 0; values = null; } /** Constructor creating a scalar taking the numbers value as a string * @param _value = the numbers value as a string */ public SparseNumberToken(String _value) { this(_value, ""); } /** Constructor creating a scalar taking the numbers value as a double * @param _value = the numbers value as a double */ public SparseNumberToken(double _value) { this(_value, 0); } /** Constructor taking the numbers value as a double[][] * @param _value = the numbers value as a 2D array of double */ public SparseNumberToken(double[][] _values) { this(_values, null); } /**Constructor taking the numbers value as a string * @param _real = the numbers real value as a string * @param _imaginary = the numbers imaginary value as a string */ public SparseNumberToken(String _real, String _imaginary) { super(5, "sparse"); sizeX = 1; sizeY = 1; values = new double[1][1][2]; if (!_real.equals("")) values[0][0][REAL] = new Double(_real).doubleValue(); if (!_imaginary.equals("")) values[0][0][IMAGINARY] = new Double(_imaginary).doubleValue(); } /**Constructor taking the numbers value as a pair of double * values representing real and imaginary part * @param _real = the numbers real value as a double * @param _imaginary = the numbers imaginary value as a double */ public SparseNumberToken(double _real, double _imaginary) { super(5, "sparse"); sizeX = 1; sizeY = 1; values = new double[1][1][2]; values[0][0][REAL] = _real; values[0][0][IMAGINARY] = _imaginary; } /**Constructor taking the numbers value as a pair of double values representing real and imaginary part @param _values = the values as a array containing the real and imaginary values*/ public SparseNumberToken(double[] _values) { super(5, "sparse"); sizeX = 1; sizeY = 1; values = new double[1][1][2]; values[0][0][REAL] = _values[REAL]; values[0][0][IMAGINARY] = _values[IMAGINARY]; } /**Constructor taking the numbers value as two double[][] @param _real = the numbers value as a 2D array of double @param _imaginary = the numbers value as a 2D array of double*/ public SparseNumberToken(double[][] _real, double[][] _imaginary) { super(5, "sparse"); sizeY = _real.length; sizeX = _real[0].length; values = new double[sizeY][sizeX][2]; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { values[yy][xx][REAL] = _real[yy][xx]; // imaginary number may be null if (_imaginary != null) values[yy][xx][IMAGINARY] = _imaginary[yy][xx]; else values[yy][xx][IMAGINARY] = 0; } } } /**Constructor taking the numbers value as a double[][][] @param _values = the numbers value as a 3D array of double*/ public SparseNumberToken(double[][][] _values) { super(5, "sparse"); sizeY = _values.length; sizeX = _values[0].length; values = new double[sizeY][sizeX][2]; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { values[yy][xx][REAL] = _values[yy][xx][REAL]; values[yy][xx][IMAGINARY] = _values[yy][xx][IMAGINARY]; } } } /** return a new Number Token of size y*x * */ public DataToken getElementSized(int y, int x) { return new DoubleNumberToken(new double[y][x][2]); } /** increase/decrease the size of the current DoubleNumberToken to size y*x * @param dy number of rows * @param dx number of columns */ public void setSize(int dy, int dx) { double[][][] newValues = new double[dy][dx][2]; ErrorLogger.debugLine("number "+dy+" "+dx); ErrorLogger.debugLine("number "+sizeY+" "+sizeX); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { ErrorLogger.debugLine("number "+yy+" "+xx); newValues[yy][xx][REAL] = values[yy][xx][REAL]; newValues[yy][xx][IMAGINARY] = values[yy][xx][IMAGINARY]; } } values = newValues; sizeY = dy; sizeX = dx; } // end setSize /**@return the real value of the first number*/ public double getValue() { return values[0][0][REAL]; } /**@return the real value of the first number*/ //public double getValueRe() //{ // return values[0][0][REAL]; //} /**@return the real value of the number at position y, x*/ public double getValueRe(int y, int x) { return values[y][x][REAL]; } /**@return the real value of the first number as an integer*/ //public int getIntValue() //{ // double temp = values[0][0][REAL]; // return (new Double(temp)).intValue(); //} /**@return the real value of the number at position y, x as an integer*/ public int getIntValue(int y, int x) { double temp = values[x][y][REAL]; return (new Double(temp)).intValue(); } /**@return the imaginary value of the first number*/ public double getValueIm() { return values[0][0][IMAGINARY]; } /**@return the imaginary value of the number at position y, x*/ public double getValueIm(int y, int x) { return values[y][x][IMAGINARY]; } /**@return the absolute value of the number at position y, x*/ public double getValueAbs(int y, int x) { double temp = Math.pow(values[y][x][REAL], 2) + Math.pow(values[y][x][IMAGINARY], 2); return Math.sqrt(temp); } /**@return the angle of the number at position y, x in radians*/ public double getValueArg(int y, int x) { return Math.atan2(values[y][x][IMAGINARY], values[y][x][REAL]); } /**@return the value of the number (old notation)*/ public double[][] getValuesSSSSS() { return getReValues(); } /**@return the real values of the number*/ public double[][] getReValues() { double[][] temp = new double[sizeY][sizeX]; if (sizeY==0 && sizeX==0) return null; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { temp[yy][xx] = values[yy][xx][REAL]; } } return temp; } /**@return the imaginary values of the number*/ public double[][] getImValues() { double[][] temp = new double[sizeY][sizeX]; if (sizeY==0 && sizeX==0) return null; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { temp[yy][xx] = values[yy][xx][IMAGINARY]; } } return temp; } /**@return the imaginary value of the number*/ public double[][] getValuesImg() { return getImValues(); } /*public OperandToken getElement(int y, int x) { return new DoubleNumberToken(values[y][x]); }*/ /*public OperandToken getElement(int n) { int x = (int) (n/sizeY); // column to start int y = n - x*sizeY; // row to start return new DoubleNumberToken(values[y][x]); }*/ public void setElement(int y, int x, OperandToken num) { double real = ((DoubleNumberToken)num).getValueRe(); double imag = ((DoubleNumberToken)num).getValueIm(); ErrorLogger.debugLine("DoubleNumberToken("+y+","+x+")"+ real+" "+imag); values[y][x][REAL] = real; values[y][x][IMAGINARY] = imag; } public void setElement(int n, OperandToken num) { int x = (int)(n/sizeY); // column to start int y = n - x*sizeY; // row to start double real = ((DoubleNumberToken)num).getValueRe(); double imag = ((DoubleNumberToken)num).getValueIm(); ErrorLogger.debugLine("DoubleNumberToken("+y+","+x+")"+ real+" "+imag); values[y][x][REAL] = real; values[y][x][IMAGINARY] = imag; } /**@return an array of double representing the element at y,x @param y = y position in matrix @param x = x position in matrix*/ public double[] getValueComplex(int y, int x) { return values[y][x]; } /**Set value at position y, x @param y = y position in matrix @param x = x position in matrix @param _value = the value to set it to as an array of doubles @param imag = imaginary value */ public void setValueComplex(int y, int x, double[] _value) { values[y][x][REAL] = _value[REAL]; values[y][x][IMAGINARY] = _value[IMAGINARY]; } /**Set value at position y, x @param y = y position in matrix @param x = x position in matrix @param real = real value @param imag = imaginary value */ public void setValue(int y, int x, double _real, double _imag) { values[y][x][REAL] = _real; values[y][x][IMAGINARY] = _imag; } /**return the number as a string*/ public String toString() { String result = null; if((sizeY == 0) && (sizeX == 0)) { result = "[]"; } else if((sizeY == 1) && (sizeX == 1)) { result = toString(values[0][0]); } else { StringBuffer buffer = new StringBuffer(20); for(int yy = 0; yy < sizeY; yy++) { buffer.append("["); for(int xx = 0; xx < sizeX; xx++) { buffer.append(toString(values[yy][xx])); if(xx < sizeX - 1) buffer.append(" , "); } buffer.append("]\n"); } result = new String(buffer); } return result; } /** create string representation of (complex) double values @param _values[]={REAL,IMAGINARY} real and imaginary part of number*/ public String toString(double _values[]) { double re = _values[REAL]; double im = _values[IMAGINARY]; StringBuffer result = new StringBuffer(); if((im != 0.0) || Double.isNaN(im)) result.append("("); // real part of number // +/- infinity, not a number, number if (re == Double.POSITIVE_INFINITY) result.append("Inf"); else if (re == Double.NEGATIVE_INFINITY) result.append("-Inf"); else if (Double.isNaN(re)) result.append("NaN"); else result.append(numFormat.format(re)); // imaginary part of number if((im != 0.0) || Double.isNaN(im)) { if ((re!=0.0) && !(im<0)) result.append("+"); // +/- infinity, not a number, number if (im == Double.POSITIVE_INFINITY) result.append("Inf"); else if (im == Double.NEGATIVE_INFINITY) result.append("-Inf"); else if (Double.isNaN(im)) result.append("NaN"); else result.append(numFormat.format(im)); result.append("i)"); } return result.toString(); } /**Evaluate the token. This causes it to return itself*/ public OperandToken evaluate(Token[] operands, GlobalValues globals) { return this; } /**Check if two tokens are equal @param arg = the object to check against*/ public boolean equals(Object arg) { if(arg instanceof DoubleNumberToken) { DoubleNumberToken nArg = (DoubleNumberToken)arg; if(sizeX == nArg.getSizeX() && sizeY == nArg.getSizeY()) { boolean equal = true; for (int yy=0; yy<sizeY && equal; yy++) { for (int xx=0; xx<sizeX && equal; xx++) { if((values[yy][xx][REAL] - nArg.getValueRe(yy, xx) != 0) || (values[yy][xx][IMAGINARY] - nArg.getValueIm(yy, xx) != 0)) equal = false; } } return equal; } return false; } return false; } /**calculate the arg of the complex number at y, x*/ public double arg(int y, int x) { return Math.atan2(values[y][x][REAL], values[y][x][IMAGINARY]); } ///////////////////////standard operators/////////////////// //////////////////////////////////////////////////////////// /**add arg to this object for a number token @param = the value to add to it @return the result as an OperandToken*/ public OperandToken add(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: add: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); // Check dimensions of matrices if((sizeX == argSizeX) && (sizeY == argSizeY)) { // Add (n*m) + (n*m) ErrorLogger.debugLine("DoubleNumberToken: add (n*m) + (n*m)"); DoubleNumberToken result = new DoubleNumberToken(values); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { double realval = values[yy][xx][REAL] + nArg.getValueRe(yy, xx); double imaginaryval = values[yy][xx][IMAGINARY] + nArg.getValueIm(yy, xx); result.setValue(yy, xx, realval, imaginaryval); } } //ErrorLogger.debugLine("end DoubleNumberToken: add (n*m) + (n*m)"); return result; } else if((sizeX==1) && (sizeY==1)) { // 1 + [3,4,5] ErrorLogger.debugLine("DoubleNumberToken: add (1*1) + (n*m)"); DoubleNumberToken result = nArg; double re = getValueRe(0, 0); double im = getValueIm(0, 0); for(int yy = 0; yy < argSizeY; yy++) { for(int xx = 0; xx < argSizeX; xx++) { double realval = nArg.getValueRe(yy,xx) + re; double imaginaryval = nArg.getValueIm(yy,xx) + im; result.setValue(yy, xx, realval, imaginaryval); } } //ErrorLogger.debugLine("end DoubleNumberToken: add (n*m) + (n*m)"); return result; } else if((argSizeX==1) && (argSizeY==1)) { // [3,4,5] +1 ErrorLogger.debugLine("DoubleNumberToken: add (n,m) + (1,1)"); DoubleNumberToken result = new DoubleNumberToken(values); double re = nArg.getValueRe(0, 0); double im = nArg.getValueIm(0, 0); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { double realval = values[yy][xx][REAL] + re; double imaginaryval = values[yy][xx][IMAGINARY] + im; result.setValue(yy, xx, realval, imaginaryval); } } //ErrorLogger.debugLine("end DoubleNumberToken: add (n*m) + (n*m)"); return result; } else { /* Matrices have unequal size: (n*m) != (o*p) */ Errors.throwMathLibException("DoubleNumberToken: add matrices of unequal size"); return null; } } // and add /**subtract arg from this object for a number token @param = the value to subtract @return the result as an OperandToken*/ public OperandToken subtract(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: substract: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); //Check dimensions of matrices if((sizeX == argSizeX) && (sizeY == argSizeY)) { // Sub (n*m) - (n*m) ErrorLogger.debugLine("DoubleNumberToken: sub (n*m) - (n*m)"); DoubleNumberToken result = new DoubleNumberToken(values); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { double realval = values[yy][xx][REAL] - nArg.getValueRe(yy, xx); double imaginaryval = values[yy][xx][IMAGINARY] - nArg.getValueIm(yy, xx); result.setValue(yy, xx, realval, imaginaryval); } } return result; } else if((sizeX == 1) && (sizeY == 1)) { // 1 - [2,3,4] ErrorLogger.debugLine("DoubleNumberToken: sub (1*1) - (n*m)"); DoubleNumberToken result = nArg; double re = getValueRe(0, 0); double im = getValueIm(0, 0); for(int yy = 0; yy < argSizeY; yy++) { for(int xx = 0; xx < argSizeX; xx++) { double realval = re - nArg.getValueRe(yy,xx); double imaginaryval = im - nArg.getValueIm(yy,xx); result.setValue(yy, xx, realval, imaginaryval); } } return result; } else if((argSizeX == 1) && (argSizeY == 1)) { // [3,4,5] - 5 ErrorLogger.debugLine("DoubleNumberToken: sub (n*m) - (1*1)"); DoubleNumberToken result = new DoubleNumberToken(values); double re = nArg.getValueRe(0, 0); double im = nArg.getValueIm(0, 0); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { double realval = values[yy][xx][REAL] - re; double imaginaryval = values[yy][xx][IMAGINARY] - im; result.setValue(yy, xx, realval, imaginaryval); } } return result; } else { // Matrices have unequal size: (n*m) != (o*p) ErrorLogger.debugLine("DoubleNumberToken: sub matrices of unequal size"); return null; } } /**Raise this object to the power of arg @param = the value to raise it to the power of @return the result as an OperandToken*/ public OperandToken power(OperandToken arg) { // works only on numbers if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: powerOf: no number"); //double[][] argValuesImg = ((DoubleNumberToken)arg).getValuesImg(); int argSizeX = ((DoubleNumberToken)arg).getSizeX(); int argSizeY = ((DoubleNumberToken)arg).getSizeY(); if ((sizeX==1) && (sizeY==1)) { // e.g. [1,2,3;4,5,6].^4 double [][][]results = new double[sizeY][sizeX][2]; // bug in Z()-class: 0^something equals 0 if (values[0][0][REAL] == 0 && values[0][0][IMAGINARY] == 0) return zero; double[] argValues = ((DoubleNumberToken)arg).getValueComplex(0, 0); //Complex result = Z.pow(values.get(0,0), argValues.get(0, 0)); double re = Math.log(getValueAbs(0, 0)); double im = getValueArg(0, 0); double re2 = (re*argValues[REAL]) - (im*argValues[IMAGINARY]); double im2 = (re*argValues[IMAGINARY]) + (im*argValues[REAL]); double scalar = Math.exp(re2); results[0][0][REAL] = scalar * Math.cos(im2); results[0][0][IMAGINARY] = scalar * Math.sin(im2); return new DoubleNumberToken(results); } else if ((argSizeX==1) && (argSizeY==1)) { // e.g. [1,2,3;4,5,6].^2 } Errors.throwMathLibException("DoubleNumberToken: power invalid array"); return null; } // end powerOf /**multiply arg by this object for a number token @param arg = the value to multiply it by @return the result as an OperandToken*/ public OperandToken multiply(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: multiply: no number"); DoubleNumberToken argValues = ((DoubleNumberToken)arg); int argSizeX = ((DoubleNumberToken)arg).getSizeX(); int argSizeY = ((DoubleNumberToken)arg).getSizeY(); /* Check if arg is a scalar */ if((argSizeX == 1) && (argSizeY == 1)) { // Multiply (n*m) = (n*m) * scalar ErrorLogger.debugLine("DoubleNumberToken: multiply ("+sizeY+"*"+sizeX+") * scalar"); double [][][]results = new double[sizeY][sizeX][2]; double argRe = argValues.getValueRe(); double argIm = argValues.getValueIm(); for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { double temp = values[yy][xx][REAL] * argRe - values[yy][xx][IMAGINARY] * argIm; results[yy][xx][IMAGINARY] = values[yy][xx][IMAGINARY] * argRe + values[yy][xx][REAL] * argIm; results[yy][xx][REAL] = temp; } } return new DoubleNumberToken(results); } else if((sizeX == 1) && (sizeY == 1)) { /* the DoubleNumberToken of this class is a scalar */ /* Multiply (n*m) = scalar * (n*m) */ ErrorLogger.debugLine("DoubleNumberToken: multiply scalar * (n*m) "); //argValues = argValues.times(values.get(0,0)); //values[0][0] = multiply(values[0][0], argValues.getValueComplex(0, 0)); return arg.multiply(this); } else if (sizeX == argSizeY) { /* Multiply (n*o) = (n*m) * (m*o) */ ErrorLogger.debugLine("DoubleNumberToken: multiply (n*m) * (m*o)"); //Zmat resultValues = values.times(argValues); double[][][] results = new double[sizeY][argSizeX][2]; for(int i=0; i<sizeY; i++) { for (int k=0; k<argSizeX; k++) { results[i][k][REAL] = 0; results[i][k][IMAGINARY] = 0; for (int j=0; j<sizeX; j++) { double temp[] = multiply(values[i][j], argValues.getValueComplex(j, k)); results[i][k][REAL] += temp[REAL]; results[i][k][IMAGINARY] += temp[IMAGINARY]; } } } return new DoubleNumberToken(results); } else { /* dimensions do not match */ ErrorLogger.debugLine("DoubleNumberToken: multiply: dimensions don't match"); return null; } } // end multiply /**Multiplies two complex numbers @param arg1 = the first complex number as an array of double @param arg2 = the second complex number as an array of double @return the result as an array of double*/ public double[] multiply(double[] arg1, double[]arg2) { double[] temp = new double[2]; temp[REAL] = (arg1[REAL] * arg2[REAL]) - (arg1[IMAGINARY] * arg2[IMAGINARY]); temp[IMAGINARY] = (arg1[REAL] * arg2[IMAGINARY]) + (arg1[IMAGINARY] * arg2[REAL]); return temp; } /**divide this object by arg for a number token @param arg = the value to divide it by @return the result as an OperandToken*/ public OperandToken divide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: divide: no number"); DoubleNumberToken nArg = (DoubleNumberToken)arg; int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); // Check if arg is a scalar if((argSizeX == 1) && (argSizeY == 1)) { DoubleNumberToken result = new DoubleNumberToken(values); //this); // Divide (n*m) = (n*m) / scalar double[] argValue = nArg.getValueComplex(0, 0); ErrorLogger.debugLine("DoubleNumberToken: divide (n*m) / scalar"); for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { result.setValueComplex(yy, xx, divide(values[yy][xx], argValue)); } } return result; } else if((sizeX == 1) && (sizeY == 1)) { // the DoubleNumberToken of this class is a scalar // Divide (n*m) = scalar / (n*m) ErrorLogger.debugLine("DoubleNumberToken: divide scalar / (n*m) "); DoubleNumberToken result = new DoubleNumberToken(1); double[] value = values[0][0]; for (int yy=0; yy<argSizeY; yy++) { for (int xx=0; xx<argSizeX; xx++) { result.setValueComplex(yy, xx, divide(value, nArg.getValueComplex(yy, xx))); } } return result; } else { ErrorLogger.debugLine("DoubleNumberToken: divide: dimensions don't match"); return null; } } // end divide /** divide two complex numbers and return a complex number again, pay special attention to infinity and not a number @param arg1 = the first complex number as an array of double @param arg2 = the second complex number as an array of double @return the result as an array of double*/ public double[] divide(double[] arg1, double[] arg2) { /* {REAL,IMAGINARY} = divide( {REAL,IMAGINARY}, {REAL,IMAGINARY}) */ double x = arg2[REAL]; double y = arg2[IMAGINARY]; double zRe, zIm; double scalar; double[] temp = new double[2]; if ((x==0.0) && (y==0.0)) { // something like 1/0 50/0 or 0/0 // real part if (Double.isNaN(arg1[REAL])) zRe = Double.NaN; else if (arg1[REAL]>0) zRe = Double.POSITIVE_INFINITY; else if (arg1[REAL]<0) zRe = Double.NEGATIVE_INFINITY; else zRe = Double.NaN; // something like (1+i)/0 50i/0 // imaginary part if (Double.isNaN(arg1[IMAGINARY])) zIm = Double.NaN; else if (arg1[IMAGINARY]>0) zIm = Double.POSITIVE_INFINITY; else if (arg1[IMAGINARY]<0) zIm = Double.NEGATIVE_INFINITY; else zIm = 0.0; } else if(Math.abs(x) >= Math.abs(y)) { scalar = 1.0 / ( x + y*(y/x) ); zRe = scalar * (arg1[REAL] + arg1[IMAGINARY]*(y/x)); zIm = scalar * (arg1[IMAGINARY] - arg1[REAL]*(y/x)); } else { scalar = 1.0 / ( x*(x/y) + y ); zRe = scalar * (arg1[REAL]*(x/y) + arg1[IMAGINARY]); zIm = scalar * (arg1[IMAGINARY]*(x/y) - arg1[REAL]); } temp[REAL] = zRe; temp[IMAGINARY] = zIm; return temp; } //////////////////////////////////////////SCALAR OPERATORS////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// /**scalar multiply arg by this object for a number token @arg = the value to multiply it by @return the result as an OperandToken*/ public OperandToken scalarMultiply(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: scalar multiply: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); double[][] argValues = nArg.getValuesIm(); double[][] argValuesImg = nArg.getValuesIm(); int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); if ((sizeX == argSizeX) && (sizeY == argSizeY)) { // scalar multiplication (n*m) = (n*m) .* (n*m) ErrorLogger.debugLine("DoubleNumberToken: multiply (n*m) .* (n*m)"); double[][][] results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { double[] argVal = nArg.getValueComplex(y, x); results[y][x] = multiply(values[y][x], argVal); } } return new DoubleNumberToken(results); } else if ((argSizeX==1) && (argSizeY==1)) { // scalar multiplication (n*m) .* (1*1) ErrorLogger.debugLine("DoubleNumberToken: multiply (n*m) .* (1*1)"); double[][][] results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { double[] argVal = nArg.getValueComplex(0, 0); results[y][x] = multiply(values[y][x], argVal); } } return new DoubleNumberToken(results); } else if ((sizeX == 1) && (sizeY == 1)) { // scalar multiplication (1*1) .* (n*m) ErrorLogger.debugLine("DoubleNumberToken: multiply (1*1) .* (n*m)"); double[][][] results = new double[argSizeY][argSizeX][2]; for (int y=0; y<argSizeY; y++) { for (int x=0; x<argSizeX; x++) { double[] val = getValueComplex(0, 0); results[y][x] = multiply(val, nArg.getValueComplex(y,x)); } } return new DoubleNumberToken(results); } else { //dimensions do not match Errors.throwMathLibException("DoubleNumberToken: scalar multiply: dimensions don't match"); return null; } } // end scalarMultiply /**scalar divide arg by this object for a number token @arg = the value to divide it by @return the result as an OperandToken*/ public OperandToken scalarDivide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: scalar divide: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); double[][] argValues = nArg.getValuesRe(); double[][] argValuesImg = nArg.getValuesIm(); int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); if ((sizeX == argSizeX) && (sizeY == argSizeY)) { // divide multiplication (n*m) = (n*m) .* (n*m) ErrorLogger.debugLine("DoubleNumberToken: scalar divide (n*m) .* (n*m)"); double[][][] results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { double[] argVal = nArg.getValueComplex(y, x); results[y][x] = divide(values[y][x], argVal); } } return new DoubleNumberToken(results); } else if ((argSizeX==1) && (argSizeY==1)) { // divide multiplication (n*m) ./ (1,1) ErrorLogger.debugLine("DoubleNumberToken: scalar divide (n*m) ./ (1*1)"); double[][][] results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { double[] argVal = nArg.getValueComplex(0, 0); results[y][x] = divide(values[y][x], argVal); } } return new DoubleNumberToken(results); } else if ((sizeX==1) && (sizeY==1)) { // divide multiplication (n*m) ./ (1,1) ErrorLogger.debugLine("DoubleNumberToken: scalar divide (1*1) ./ (n*m)"); double[][][] results = new double[argSizeY][argSizeX][2]; for (int y=0; y<argSizeY; y++) { for (int x=0; x<argSizeX; x++) { double[] val = getValueComplex(0, 0); results[y][x] = divide(val, nArg.getValueComplex(y,x) ); } } return new DoubleNumberToken(results); } else { //dimensions do not match Errors.throwMathLibException("DoubleNumberToken: scalar multiply: dimensions don't match"); return null; } } // end scalarDivide /**left divide @arg = @return the result as an OperandToken*/ public OperandToken leftDivide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: left divide: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); DoubleNumberToken num = new DoubleNumberToken(nArg.getReValues()); return num.divide(new DoubleNumberToken(values)); } // end leftDivide /**scalar left divide @arg = @return the result as an OperandToken*/ public OperandToken scalarLeftDivide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: scalar left divide: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); DoubleNumberToken num = new DoubleNumberToken(nArg.getReValues()); return num.scalarDivide(new DoubleNumberToken(values)); } // end scalarLeftDivide /**calculate the transpose of a matrix @return the result as an OperandToken*/ public OperandToken transpose() { // transposed array double[][] real = new double[sizeX][sizeY]; double[][] imag = new double[sizeX][sizeY]; // swap rows and columns for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { // copy (y,x) -> (x,y), also change sign of imaginary part real[x][y] = values[y][x][REAL]; imag[x][y] = values[y][x][IMAGINARY] * (-1); } } return new DoubleNumberToken(real, imag); } /**calculate the conjugate transpose of a matrix @return the result as an OperandToken*/ public OperandToken ctranspose() { // transposed array double[][] real = new double[sizeX][sizeY]; double[][] imag = new double[sizeX][sizeY]; // swap rows and columns for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { // copy (y,x) -> (x,y), for conjugate transpose do not // change sign of imaginary part real[x][y] = values[y][x][REAL]; imag[x][y] = values[y][x][IMAGINARY] ; } } return new DoubleNumberToken(real, imag); } ///////////////////////////////////////Trigonometric functions///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// /**trigonometric functions - calculate the sine of this token @return the result as an OperandToken*/ public OperandToken sin() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = sin(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the sine of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] sin(double[] arg) { double result[] = new double[2]; double scalar; double iz_re, iz_im; double _re1, _im1; double _re2, _im2; // iz: i.Times(z) ... iz_re = -arg[IMAGINARY]; iz_im = arg[REAL]; // _1: iz.exp() ... scalar = Math.exp(iz_re); _re1 = scalar * Math.cos(iz_im); _im1 = scalar * Math.sin(iz_im); // _2: iz.neg().exp() ... scalar = Math.exp(-iz_re); _re2 = scalar * Math.cos(-iz_im); _im2 = scalar * Math.sin(-iz_im); // _1: _1.Minus(_2) ... _re1 = _re1 - _re2; // !!! _im1 = _im1 - _im2; // !!! // result: _1.Div(2*i) ... result[REAL] = 0.5*_im1; result[IMAGINARY] = -0.5*_re1; return result; } /**trigonometric functions - calculate the cosine of this token @return the result as an OperandToken*/ public OperandToken cos() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = cos(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the cosine of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] cos(double[] arg) { double result[] = new double[2]; double scalar; double iz_re, iz_im; double _re1, _im1; double _re2, _im2; // iz: i.Times(z) ... iz_re = -arg[IMAGINARY]; iz_im = arg[REAL]; // _1: iz.exp() ... scalar = Math.exp(iz_re); _re1 = scalar * Math.cos(iz_im); _im1 = scalar * Math.sin(iz_im); // _2: iz.neg().exp() ... scalar = Math.exp(-iz_re); _re2 = scalar * Math.cos(-iz_im); _im2 = scalar * Math.sin(-iz_im); // _1: _1.Plus(_2) ... _re1 = _re1 + _re2; // !!! _im1 = _im1 + _im2; // !!! // result: _1.scale(0.5) ... result[REAL] = 0.5*_re1; result[IMAGINARY] = -0.5*_im1; return result; } /**trigonometric functions - calculate the tangent of this token @return the result as an OperandToken*/ public OperandToken tan() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = tan(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the tangent of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] tan(double[] arg) { double[] temp1 = new double[2]; temp1[REAL] = arg[REAL]; temp1[IMAGINARY] = arg[IMAGINARY]; temp1 = sin(temp1); double[] temp2 = cos(arg); return divide(temp1, temp2); } /**trigonometric functions - calculate the arc sine of this token @return the result as an OperandToken*/ public OperandToken asin() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = asin(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the arcsine of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] asin(double[] arg) { double result[] = new double[2]; // asin(z) = -i * log(i*z + Sqrt(1 - z*z)) double re = arg[REAL]; double im = arg[IMAGINARY]; // _1: one.Minus(z.Times(z)) ... result[REAL] = 1.0 - ( (re*re) - (im*im) ); result[IMAGINARY] = 0.0 - ( (re*im) + (im*re) ); // result: _1.Sqrt() ... result = sqrt(result); // _1: z.Times(i) ... // result: _1.Plus(result) ... result[REAL] = result[REAL] - im; result[IMAGINARY] = result[IMAGINARY] + re; // _1: result.log() ... result = log(result); double temp = result[IMAGINARY]; result[IMAGINARY] = -result[REAL]; result[REAL] = temp; return result; } /**trigonometric functions - calculate the arc cosine of this token @return the result as an OperandToken*/ public OperandToken acos() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = acos(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the arccosine of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] acos(double[] arg) { double result[] = new double[2]; double _re1, _im1; double re = arg[REAL]; double im = arg[IMAGINARY]; // _1: one - z^2 ... result[REAL] = 1.0 - ( (re*re) - (im*im) ); result[IMAGINARY] = 0.0 - ( (re*im) + (im*re) ); // result: _1.Sqrt() ... result = sqrt(result); // _1: i * result ... _re1 = - result[IMAGINARY]; _im1 = + result[REAL]; // result: z +_1 ... result[REAL] = re + _re1; result[IMAGINARY] = im + _im1; // _1: result.log() result = log(result); // result: -i * _1 ... double temp = result[IMAGINARY]; result[IMAGINARY] = -result[REAL]; result[REAL] = temp; return result; } /**trigonometric functions - calculate the arc tangent of this token @return the result as an OperandToken*/ public OperandToken atan() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = atan(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the arctangent of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] atan(double[] arg) { double result[] = new double[2]; double[] temp = new double[2]; // atan(z) = -i/2 * log( (i-z)/(i+z) ) double _re1, _im1; // result: i.Minus(z) ... temp[REAL] = -arg[REAL]; temp[IMAGINARY] = 1 - arg[IMAGINARY]; // _1: i.Plus(z) ... result[REAL] = arg[REAL]; result[IMAGINARY] = 1 + arg[IMAGINARY]; // result: result.Div(_1) ... result = divide(temp, result); // _1: result.log() ... result = log(result); // result: half_i.neg().Times(_2) ... double t = -0.5 * result[REAL]; result[REAL] = 0.5 * result[IMAGINARY]; result[IMAGINARY] = t; return result; } /**Trigonometric function - calculates the hyperbolic sine @return the result as an OperandToken*/ public OperandToken sinh() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = sinh(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the hyperbolic sine of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] sinh(double[] arg) { double result[] = new double[2]; double scalar; double _re1, _im1; double _re2, _im2; // _1: z.exp() ... scalar = Math.exp(arg[REAL]); _re1 = scalar * Math.cos(arg[IMAGINARY]); _im1 = scalar * Math.sin(arg[IMAGINARY]); // _2: z.neg().exp() ... scalar = Math.exp(-arg[REAL]); _re2 = scalar * Math.cos(-arg[IMAGINARY]); _im2 = scalar * Math.sin(-arg[IMAGINARY]); // _1: _1.Minus(_2) ... _re1 = _re1 - _re2; // !!! _im1 = _im1 - _im2; // !!! // result: _1.scale(0.5) ... result[REAL] = 0.5 * _re1; result[IMAGINARY] = 0.5 * _im1; return result; } /**Trigonometric function - calculates the hyperbolic cosine @return the result as an OperandToken*/ public OperandToken cosh() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = cosh(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the hyperbolic cosine of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] cosh(double[] arg) { double result[] = new double[2]; double scalar; double _re1, _im1; double _re2, _im2; // _1: z.exp() ... scalar = Math.exp(arg[REAL]); _re1 = scalar * Math.cos(arg[IMAGINARY]); _im1 = scalar * Math.sin(arg[IMAGINARY]); // _2: z.neg().exp() ... scalar = Math.exp(-arg[REAL]); _re2 = scalar * Math.cos(-arg[IMAGINARY]); _im2 = scalar * Math.sin(-arg[IMAGINARY]); // _1: _1.Plus(_2) ... _re1 = _re1 + _re2; // !!! _im1 = _im1 + _im2; // !!! // result: _1.scale(0.5) ... result[REAL] = 0.5 * _re1; result[IMAGINARY] = 0.5 * _im1; return result; } /**Trigonometric function - calculates the hyperbolic tan @return the result as an OperandToken*/ public OperandToken tanh() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = tanh(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the hyperbolic tangent of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] tanh(double[] arg) { double[] temp1 = new double[2]; temp1[REAL] = arg[REAL]; temp1[IMAGINARY] = arg[IMAGINARY]; temp1 = sinh(temp1); double[] temp2 = cosh(arg); return divide(temp1, temp2); } /**Trigonometric function - calculates the inverse hyperbolic sine @return the result as an OperandToken*/ public OperandToken asinh() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = asinh(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the inverse hyperbolic sine of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] asinh(double[] arg) { double result[] = new double[2]; // asinh(z) = log(z + Sqrt(z*z + 1)) double re = arg[REAL]; double im = arg[IMAGINARY]; // _1: z.Times(z).Plus(one) ... result[REAL] = ( (re*re) - (im*im) ) + 1.0; result[IMAGINARY] = ( (re*im) + (im*re) ); // result: _1.Sqrt() ... result = sqrt(result); // result: z.Plus(result) ... result[REAL] = re + result[REAL]; // ! result[IMAGINARY] = im + result[IMAGINARY]; // ! // _1: result.log() ... result = log(result); return result; } /**Trigonometric function - calculates the inverse hyperbolic cosine @return the result as an OperandToken*/ public OperandToken acosh() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = acosh(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the inverse hyperbolic cosine of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] acosh(double[] arg) { double result[] = new double[2]; // acosh(z) = log(z + Sqrt(z*z - 1)) double re = arg[REAL]; double im = arg[IMAGINARY]; // _1: z.Times(z).Minus(one) ... result[REAL] = ( (re*re) - (im*im) ) - 1.0; result[IMAGINARY] = ( (re*im) + (im*re) ) - 0.0; // result: _1.Sqrt() ... result = sqrt(result); // result: z.Plus(result) ... result[REAL] = re + result[REAL]; // ! result[IMAGINARY] = im + result[IMAGINARY]; // ! // _1: result.log() ... result = log(result); // result: _1 ... return result; } /**Trigonometric function - calculates the inverse hyperbolic tangent @return the result as an OperandToken*/ public OperandToken atanh() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = atanh(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the inverse hyperbolic tangent of a complex number @param arg = the angle as an array of double @return the result as an array of double*/ public double[] atanh(double[] arg) { double result[] = new double[2]; // atanh(z) = 1/2 * log( (1+z)/(1-z) ) // _1: one.Minus(z) ... double[] temp = new double[2]; temp[REAL] = 1 - arg[REAL]; temp[IMAGINARY] = - arg[IMAGINARY]; // result: one.Plus(z) ... result[REAL] = 1 + arg[REAL]; // result: result.Div(_1) ... result = divide(result, temp); // _1: result.log() ... result = log(result); // result: _1.scale(0.5) ... result[REAL] = 0.5 * result[REAL]; result[IMAGINARY] = 0.5 * result[IMAGINARY]; return result; } ///////////////////////////////////////Exponential Functions//////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// /**Standard functions - calculates the exponent @return the result as an OperandToken*/ public OperandToken exp() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = exp(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the exponent of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] exp(double[] arg) { double[] result = new double[2]; double scalar = Math.exp(arg[REAL]); // e^ix = cis x result[REAL] = scalar * Math.cos(arg[IMAGINARY]); result[IMAGINARY] = scalar * Math.sin(arg[IMAGINARY]); return result; } /**Standard functions - calculates the natural logarythm @return the result as an OperandToken*/ public OperandToken ln() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = log(values[y][x]); } } return new DoubleNumberToken(results); } /**Standard functions - calculates the logarythm @return the result as an OperandToken*/ public OperandToken log() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = log(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the logarythm of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] log(double[] arg) { double[] result = new double[2]; double re = arg[REAL]; double im = arg[IMAGINARY]; double temp = Math.pow(re, 2) + Math.pow(im, 2); temp = Math.sqrt(temp); result[REAL] = Math.log(temp); result[IMAGINARY] = Math.atan2(im, re); return result; // principal value } /**Standard functions - calculates the square root @return the result as an OperandToken*/ public OperandToken sqrt() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x] = sqrt(values[y][x]); } } return new DoubleNumberToken(results); } /**Calculates the sqrt of a complex number @param arg = the value as an array of double @return the result as an array of double*/ public double[] sqrt(double[] arg) { // with thanks to Jim Shapiro <jnshapi@argo.ecte.uswc.uswest.com> // adapted from "Numerical Recipies in C" (ISBN 0-521-43108-5) // by William H. Press et al double[] result = new double[2]; double re = arg[REAL]; double im = arg[IMAGINARY]; double temp = Math.pow(re, 2) + Math.pow(im, 2); double mag = Math.sqrt(temp); if (mag > 0.0) { if (re > 0.0) { temp = Math.sqrt(0.5 * (mag + re)); re = temp; im = 0.5 * im / temp; } else { temp = Math.sqrt(0.5 * (mag - re)); if (im < 0.0) { temp = -temp; }//endif re = 0.5 * im / temp; im = temp; }//endif } else { re = 0.0; im = 0.0; } result[REAL] = re; result[IMAGINARY] = im; return result; } ///////////////////////////////////////Standard Math Functions/////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// /**Standard functions - absolute value @return the result as an OperandToken*/ public OperandToken abs() { double[][][] results = new double[sizeY][sizeX][2]; if (isReal()) { // real numbers only for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { results[yy][xx][REAL] = java.lang.Math.abs(values[yy][xx][REAL]); } } } else { // complex absolute value double real = 0; double imag = 0; for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { real = values[yy][xx][REAL]; imag = values[yy][xx][IMAGINARY]; results[yy][xx][REAL] = Math.sqrt( real*real + imag*imag ); results[yy][xx][IMAGINARY] = 0; } } } return new DoubleNumberToken(results); } /**Standard functions - rounds the value down @return the result as an OperandToken*/ public OperandToken floor() { double[][][] results = new double[sizeY][sizeX][2]; for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { results[yy][xx][REAL] = java.lang.Math.floor(values[yy][xx][REAL]); results[yy][xx][IMAGINARY] = java.lang.Math.floor(values[yy][xx][IMAGINARY]); } } return new DoubleNumberToken(results); } /**Standard functions - rounds the value up @return the result as an OperandToken*/ public OperandToken ceil() { double[][][] results = new double[sizeY][sizeX][2]; for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { results[yy][xx][REAL] = Math.ceil(values[yy][xx][REAL]); results[yy][xx][IMAGINARY] = Math.ceil(values[yy][xx][IMAGINARY]); } } return new DoubleNumberToken(results); } /**Standard functions - rounds the value to the nearest integer @return the result as an OperandToken*/ public OperandToken round() { double[][][] results = new double[sizeY][sizeX][2]; for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { results[yy][xx][REAL] = java.lang.Math.rint(values[yy][xx][REAL]); results[yy][xx][IMAGINARY] = java.lang.Math.rint(values[yy][xx][IMAGINARY]); } } return new DoubleNumberToken(results); } /**standard function - returns the negative of the number*/ public OperandToken negate() { double[][][] results = new double[sizeY][sizeX][2]; for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { results[yy][xx][REAL] = -values[yy][xx][REAL]; results[yy][xx][IMAGINARY] = -values[yy][xx][IMAGINARY]; } } return new DoubleNumberToken(results); } /**Standard functions - calculates the minimum of two values @return the result as an OperandToken*/ public OperandToken min(RootObject arg) { // !!! see matlab documentation for correct implementation double arg2 = ((DoubleNumberToken)arg).getValueRe(0, 0); double result = java.lang.Math.min(values[0][0][REAL], arg2); return new DoubleNumberToken(result); } /**Standard functions - calculates the maximum of two values @return the result as an OperandToken*/ public OperandToken max(RootObject arg) { // !!! see matlab documentation for correct implementation double arg2 = ((DoubleNumberToken)arg).getValueRe(0, 0); double result = java.lang.Math.max(values[0][0][REAL], arg2); return new DoubleNumberToken(result); } /**Standard functions - calculates the factorial of the number @return the result as an OperandToken*/ public OperandToken factorial() { double[][][] results = new double[sizeY][sizeX][2]; for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { double amount = java.lang.Math.rint(values[yy][xx][REAL]); results[yy][xx][REAL] = factorial(amount); } } return new DoubleNumberToken(results); } /**Calulates the factorial of a real value @param amount = the number to calc the factorial of @return the result as a double*/ public double factorial(double amount) { double answer = 1; for(int count = 1; count <= amount; count++) answer *= count; return answer; } //////////////////////////////////////Complex Functions///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /**Complex function - calculates the complex conjugate of the number*/ public OperandToken conjugate() { double[][][] results = new double[sizeY][sizeX][2]; for(int y = 0; y < sizeY; y++) { for(int x = 0; x < sizeX; x++) { results[y][x][REAL] = values[y][x][REAL]; results[y][x][IMAGINARY] = -values[y][x][IMAGINARY]; } } return new DoubleNumberToken(results); } //////////////////////////////////////Test Functions/////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /**Checks if this operand is zero @return true if this number == 0 or that all values are 0 for a matrix*/ public boolean isNull() { boolean result = true; for (int yy=0; yy<sizeY && result; yy++) { for (int xx=0; xx<sizeX && result; xx++) { if(values[yy][xx][REAL] != 0 || values[yy][xx][IMAGINARY] != 0) result = false; } } return result; } /**Checks if this operand is a numeric value @return true if this is a number, false if it's an algebraic expression*/ public boolean isNumeric() { return true; } /**@return true if this number token is a scalar (1*1 matrix)*/ public boolean isScalar() { if ((sizeX==1) && (sizeY==1)) return true; else return false; } /**@return true if this number token is a real matrix, without an imaginary part*/ public boolean isReal() { // if at least one element has an imaginary part the matrix is not real for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { if (values[y][x][IMAGINARY] != 0) return false; } } return true; } /**@return true if this number token is an integral matrix, without an imaginary part*/ public boolean isInteger() { // if at least one element has an imaginary part the matrix is not real, or is not integral for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { if ((values[y][x][IMAGINARY] != 0 ) || (values[y][x][REAL] != java.lang.Math.floor(values[y][x][REAL]))) return false; } } return true; } /**@return true if this number token is an imaginary matrix, without a real part*/ public boolean isImaginary() { // if at least one element has a real part the matrix is not imaginary for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { if (values[y][x][REAL] != 0) return false; } } return true; } /**@return true if this number token is a complex matrix with both real and imaginary parts*/ public boolean isComplex() { // if at least one element has a real value and also on element has // an imaginary part the matrix is complex boolean isRe = false; boolean isIm = false; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { if (values[y][x][REAL] != 0) isRe = true; if (values[y][x][IMAGINARY] != 0) isIm = true; } } // check if both real and imaginary tags are set if (isRe & isIm) return true; else return false; } public OperandToken degreesToRadians() { //convert from degrees to radians double[][] values = getReValues(); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { values[yy][xx] = values[yy][xx] * Math.PI / 180; } } return new DoubleNumberToken(values); } public OperandToken radiansToDegrees() { //convert from degrees to radians double[][] values = getReValues(); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { values[yy][xx] = values[yy][xx] * 180 / Math.PI; } } return new DoubleNumberToken(values); } }