/* * © Copyright FOCONIS AG, 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * */ package org.openntf.formula.function; import java.util.Map; import org.openntf.formula.Function; import org.openntf.formula.FunctionFactory; import org.openntf.formula.FunctionSet; import org.openntf.formula.ValueHolder; import org.openntf.formula.annotation.OpenNTF; import org.openntf.formula.annotation.ParamCount; import org.openntf.formula.impl.ParameterCollectionDouble; public enum MathFunctions { ; public static class Functions extends FunctionSet { private static final Map<String, Function> functionSet = FunctionFactory.getFunctions(MathFunctions.class); @Override public Map<String, Function> getFunctions() { return functionSet; } } @ParamCount(1) public static Number atAbs(final Number arg) { return Math.abs(arg.doubleValue()); } @ParamCount(1) public static Number atACos(final Number arg) { return Math.acos(arg.doubleValue()); } @ParamCount(1) public static Number atASin(final Number arg) { return Math.asin(arg.doubleValue()); } @ParamCount(1) public static Number atATan(final Number arg) { return Math.atan(arg.doubleValue()); } @ParamCount(2) public static Number atATan2(final Number arg1, final Number arg2) { // pay attention. Formula language expects the arguments in different order return Math.atan2(arg2.doubleValue(), arg1.doubleValue()); } @ParamCount(1) public static Number atCos(final Number arg) { return Math.cos(arg.doubleValue()); } @ParamCount(1) public static Number atExp(final Number arg) { return Math.exp(arg.doubleValue()); } @ParamCount({ 2, 3 }) public static Number atFloatEq(final Number... args) { double epsilon = (args.length == 3) ? args[2].doubleValue() : 0.0001; return Math.abs(args[0].doubleValue() - args[1].doubleValue()) < epsilon ? 1 : 0; } @ParamCount(1) public static Number atInteger(final Number arg) { return arg.intValue(); } @ParamCount(1) public static Number atLog(final Number arg) { return Math.log10(arg.doubleValue()); } @ParamCount(1) public static Number atLn(final Number arg) { return Math.log(arg.doubleValue()); } // Max returns either the largest number in a single list, or the larger of two numbers or number lists. @ParamCount({ 1, 2 }) public static ValueHolder atMax(final ValueHolder[] params) { if (params.length == 1) { ValueHolder vh = params[0]; double ret = Double.MIN_VALUE; for (int i = 0; i < vh.size; i++) { ret = Math.max(ret, vh.getDouble(i)); } return ValueHolder.valueOf(ret); } else if (ValueHolder.hasMultiValues(params)) { ParameterCollectionDouble values = new ParameterCollectionDouble(params, false); ValueHolder ret = ValueHolder.createValueHolder(double.class, values.size()); for (double[] value : values) { ret.add(Math.max(value[0], value[1])); } return ret; } else { ValueHolder ret = ValueHolder.createValueHolder(double.class, 1); ret.add(Math.max(params[0].getDouble(0), params[1].getDouble(0))); return ret; } } //... the same for Min @ParamCount({ 1, 2 }) public static ValueHolder atMin(final ValueHolder[] params) { if (params.length == 1) { double ret = Double.MAX_VALUE; ValueHolder vh = params[0]; for (int i = 0; i < vh.size; i++) { ret = Math.min(ret, vh.getDouble(i)); } return ValueHolder.valueOf(ret); } else if (ValueHolder.hasMultiValues(params)) { ParameterCollectionDouble values = new ParameterCollectionDouble(params, false); ValueHolder ret = ValueHolder.createValueHolder(double.class, values.size()); for (double[] value : values) { ret.add(Math.min(value[0], value[1])); } return ret; } else { ValueHolder ret = ValueHolder.createValueHolder(double.class, 1); ret.add(Math.min(params[0].getDouble(0), params[1].getDouble(0))); return ret; } } @ParamCount(2) public static Number atModulo(final Number arg1, final Number arg2) { // how I would do it // return arg1.longValue() % arg2.longValue(); // how notes does it double divres = arg1.doubleValue() / arg2.doubleValue(); if (Double.isInfinite(divres)) return divres; return (long) (arg1.doubleValue() - (long) divres * arg2.doubleValue()); } private static ValueHolder PI = ValueHolder.valueOf(Math.PI); @ParamCount(0) public static ValueHolder atPi() { return PI; } @ParamCount(2) public static Number atPower(final Number arg1, final Number arg2) { return Math.pow(arg1.doubleValue(), arg2.doubleValue()); } @ParamCount(0) public static ValueHolder atRandom() { return ValueHolder.valueOf(Math.random()); } @ParamCount(1) public static Number atRound(final Number arg) { return Math.round(arg.doubleValue()); } @ParamCount(1) public static Number atSin(final Number arg) { return Math.sin(arg.doubleValue()); } @ParamCount(1) public static Number atSqrt(final Number arg) { return Math.sqrt(arg.doubleValue()); } @ParamCount({ 1, Integer.MAX_VALUE }) public static ValueHolder atSum(final ValueHolder[] params) { double ret = 0; for (ValueHolder valueHolder : params) { for (int i = 0; i < valueHolder.size; i++) { ret += valueHolder.getDouble(i); } } return ValueHolder.valueOf(ret); } @ParamCount(1) public static Number atTan(final Number arg) { return Math.tan(arg.doubleValue()); } @ParamCount(1) public static Number atSign(final Number arg) { int i = (arg instanceof Integer) ? arg.intValue() : Double.compare(arg.doubleValue(), 0.0); return (i == 0) ? 0 : (i < 0) ? -1 : 1; } // =========================================== // These functions are NOT supported by Lotus: /* (non-Javadoc) * @see java.lang.Math.cbrt */ @ParamCount(1) @OpenNTF public static Number atCbrt(final Number arg) { return Math.cbrt(arg.doubleValue()); } @ParamCount(1) @OpenNTF public static Number atCeil(final Number arg) { return Math.ceil(arg.doubleValue()); } @ParamCount(1) @OpenNTF public static Number atFloor(final Number arg) { return Math.floor(arg.doubleValue()); } // TODO: Implement the complete Math Functions }