Variable Math

In MAPPER, operators like +, -, and * perform math on variables in commands like @ART, @CHG and @CAL. The MJ variable classes support similar mathematical operations and functions via the IMathOperators and IMathFunctions interfaces. Only MJDecimal, MJInteger and MJVariant implement these interfaces; while MJ supports math involving MJString variables, it follows Java's strong typing by encouraging math on numbers and discouraging math on strings.

MJ also provides formulas as a convenient way to perform math with variables; internally, formulas make use of the IMathOperators and IMathFunctions interfaces.

Interface IMathOperators

Here are the binary and unary mathematical methods available in IMathOperators:

MAPPER Operator Description IMathOperators Method
+ Addition: a+b add
- Subtraction: a-b subtract
/ Division: a/b divide
// Integer division: a//b. Gives the unrounded integer portion of the dividend of value a divided by value b. divideToIntegralValue
* Multiplication: a*b multiply
** Exponentiation: a**b. Gives the result of value a raised to the power of value b. pow
- Unary minus: -a. Gives the negative of value a. negate

The IMathOperators interface also supports increment and decrement as the equivalent of MAPPER @INC and @DEC.

Interface IMathFunctions

The mathematical functions supported by @ART and @CAL are available in IMathFunctions:

MAPPER Function Description IMathFunctions Method
ABS(x) Absolute value or magnitude of x. abs
MOD(x,y) Modulus; remainder value of x/y. mod
FRAC(x) Fractional portion of x. frac
INT(x) Integer portion of x. intf
SQRT(x) Square root of x. sqrt

Methods similar to trigonometric functions like ACOS(x), DEG(x) and LOG(x) are also present in IMathFunctions.

Examples of Math with MJ Numeric Variables

Here are examples of mathematical methods and functions supported by MJDecimal and MJInteger:

//////////////////// Addition (@CHG) ////////////////////////////////////
// @LDV <decVar>f3.2=9.428 .
// @CHG <sumVar>f7.3 <decVar> + 22 .

MJDecimal decVar = new MJDecimal(VariableScope.LOCAL, 3, 2, new BigDecimal("9.428"));
Number sum = decVar.add(22L, EnumSet.of(MathOption.EVALUATE_JAVA_TYPE));
assert sum instanceof BigDecimal;
MJDecimal sumVar = new MJDecimal(VariableScope.LOCAL, 7, 3, (BigDecimal) sum);
assert "31.428".equals(sumVar.toMapperNumericString());

//////////////////// Subtraction (@ART) /////////////////////////////////
// @LDV <sub1>f4.2=10.8765, <sub2>f4.2=-1.43 .
// @ART <sub1>-<sub2> <diffVar>f18.17 .

MJDecimal sub1 = new MJDecimal(VariableScope.LOCAL, 4, 2, new BigDecimal("10.8765"));
MJDecimal sub2 = new MJDecimal(VariableScope.LOCAL, 4, 2, new BigDecimal("-1.43"));
Number diff = sub1.subtract(sub2, EnumSet.of(MathOption.EVALUATE_MAPPER_TYPE));
assert diff instanceof BigDecimal;
MJDecimal diffVar = new MJDecimal(VariableScope.LOCAL, 18, 17, (BigDecimal) diff);
assert "12.300000000000000".equals(diffVar.toMapperNumericString());

//////////////////// Multiplication (@CHG) //////////////////////////////
// @LDV <mpc>i9=987654321, <mpi>i8=86453095 .
// @CHG <intRslt>i16 <mpc> * <mpi> .

MJInteger mpc = new MJInteger(VariableScope.LOCAL, 9,
  EnumSet.noneOf(LoadOption.class), "987654321");
MJInteger mpi = new MJInteger(VariableScope.LOCAL, 8,
  EnumSet.noneOf(LoadOption.class), "86453095");
Number prod = mpc.multiply(mpi, EnumSet.of(MathOption.EVALUATE_JAVA_TYPE));
assert prod instanceof Long;
MJInteger intRslt = new MJInteger(VariableScope.LOCAL, 16, ((Long) prod).longValue());
assert "8.53857728406E16".equals(intRslt.toMapperNumericString());

