All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.databene.script.math.ArithmeticEngine Maven / Gradle / Ivy

Go to download

'DatabeneScript' is an open source software library for resolving Java-like script expressions, written by Volker Bergmann.

There is a newer version: 1.0.0
Show newest version
/*
 * (c) Copyright 2009-2010 by Volker Bergmann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, is permitted under the terms of the
 * GNU General Public License.
 *
 * For redistributing this software or a derivative work under a license other
 * than the GPL-compatible Free Software License as defined by the Free
 * Software Foundation or approved by OSI, you must first obtain a commercial
 * license to this software product from Volker Bergmann.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
 * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
 * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package org.databene.script.math;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

import org.databene.commons.BeanUtil;
import org.databene.commons.converter.AnyConverter;

/**
 * Provides arithmetic operations.
*
* Created at 06.10.2009 08:00:44 * @since 0.6.0 * @author Volker Bergmann */ public class ArithmeticEngine { // initialization -------------------------------------------------------------------------------------------------- private static Map, TypeArithmetic> typeArithmetics; static { typeArithmetics = new HashMap, TypeArithmetic>(); addTypeArithmetics( // TODO v0.7 allow for user extension and probably merge with ConverterManager setup new DateArithmetic(), new TimeArithmetic(), new TimestampArithmetic()); } private static void addTypeArithmetics(TypeArithmetic... arithmetics) { for (TypeArithmetic arithmetic : arithmetics) typeArithmetics.put(arithmetic.getBaseType(), arithmetic); } // singleton stuff ------------------------------------------------------------------------------------------------- private static ArithmeticEngine defaultInstance = new ArithmeticEngine(); public static ArithmeticEngine defaultInstance() { return defaultInstance; } // interface ------------------------------------------------------------------------------------------------------- public Object add(Object summand1, Object summand2) { // null conversion if (summand1 == null) return summand2; else if (summand2 == null) return summand1; // arbitrary conversion Class resultType = TypeManager.combinedType(summand1.getClass(), summand2.getClass()); TypeArithmetic typeArithmetic = typeArithmetics.get(resultType); if (typeArithmetic != null) return typeArithmetic.add(summand1, summand2); Object s1 = AnyConverter.convert(summand1, resultType); Object s2 = AnyConverter.convert(summand2, resultType); if (resultType == String.class) return (String) s1 + s2; else if (resultType == Boolean.class) return (Boolean) s1 || (Boolean) s2; else if (resultType == Character.class) return (Character) s1 + (Character) s2; else if (resultType == Byte.class) return (Byte) s1 + (Byte) s2; else if (resultType == Short.class) return (Short) s1 + (Short) s2; else if (resultType == Integer.class) return (Integer) s1 + (Integer) s2; else if (resultType == Long.class) return (Long) s1 + (Long) s2; else if (resultType == Float.class) return (Float) s1 + (Float) s2; else if (resultType == Double.class) return (Double) s1 + (Double) s2; else if (resultType == BigInteger.class) return ((BigInteger) s1).add((BigInteger) s2); else if (resultType == BigDecimal.class) return ((BigDecimal) s1).add((BigDecimal) s2); else throw new UnsupportedOperationException("Addition of types " + BeanUtil.simpleClassName(summand1) + " and " + BeanUtil.simpleClassName(summand2) + " is not supported"); } public Object subtract(Object minuend, Object subtrahend) { // null conversion if (subtrahend == null) return minuend; else if (minuend == null) return negate(subtrahend); // arbitrary conversion Class resultType = TypeManager.combinedType(minuend.getClass(), subtrahend.getClass()); TypeArithmetic typeArithmetic = typeArithmetics.get(resultType); if (typeArithmetic != null) return typeArithmetic.subtract(minuend, subtrahend); Object s1 = AnyConverter.convert(minuend, resultType); Object s2 = AnyConverter.convert(subtrahend, resultType); if (resultType == Character.class) return (Character) s1 - (Character) s2; else if (resultType == Byte.class) return (Byte) s1 - (Byte) s2; else if (resultType == Short.class) return (Short) s1 - (Short) s2; else if (resultType == Integer.class) return (Integer) s1 - (Integer) s2; else if (resultType == Long.class) return (Long) s1 - (Long) s2; else if (resultType == Float.class) return (Float) s1 - (Float) s2; else if (resultType == Double.class) return (Double) s1 - (Double) s2; else if (resultType == BigInteger.class) return ((BigInteger) s1).subtract((BigInteger) s2); else if (resultType == BigDecimal.class) return ((BigDecimal) s1).subtract((BigDecimal) s2); else throw new UnsupportedOperationException("Subtraction of type " + BeanUtil.simpleClassName(subtrahend) + " from " + BeanUtil.simpleClassName(minuend) + " is not supported"); } public Object negate(Object value) { // null handling if (value == null) return null; // arbitrary conversion Class type = value.getClass(); if (type == Byte.class) return - (Byte) value; else if (type == Short.class) return - (Short) value; else if (type == Integer.class) return - (Integer) value; else if (type == Long.class) return - (Long) value; else if (type == Float.class) return - (Float) value; else if (type == Double.class) return - (Double) value; else if (type == BigInteger.class) return ((BigInteger) value).negate(); else if (type == BigDecimal.class) return ((BigDecimal) value).negate(); else throw new UnsupportedOperationException("Cannot negate " + BeanUtil.simpleClassName(value)); } public Object multiply(Object factor1, Object factor2) { // null handling if (factor1 == null || factor2 == null) return null; // arbitrary conversion Class resultType = TypeManager.combinedType(factor1.getClass(), factor2.getClass()); TypeArithmetic typeArithmetic = typeArithmetics.get(resultType); if (typeArithmetic != null) return typeArithmetic.multiply(factor1, factor2); Object s1 = AnyConverter.convert(factor1, resultType); Object s2 = AnyConverter.convert(factor2, resultType); if (resultType == Byte.class) return (Byte) s1 * (Byte) s2; else if (resultType == Short.class) return (Short) s1 * (Short) s2; else if (resultType == Integer.class) return (Integer) s1 * (Integer) s2; else if (resultType == Long.class) return (Long) s1 * (Long) s2; else if (resultType == Float.class) return (Float) s1 * (Float) s2; else if (resultType == Double.class) return (Double) s1 * (Double) s2; else if (resultType == BigInteger.class) return ((BigInteger) s1).multiply((BigInteger) s2); else if (resultType == BigDecimal.class) return ((BigDecimal) s1).multiply((BigDecimal) s2); else throw new UnsupportedOperationException("Multiplication of type " + BeanUtil.simpleClassName(factor1) + " with " + BeanUtil.simpleClassName(factor2) + " is not supported"); } public Object divide(Object dividend, Object divisor) { // null handling if (divisor == null) throw new IllegalArgumentException("Division by null"); if (dividend == null) return null; // arbitrary conversion Class resultType = TypeManager.combinedType(dividend.getClass(), divisor.getClass()); TypeArithmetic typeArithmetic = typeArithmetics.get(resultType); if (typeArithmetic != null) return typeArithmetic.multiply(dividend, divisor); Object s1 = AnyConverter.convert(dividend, resultType); Object s2 = AnyConverter.convert(divisor, resultType); if (resultType == Byte.class) return (Byte) s1 / (Byte) s2; else if (resultType == Short.class) return (Short) s1 / (Short) s2; else if (resultType == Integer.class) return (Integer) s1 / (Integer) s2; else if (resultType == Long.class) return (Long) s1 / (Long) s2; else if (resultType == Float.class) return (Float) s1 / (Float) s2; else if (resultType == Double.class) return (Double) s1 / (Double) s2; else if (resultType == BigInteger.class) return ((BigInteger) s1).divide((BigInteger) s2); else if (resultType == BigDecimal.class) return ((BigDecimal) s1).divide((BigDecimal) s2); else throw new UnsupportedOperationException( "Multiplication of type " + BeanUtil.simpleClassName(dividend) + " (" + dividend + ") with " + BeanUtil.simpleClassName(divisor) + " (" + divisor + ") is not supported"); } @SuppressWarnings({ "unchecked", "rawtypes" }) public boolean less(Object part1, Object part2) { // null handling if (part2 == null || part1 == null) throw new IllegalArgumentException("Cannot compare null"); Class resultType = TypeManager.combinedType(part1.getClass(), part2.getClass()); // convert the terms to the same type and compare them Object s1 = AnyConverter.convert(part1, resultType); Object s2 = AnyConverter.convert(part2, resultType); if (Comparable.class.isAssignableFrom(resultType)) return (((Comparable) s1).compareTo(s2) < 0); else throw new UnsupportedOperationException("Cannot compare type " + BeanUtil.simpleClassName(part1) + " with " + BeanUtil.simpleClassName(part2)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public boolean lessOrEquals(Object part1, Object part2) { // null handling if (part2 == null || part1 == null) throw new IllegalArgumentException("Cannot compare null"); Class resultType = TypeManager.combinedType(part1.getClass(), part2.getClass()); // convert the terms to the same type and compare them Object s1 = AnyConverter.convert(part1, resultType); Object s2 = AnyConverter.convert(part2, resultType); if (Comparable.class.isAssignableFrom(resultType)) return (((Comparable) s1).compareTo(s2) <= 0); else throw new UnsupportedOperationException("Cannot compare type " + BeanUtil.simpleClassName(part1) + " with " + BeanUtil.simpleClassName(part2)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public boolean equals(Object part1, Object part2) { // null handling if (part2 == null && part1 == null) return true; if (part2 == null || part1 == null) return false; // comparing non-null values Class resultType = TypeManager.combinedType(part1.getClass(), part2.getClass()); // convert the terms to the same type and compare them Object s1 = AnyConverter.convert(part1, resultType); Object s2 = AnyConverter.convert(part2, resultType); if (Comparable.class.isAssignableFrom(resultType)) return (((Comparable) s1).compareTo(s2) == 0); else throw new UnsupportedOperationException("Cannot compare type " + BeanUtil.simpleClassName(part1) + " with " + BeanUtil.simpleClassName(part2)); } public Boolean greater(Object o1, Object o2) { return less(o2, o1); } public Boolean greaterOrEquals(Object o1, Object o2) { return !less(o1, o2); } public Object bitwiseAnd(Object o1, Object o2) { Class resultType = TypeManager.combinedType(o1.getClass(), o2.getClass()); if (resultType == Boolean.class) return ((Boolean) o1).booleanValue() & ((Boolean) o2).booleanValue(); if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number or boolean: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number or boolean: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (resultType == Integer.class) return n1.intValue() & n2.intValue(); else if (resultType == Long.class) return n1.longValue() & n2.longValue(); else if (resultType == Short.class) return n1.shortValue() & n2.shortValue(); else if (resultType == Long.class) return n1.byteValue() & n2.byteValue(); else throw new IllegalStateException("Illegal state for " + resultType.getName()); } public Object bitwiseOr(Object o1, Object o2) { Class resultType = TypeManager.combinedType(o1.getClass(), o2.getClass()); if (resultType == Boolean.class) return ((Boolean) o1).booleanValue() | ((Boolean) o2).booleanValue(); if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number or boolean: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number or boolean: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (resultType == Integer.class) return n1.intValue() | n2.intValue(); else if (resultType == Long.class) return n1.longValue() | n2.longValue(); else if (resultType == Short.class) return n1.shortValue() | n2.shortValue(); else if (resultType == Long.class) return n1.byteValue() | n2.byteValue(); else throw new IllegalStateException("Illegal state for " + resultType.getName()); } public Object bitwiseExclusiveOr(Object o1, Object o2) { Class resultType = TypeManager.combinedType(o1.getClass(), o2.getClass()); if (resultType == Boolean.class) return ((Boolean) o1).booleanValue() ^ ((Boolean) o2).booleanValue(); if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number or boolean: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number or boolean: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (resultType == Integer.class) return n1.intValue() ^ n2.intValue(); else if (resultType == Long.class) return n1.longValue() ^ n2.longValue(); else if (resultType == Short.class) return n1.shortValue() ^ n2.shortValue(); else if (resultType == Long.class) return n1.byteValue() ^ n2.byteValue(); else throw new IllegalStateException("Illegal state for " + resultType.getName()); } public Object shiftLeft(Object o1, Object o2) { if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (n1 instanceof Integer) return n1.intValue() << n2.intValue(); else if (n1 instanceof Long) return n1.longValue() << n2.intValue(); else if (n1 instanceof Short) return n1.shortValue() << n2.intValue(); else if (n1 instanceof Byte) return n1.byteValue() << n2.intValue(); else throw new IllegalArgumentException("Cannot shift " + BeanUtil.simpleClassName(o1)); } public Object shiftRight(Object o1, Object o2) { if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (n1 instanceof Integer) return n1.intValue() >> n2.intValue(); else if (n1 instanceof Long) return n1.longValue() >> n2.intValue(); else if (n1 instanceof Short) return n1.shortValue() >> n2.intValue(); else if (n1 instanceof Byte) return n1.byteValue() >> n2.intValue(); else throw new IllegalArgumentException("Cannot shift " + BeanUtil.simpleClassName(o1)); } public Object shiftRightUnsigned(Object o1, Object o2) { if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (n1 instanceof Integer) return n1.intValue() >>> n2.intValue(); else if (n1 instanceof Long) return n1.longValue() >>> n2.intValue(); else if (n1 instanceof Short) return n1.shortValue() >>> n2.intValue(); else if (n1 instanceof Byte) return n1.byteValue() >>> n2.intValue(); else throw new IllegalArgumentException("Cannot shift " + BeanUtil.simpleClassName(o1)); } public Object mod(Object o1, Object o2) { if (!(o1 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o1); if (!(o2 instanceof Number)) throw new IllegalArgumentException("Not a number: " + o2); Number n1 = (Number) o1; Number n2 = (Number) o2; if (n1 instanceof Integer) return n1.intValue() % n2.intValue(); else if (n1 instanceof Long) return n1.longValue() % n2.intValue(); else if (n1 instanceof Short) return n1.shortValue() % n2.intValue(); else if (n1 instanceof Byte) return n1.byteValue() % n2.intValue(); else if (n1 instanceof BigInteger) return ((BigInteger) n1).mod((BigInteger) n2); else throw new IllegalArgumentException("Cannot calculate the modulo of " + BeanUtil.simpleClassName(o1)); } public Object logicalComplement(Object value) { if (!(value instanceof Boolean)) throw new IllegalArgumentException("Not a boolean: " + value); return !((Boolean) value).booleanValue(); } public Object bitwiseComplement(Object value) { if (!(value instanceof Number)) throw new IllegalArgumentException("Not a number: " + value); Number number = (Number) value; if (number instanceof Integer) return ~ number.intValue(); else if (number instanceof Long) return ~ number.longValue(); else if (number instanceof Short) return ~ number.shortValue(); else if (number instanceof Byte) return ~ number.byteValue(); else throw new IllegalArgumentException("Cannot complement " + BeanUtil.simpleClassName(value)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy