public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) { int maxN = args.length; if (maxN < 1) { return ErrorEval.VALUE_INVALID; } ValueEval firstArg = args[0]; try { if (firstArg instanceof NumericValueEval) { return evaluateSingleProduct(args); } if (firstArg instanceof RefEval) { return evaluateSingleProduct(args); } if (firstArg instanceof TwoDEval) { TwoDEval ae = (TwoDEval) firstArg; if (ae.isRow() && ae.isColumn()) { return evaluateSingleProduct(args); } return evaluateAreaSumProduct(args); } } catch (EvaluationException e) { return e.getErrorEval(); } throw new RuntimeException( "Invalid arg type for SUMPRODUCT: (" + firstArg.getClass().getName() + ")"); }
private static void throwFirstError(TwoDEval areaEval) throws EvaluationException { int height = areaEval.getHeight(); int width = areaEval.getWidth(); for (int rrIx = 0; rrIx < height; rrIx++) { for (int rcIx = 0; rcIx < width; rcIx++) { ValueEval ve = areaEval.getValue(rrIx, rcIx); if (ve instanceof ErrorEval) { throw new EvaluationException((ErrorEval) ve); } } } }
private static boolean areasAllSameSize(TwoDEval[] args, int height, int width) { for (int i = 0; i < args.length; i++) { TwoDEval areaEval = args[i]; // check that height and width match if (areaEval.getHeight() != height) { return false; } if (areaEval.getWidth() != width) { return false; } } return true; }
private static ValueEval evaluateAreaSumProduct(ValueEval[] evalArgs) throws EvaluationException { int maxN = evalArgs.length; TwoDEval[] args = new TwoDEval[maxN]; try { System.arraycopy(evalArgs, 0, args, 0, maxN); } catch (ArrayStoreException e) { // one of the other args was not an AreaRef return ErrorEval.VALUE_INVALID; } TwoDEval firstArg = args[0]; int height = firstArg.getHeight(); int width = firstArg.getWidth(); // TODO - junit // first check dimensions if (!areasAllSameSize(args, height, width)) { // normally this results in #VALUE!, // but errors in individual cells take precedence for (int i = 1; i < args.length; i++) { throwFirstError(args[i]); } return ErrorEval.VALUE_INVALID; } double acc = 0; for (int rrIx = 0; rrIx < height; rrIx++) { for (int rcIx = 0; rcIx < width; rcIx++) { double term = 1D; for (int n = 0; n < maxN; n++) { double val = getProductTerm(args[n].getValue(rrIx, rcIx), false); term *= val; } acc += term; } } return new NumberEval(acc); }