//////////////////// Division (@CHG) ////////////////////////////////////
// @LDV <dvd>i4=22, <dvi>i4=7 .
// @CHG <fltPi>f18.17 <dvd> / <dvi> .

MJInteger dvd = new MJInteger(VariableScope.LOCAL, 4,
  EnumSet.noneOf(LoadOption.class), "22");
MJInteger dvi = new MJInteger(VariableScope.LOCAL, 4,
  EnumSet.noneOf(LoadOption.class), "7");
Number quot = dvd.divide(dvi, EnumSet.of(MathOption.EVALUATE_JAVA_TYPE,
  MathOption.PREFER_DECIMAL_OVER_FLOAT));
assert quot instanceof BigDecimal;
MJDecimal fltPi = new MJDecimal(VariableScope.LOCAL, 18, 17, (BigDecimal) quot);
assert "3.1428571428571400".equals(fltPi.toMapperNumericString());

//////////////////// Integer Division (@CHG) ////////////////////////////
// @LDV <dvd>i4=22, <dvi>i4=7 .
// @CHG <fltPi>f18.17 <dvd> // <dvi> .

Number iq = dvd.divideToIntegralValue(dvi, EnumSet.of(MathOption.EVALUATE_JAVA_TYPE));
assert iq instanceof Long;
MJDecimal fltIQ = new MJDecimal(VariableScope.LOCAL, 18, 17,
  BigDecimal.valueOf(((Long) iq).longValue(), 0));
assert "3.0000000000000000".equals(fltIQ.toMapperNumericString());

//////////////////// Exponentiation (@ART) //////////////////////////////
// @LDV <exp>i2=-2, <base>f3=-10.0 .
// @ART <base>**<exp> <fltPow>f18.17 .

MJDecimal base = new MJDecimal(VariableScope.LOCAL, 3, 0,
  EnumSet.noneOf(LoadOption.class), "-10.0");
MJInteger exp = new MJInteger(VariableScope.LOCAL, 2,
  EnumSet.noneOf(LoadOption.class), "-2");
Number power = base.pow(exp, EnumSet.of(MathOption.EVALUATE_MAPPER_TYPE));
assert power instanceof BigDecimal;
MJDecimal fltPow = new MJDecimal(VariableScope.LOCAL, 18, 17, (BigDecimal) power);
assert "0.0100000000000000".equals(fltPow.toMapperNumericString());

//////////////////// FRAC function (@ART) ///////////////////////////////
// @LDV <fnum>f3.2=1.23 .
// @ART FRAC(<fnum>) <fracRslt>f12.4 .

MJDecimal fnum = new MJDecimal(VariableScope.LOCAL, 3, 2,
  EnumSet.noneOf(LoadOption.class), "1.23");
Number frac = fnum.frac(EnumSet.of(MathOption.EVALUATE_MAPPER_TYPE,
  MathOption.PREFER_DECIMAL_OVER_FLOAT));
assert frac instanceof BigDecimal;
MJDecimal fracRslt = new MJDecimal(VariableScope.LOCAL, 12, 4, (BigDecimal) frac);
assert "0.2000".equals(fracRslt.toMapperNumericString());

//////////////////// MOD function (@ART) ///////////////////////////////
// @LDV <mdvd>f6.4=-4.4857, <mdiv>i1=2 .
// @ART MOD(<mdvd>,<mdiv>) <modRslt>f4 .

MJDecimal mdvd = new MJDecimal(VariableScope.LOCAL, 6, 4,
  EnumSet.noneOf(LoadOption.class), "-4.4857");
MJInteger mdiv = new MJInteger(VariableScope.LOCAL, 4,
  EnumSet.noneOf(LoadOption.class), "2");
Number mod = mdvd.mod(mdiv, EnumSet.of(MathOption.EVALUATE_MAPPER_TYPE,
  MathOption.PREFER_DECIMAL_OVER_FLOAT));
assert mod instanceof BigDecimal;
MJDecimal modRslt = new MJDecimal(VariableScope.LOCAL, 4, 0, (BigDecimal) mod);
assert "-0.5".equals(modRslt.toMapperNumericString());