API Docs for: 1.0

src/js/Calculation.js

/*! @file Calculation.js */

/*
 * part of the 'Transfinite Ordinal Calculator'
 * author: Claudio Kressibucher
 * license: GNU LGPL
 */

/* JSHINT global declaration */
/*global oGui:true, util:true, config:true, ClassedError:true, Ord:true, OrdSummand:true, model:true, Calculation:true */

// ============================================================ //
// ===== 01) Constructor ====================================== //
// ============================================================ //
/**
 * Class to compute the result of an operation
 * of two ordinal numbers.
 *
 * The intended usage to perform an arithmetic operation is as follows:
 * First, you create a Calculation object by invoking the constructor.
 * Then you invoke the simplify-Method on the object, which returns
 * a normalized Ordinal as an object of type Ord.
 * When comparing two Ordinals (type Ord) against each other,
 * directly call the static Calculation.compare method.
 * All other methods should not be used from outside the class.
 *
 * @class Calculation
 * @constructor
 * @param {Operand / Ord / OrdSummand / number} leftOpnd
 * @param {Operand / Ord / OrdSummand / number} rightOpnd
 * @param {Operator} optor
 */
Calculation = function Calculation(leftOpnd, rightOpnd, optor){
	// cache the enumType object literal
	var eT = model.enumType;
	
	/**
	 * The left operand.
	 * @property left
	 * @type Ord
	 */
	this.left = null;
	/**
	 * The right operand.
	 * @property right
	 * @type Ord
	 */
	this.right = null;
	/**
	 * The operator. Possible values are "^", "*", "+".
	 * @property optor
	 * @type string
	 */
	this.optor = optor.getSymbol();
	/**
	 * If there is an error message, then that indicates that an
	 * error has occurred
	 * @property calcErr
	 * @type ClassedError
	 * @private
	 */
	this.calcErr = null;
	
	if (config.debug > 0){
			util.assert(optor.getType() === eT.tOptor,
					"Calculation construtor: wrong type of operator");
	}
	
	// get left operand as instance of Ord
	if (leftOpnd instanceof Ord){
		this.left = leftOpnd;
	} else if (leftOpnd instanceof OrdSummand) {
		this.left = new Ord(leftOpnd);
	} else if (typeof(leftOpnd) === 'number'){
		this.left = new Ord(leftOpnd);
	} else if (leftOpnd instanceof model.Operand){
		this.left = leftOpnd.getOrd();
	} else {
		oGui.dbgErr("Calculation constructor: wrong type of left Operand");
	}
	
	// the same for the right operand
	if (rightOpnd instanceof Ord){
		this.right = rightOpnd;
	} else if (rightOpnd instanceof OrdSummand) {
		this.right = new Ord(rightOpnd);
	} else if (typeof(rightOpnd) === 'number'){
		this.right = new Ord(rightOpnd);
	} else if (rightOpnd instanceof model.Operand) {
		this.right = rightOpnd.getOrd();
	} else {
		oGui.dbgErr("Calculation constructor: wrong type of right Operand");
	}
};

Calculation.maxNatural = 1000000000; // 10^9 is the maximal natural number that's allowed (due to inaccurracy caused by floating point arithmetic)

//============================================================ //
//===== 02) Public Functions ================================= //
//============================================================ //
/**
 * Simplifies the expression consisting of left operand,
 * right operand and operator.
 * @method simplify
 * @return {Ord} The result of the calculation as a normalized
 * object of type Ord.
 */
Calculation.prototype.simplify = function simplify(){
	var res = null; // the result to return
		
	switch(this.optor){
	case '^':
		res = this.expOrdinals();
		break;
		
	case '*':
		res = this.multiplyOrdinals();
		break;
		
	case '+':
		res = this.sumOrdinals();
		break;
	}

	if (this.calcErr !== null){
		res = null;
	} else if (res === null || res === false || res.isUndefined()){
		this.calcErr = this.calcErr || new ClassedError("unknown Calculation error", ClassedError.types.calcError);
		res = null;
	} else {
		res.cleanUp();
	}
	return res;
};

/**
 * The main compare function. Use this method from outside the
 * Calculation class to compare two ordinals -- which may also
 * be of type 'number' -- against each other.
 * @method compare
 * @param {Ord / number} a The first operand. Might be an instance of Ord
 *  or a simple integer of type 'number'.
 * @param {Ord / number} b The second operand. Same type conventions.
 * @return {number} The result. A value greater 0 means that a is greater
 * than b, a value less than 0 means that b is greater than a, and the value
 * 0 means that a and b are equal.
 * @static
 */
Calculation.compare = function compare(a, b){
	var tCmp; // temporary comparison result
	var cmpValue = null;
	
	if (! (a instanceof Ord) ){
		if (b instanceof Ord){
			// a is a natural number, b is an Ordinal
			cmpValue = Calculation.cmpNaturalOrdinal(a, b);
		} else {
			// a and b are natural numbers
			cmpValue = Calculation.cmpNatural(a, b);
		}
	} else { // a is Ordinal (type Ord)
		if (! (b instanceof Ord) ){
			// a is an Ordinal, b is a natural number
			tCmp = Calculation.cmpNaturalOrdinal(b, a);
			cmpValue = (-1) * tCmp;
		} else {
			// a and b are both ordinals
			cmpValue = Calculation.compareOrdinals(a, b);
		}
	}
	
	if (cmpValue === null){
		oGui.dbgErr("Calculation.compare: Comparision failed, result is null");
	}
	return cmpValue;
};

Calculation.prototype.getError = function getError(){
	var tmp;
	if (this.calcErr !== null){
		tmp = this.calcErr;
		this.calcErr = null;
		return tmp;
	}
	return null;
};

//============================================================ //
//===== 03) main arithmetic functions ======================== //
//========= (object methods) ================================= //
//============================================================ //

/**
 * Calculates the ordinal sum of (left + right).
 * @method sumOrdinals
 * @return {Ord} the result
 * @private
 */
Calculation.prototype.sumOrdinals = function sumOrdinals(){
	var a = this.left;
	var b = this.right;
	
	var res; // the result
	var i = 0; // index of left operand's current summand
	var j = 0; // index of right operand's current summand
	var sumA; // current summand of left operand
	var sumB; // current summand of right operand
	var expA, expB; // exponents of sumA and sumB
	var tmpFactor; // temporary factor
	
	if (! this.checkOpnds()){
		oGui.dbgErr("error occurred in Calculation.sumOrdinals");
		return null;
	}

	res = new Ord();
	
	sumA = a.getSummand(i);
	sumB = b.getSummand(j);
	expA = sumA.getExponent();
	expB = sumB.getExponent();
	
	while ( Calculation.compare(expA, expB) > 0 ){ // while expA > expB: add terms of a
		res.addSummand(sumA);
		i++;
		if (i >= a.getNumOfSumds()){
			break;
		}
		sumA = a.getSummand(i);
		expA = sumA.getExponent();
	}

	// add first term of b
	tmpFactor = sumB.getFactor();
	if ( i < a.getNumOfSumds() && Calculation.compare(expA, expB) === 0 ){ // a has term with the same exponent: increase factor of term
		tmpFactor += sumA.getFactor();
		if (!Calculation.sIsValidNatural(tmpFactor)) {
			this.calcErr = this.calcErr || new ClassedError("natural factor " + tmpFactor + " is too great and could cause inaccurate calculations.", ClassedError.types.inaccurate);
			return null;
		}
	}
	res.addSummand( new OrdSummand(expB, tmpFactor) );
	
	// increase index of operand b
	j++;
		
	while ( j < b.getNumOfSumds() ){ // add the rest of b's terms
		res.addSummand( b.getSummand(j) );
		j++;
	}
	
	return res;
};

/**
 * Calculates the ordinal (left * right).
 * @method multiplyOrdinals
 * @return {Ord} the result
 * @private
 */
Calculation.prototype.multiplyOrdinals = function multiplyOrdinals(){
	var res;
	
	var a = this.left;
	var b = this.right;
	
	var i = 0; // index of left operand's current summand
	var j = 0; // index of right operand's current summand
	var sumA; // current summand of left operand
	var sumB; // current summand of right operand
	var expA, expB; // exponents of sumA and sumB
	
	var tmpFac; // temporary factor
	var tmpExp; // temporary exponent
	var calc;
	
	if (! this.checkOpnds()){
		oGui.dbgLog("error occurred in Calculation.multiplyOrdinals");
		return null;
	}
	
	res = new Ord();

	if (a.equalsNull() || b.equalsNull()){
		return new Ord(0);
	}
		
	sumA = a.getSummand(i);
	sumB = b.getSummand(j);
	expA = sumA.getExponent();
	expB = sumB.getExponent();
	
	while( Calculation.compare(0, expB) < 0  ){ // expB > 0
		calc = new Calculation(expA, expB, new model.Operator('+'));
		tmpExp = calc.sumOrdinals();
		res.addSummand( new OrdSummand(tmpExp, sumB.getFactor()) );
		j++;
		if (j >= b.getNumOfSumds()){ // no summands left
			break;
		}
		sumB = b.getSummand(j);
		expB = sumB.getExponent();
	}

	if (j < b.getNumOfSumds()){ // there's one natural summand left in b
		tmpFac = sumA.getFactor() * sumB.getFactor();
		if (!Calculation.sIsValidNatural(tmpFac)){
			this.calcErr = this.calcErr || new ClassedError("muliplication: natural factor too large...", ClassedError.types.inaccurate);
			return null;
		}
		res.addSummand( new OrdSummand(expA, tmpFac) );
		i++;
		while(i < a.getNumOfSumds()){ // there are some summands left in a
			sumA = a.getSummand(i);
			// expA = sumA.getExponent();
			// res.addSummand( new OrdSummand(expA, sumA.getFactor()) );
			res.addSummand( sumA );
			i++;
		}
	}
	
	if (res.isUndefined()){
		oGui.dbgWarn("Calculation.multiplyOrdinals: res has no summand at the end of calculation... return null");
		this.calcErr = this.calcErr || new ClassedError("unknown calculation error", ClassedError.types.calcError);
		res = null;
	}
	return res;
};

/**
 * Calculates the ordinal (left ^ right).<br />
 * Might pass through an exception from the method sFinitePower
 * @method expOrdinals
 * @return {Ord} the result
 * @private
 */
Calculation.prototype.expOrdinals = function(){
	var res = null;
	
	var a = this.left;
	var b = this.right;
	
	var num;
	
	var i; // index of right operand's current summand
	var bLen; // length of right operand (number of terms)

	var tmpOrd1, tmpOrd2, tmpSum = null, tmpExp, tmpFac;
	
	var eHasNatTerm = false; // boolean flag, if exponent has a natural term
	
	if (! this.checkOpnds()){
		oGui.dbgLog("error occurred in Calculation.multiplyOrdinals");
		return null;
	}
	
	if (b.isNatural()){
		if (a.isNatural()) {
			// a < omega, b < omega => natural exponentiation
			num = Math.pow(a.getSummand(0).getFactor(), b.getSummand(0).getFactor());
			if (!Calculation.sIsValidNatural(num)){
				this.calcErr = this.calcErr || new ClassedError( "exponentiation: natural number is too large...", ClassedError.types.inaccurate);
				return null;
			}
			res = new Ord( num );
		} else {
			// a >= omega, b < omega
			// finite exponentiation
			res = Calculation.sFinitePower(a, b.getSummand(0).getFactor(), this);
		}
	} else {
		// b >= omega
		if (a.equalsNull()){
			res = new Ord(0); // 0^b = 0 (if b > 0)
		} else if (a.equalsOne()){
			res = new Ord(1); // 1^b = 1
		} else if (a.isNatural()) {
			// 1 < a < omega, b >= omega
			bLen = b.getNumOfSumds();
			tmpOrd1 = new Ord(); // this Ord is the exponent of the only term of the result
			
			for (i = 0; i < bLen; i++){
				tmpSum = b.getSummand(i);
				tmpExp = tmpSum.getExponent();
				if ( ! Calculation.sIsValueNull(tmpExp) ){
					tmpOrd2 = Calculation.decreaseOne( tmpExp ); // b(i).exp - 1
					tmpOrd1.addSummand( new OrdSummand(tmpOrd2, tmpSum.getFactor()) );
				} else {
					eHasNatTerm = true;
					if (config.debug > 0){
						util.assert(i === bLen-1); // should be the last summand!
					}
				}
			}
			
			if (eHasNatTerm === true){ // natural term in exponent
				tmpFac = Math.pow(a.getSummand(0).getFactor(), tmpSum.getFactor());
				if (!Calculation.sIsValidNatural(tmpFac)){
					this.calcErr = this.calcErr || new ClassedError( "exponentiation: natural factor is too large...", ClassedError.types.accurate);
					return null;
				}
			} else {
				tmpFac = 1;
			}
			
			res = new Ord( new OrdSummand(tmpOrd1, tmpFac) );
		} else {
			// a >= omega, b >= omega
			res = Calculation.sInfPower(a, b, this);
		}
	}
	
	if (res === null || res === false || res.isUndefined()){
		oGui.dbgErr('Calculation.expOrdinals: res is null or undefined');
		this.calcErr = this.calcErr || new ClassedError("unknown calc error", ClassedError.types.calcError);
		res = null;
	}
	return res;
};

//============================================================ //
//===== 04) arithmetic helper functions ====================== //
//============================================================ //

/**
 * Helper method for expOrdinals(): Calculates the power
 * of an infinite base and a finite exponent.
 * Should only be used from inside the Calculation class.<br />
 * Throws an error (of type ClassedError) when the exponent is too great.
 * @method sFinitePower
 * @param {Ord} oBase The Base. Must be an Ordinal. (And should be
 * greater than / equal to omega).
 * @param {number} nExp The exponent. Must be an instance of number!
 * @param {Calculation} cObj Optional. If defined, the static method can
 * register an error to the object.
 * @return {Ord} result The result of the exponentiation.
 * @static
 * @private
 */
Calculation.sFinitePower = function sFinitePower(oBase, nExp, cObj){
	var i = 0;
	var j = 0;
	var sumA; // summand of oBase
	var expA; // exponent of sumA
	var nk; // factor of natural term of oBase
	var staticFactor;
	
	var res;
	
	var tmpExp;
	var num;
	var calc;

	var firstExpA;
	var staticExp;

	var maxExp = 25; // the maximum allowed exponent, if the base Ord contains a natural term (prevents results with too many terms).
	
	// check operands (special!)
	if (! oBase instanceof Ord){
		oGui.dbgErr("Calclulation.sFinitePower: wrong type of argument oBase");
		return null;
	}
	if (typeof(nExp) !== 'number'){
		oGui.dbgErr("Calclulation.sFinitePower: wrong type of argument nExp");
		return null;
	}
	// check basic operations (for stability reasons...)
	if (oBase.isNatural()){
		num = Math.pow( oBase.getSummand(0).getFactor(), nExp );
		if (!Calculation.sIsValidNatural(num)){
			oGui.dbgWarn("exponentiation: natural factor too large");
			if (cObj){
				cObj.calcErr = cObj.calc || new ClassedError( "exponentiation: natural factor is too large ...", ClassedError.types.inaccurate);
			}
			return null;
		}
		return new Ord( num );
	}
	if (nExp === 0){
		return new Ord(1);
	}
	if (nExp === 1){
		return oBase;
	}
	// normal cases: oBase >= omega; 1 < nExp < omega
	sumA = oBase.getSummand(0);
	expA = sumA.getExponent();
	firstExpA = expA;
	
	res = new Ord();
	
	// terms with exponent > 0 (limes terms)
	calc = new Calculation(firstExpA, nExp-1, new model.Operator('*'));
	staticExp = calc.multiplyOrdinals();
	do {
		sumA = oBase.getSummand(i);
		expA = sumA.getExponent();
		if (Calculation.sIsValueNull(expA)) {
			break;
		}
		calc = new Calculation(staticExp, expA, new model.Operator('+'));
		tmpExp = calc.sumOrdinals();
		// now tmpExp is a_1 *(nExp-1) + a_i
		res.addSummand(new OrdSummand(tmpExp, sumA.getFactor()));
		i++;
	} while(i < oBase.getNumOfSumds());
	
	if (Calculation.sIsValueNull(expA)){ // operand oBase has a natural term
		if (nExp > maxExp){
			// too many terms in result: cancel operation
			oGui.dbgWarn("sFinitePower: too many terms");
			if (cObj){
				cObj.calcErr = cObj.calcErr || new ClassedError("too many terms for this small display... The exponent for this type of " +
						"exponentiation should be less than " + (maxExp+1) + ".", ClassedError.types.finExpTooLarge);
			}
			return null;
		}
		nk = sumA.getFactor();
		if (nk <= 0) {
			// ignore term "+0" in base operand
			return res;
		}
		staticFactor = oBase.getSummand(0).getFactor() * nk;
		if (!Calculation.sIsValidNatural(staticFactor)){
			oGui.dbgErr("sFinitePower: invalid factor");
			if (cObj){
				cObj.calcErr = cObj.calcErr || new ClassedError( "exponentiation: natural factor is too large ...", ClassedError.types.inaccurate);
			}
			return null;
		}
		for(j = 1; j < nExp; j++){
			calc = new Calculation(firstExpA, nExp-j, new model.Operator('*'));
			tmpExp = calc.multiplyOrdinals();
			res.addSummand(new OrdSummand(tmpExp, staticFactor));
			i = 1;
			while(i < (oBase.getNumOfSumds()-1)){ // stop before the last term cause we already know that it has exponent 0
				sumA = oBase.getSummand(i);
				expA = sumA.getExponent();
				if (config.debug > 0){
					util.assert(expA !== 0 && !(expA instanceof Ord && expA.equalsNull())); // expA is not 0
				}
				calc = new Calculation(firstExpA, nExp-j-1, new model.Operator('*'));
				tmpExp = calc.multiplyOrdinals();
				if (tmpExp === null)
					return null;
				calc = new Calculation(tmpExp, expA, new model.Operator('+'));
				tmpExp = calc.sumOrdinals();
				if (tmpExp === null)
					return null;
				res.addSummand( new OrdSummand(tmpExp, sumA.getFactor()) );
				i++;
			}
		}
		res.addSummand( new OrdSummand(0, nk) );
	}

	return res;
};

/**
 * Helper method for expOrdinals(): Calculates the power
 * of an infinite base and an infinite exponent.
 * Should only be used from inside the Calculation class.
 * @method sInfPower
 * @param {Ord} oBase The Base. Must be an Ord AND must be
 * greater than / equal to omega.
 * @param {Ord} oExp The exponent. Must be an instance of Ord
 * @param {Calculation} cObj Optional. If defined, the static method can
 * register an error to the object.
 * @return {Ord} The result.
 * @static
 * @private
 */
Calculation.sInfPower = function sInfPower(oBase, oExp, cObj){
	var res = null;
	
	var firstSumBase;
	var firstExpBase;
	
	var i; // index of right operand's current summand
	var eLen; // length of right operand (number of terms)
	var sumE = null; // current summand of right operand
	var expE;

	var tmpOrd1, tmpOrd2;
	var calc;
	
	var eHasNatTerm = false; // flag, if exponent has a natural term

	// check operands
	if (! oBase instanceof Ord || ! oExp instanceof Ord){
		oGui.dbgErr('Calculation.sInfPower: one of the operands is not of type Ord');
		return null;
	}
	
	// check basic operations (just for stability)
	if (oExp.isNatural()){
		oGui.dbgWarn('Calculation.sInfPower: exponent should not be natural');
		return Calculation.sFinitePower(oBase, oExp.getSummand(0).getFactor());
	}
	if (oBase.isNatural()){
		oGui.dbgErr('Calculation.sInfPower: The base operand must not be natural');
	} else {
		// oBase >= omega; oExp >= omega
		eLen = oExp.getNumOfSumds();
		firstSumBase = oBase.getSummand(0);
		firstExpBase = firstSumBase.getExponent();
		
		tmpOrd1 = new Ord();

		for (i = 0; i < eLen; i++){
			sumE = oExp.getSummand(i);
			expE = sumE.getExponent();
			if ( ! Calculation.sIsValueNull(expE) ){
				tmpOrd1.addSummand(sumE);
			} else {
				eHasNatTerm = true;
				if (config.debug > 0) {
					util.assert(i === eLen-1); // should be the last summand!
				}
			}
		}
		
		calc = new Calculation(firstExpBase, tmpOrd1, new model.Operator('*'));
		tmpOrd2 = calc.multiplyOrdinals();
		if (tmpOrd2 === null)
			return null;
		res = new Ord( new OrdSummand(tmpOrd2, 1) );
		
		if (eHasNatTerm === true){ // natural term in exponent
			tmpOrd2 = Calculation.sFinitePower(oBase, sumE.getFactor(), cObj);
			if (tmpOrd2 === null)
				return null;
			calc = new Calculation(res, tmpOrd2, new model.Operator('*'));
			res = calc.multiplyOrdinals();
		}
	}
	
	if (res === null || res === false || res.isUndefined()){
		if (cObj){
			cObj.calcErr = cObj.calcErr || new ClassedError("unknown calc error", ClassedError.types.calcError);
		}
		res = null;
	}
	return res;
};

/**
 * Compare an Operand of type Ord with a primitive integer operand.
 * @method cmpNaturalOrdinal
 * @param {number} natural
 * @param {Ord} ordinal
 * @return {number} If natural is greater than ordinal, a value greater 0;
 *  If natural and ordinal are the same size, the value 0;
 *  and if natural is less than ordinal, a value less than 0 is returned.
 * @static
 * @private
 */
Calculation.cmpNaturalOrdinal = function(natural, ordinal){
	var first; // first summand
	var fac; // factor of first
	
	if (ordinal.isUndefined()){
		return null;
	}
	first = ordinal.getSummand(0);
	
	if (ordinal.isNatural()){
		fac = first.getFactor();
		if (natural > fac){
			return 1;
		} else if (natural < fac){
			return -1;
		} else {
			return 0;
		}
	}

	// otherwise the ordinal is greater...
	return -1;
};

/**
 * Compare two integers (type "number") operands.
 * @method cmpNatural
 * @param {number} a
 * @param {number} b
 * @return {Number} A value greater 0 if argument a is greater than b,
 * a value less than 0 if a is less than b,
 * and the value 0 if a is equal to b
 * @private
 * @static
 */
Calculation.cmpNatural = function(a, b){
	if (config.debug > 0){
		util.assert(typeof(a) === "number" && typeof(b) === "number",
				"Calculation.cmpNatural: Arguments have types other than number...");
	}
	if (a > b) {
		return 1;
	}
	if (a < b) {
		return -1;
	}
	return 0;
};

/**
 * Compare the value of two Ordinal numbers (objects of type Ord).
 * @method compareOrdinals
 * @param {Ord} a The first value to compare
 * @param {Ord} b The second value to compare
 * @return {Number} A value greater 0 if argument a is greater than b,
 * a value less than 0 if a is less than b,
 * and the value 0 if a is equal to b
 * @static
 */
Calculation.compareOrdinals = function compareOrdinals(a, b){
	var sumA;
	var sumB;
	var i = 0;
	var j = 0;
	var cmpSumds;
	
	if (config.debug > 0){
		util.assert(a instanceof Ord && b instanceof Ord);
	}
	
	// compare summands
	while (i < a.getNumOfSumds() && j < b.getNumOfSumds()){
		sumA = a.getSummand(i);
		sumB = b.getSummand(j);
		// compare summands
		cmpSumds = sumA.isGreaterThan(sumB);
		if (cmpSumds !== 0){
			return cmpSumds;
		}
		// summands are equal: continue with next ones
		i++;
		j++;
	}
	
	// one ordinal has reached the end of it's list of summands
	if (i >= a.getNumOfSumds()){ // compare j-th summand of b with 0
		if (j >= b.getNumOfSumds() ||
				b.getSummand(j).getFactor() <= 0){
			return 0; // both ordinals have reached the end...
		}
		// j-th summand of b is greater than 0 => b is greater than a
		return -1;
	} else {
		if (config.debug > 0){
			util.assert( (j >= b.getNumOfSumds()), "Error in Calculation.compareOrdinals");
		}
		// a has summand, b not => compare i-th summand of a with 0
		if (a.getSummand(i).getFactor() <= 0){
			return 0;
		}
		return 1; // factor > 0 => a is greater than b
	}
};

/**
 * Decrease the argument "ord" by one, so
 * that: 1 + ( decreaseOne(ord) ) = ord.
 * @method decreaseOne
 * @param {Ord / number} ord
 * @return {Ord} The result as an Ord object
 * @static
 * @private
 */
Calculation.decreaseOne = function decreaseOne(ord){
	var o = Calculation.natToOrd(ord);
	if (o.isNatural()){
		return new Ord( o.getSummand(0).getFactor() - 1 );
	} else {
		return ord;
	}
};

/**
 * Static function to check if value is 0,
 * whether it is of type Ord or a number.
 * @method sIsValueNull
 * @param {Ord / number} val
 * @return {boolean} True, if val === 0 or val.equalsNull()
 * @static
 * @private
 */
Calculation.sIsValueNull = function(val){
	if (typeof(val) === 'number'){
		return val === 0;
	} else if (val instanceof Ord){
		return val.equalsNull();
	} else {
		oGui.progError("Calculation.sIsValueNull: wrong type of argument.");
	}
};

/**
 * Tests if a value is inside a range from 0 to Calculation.maxNatural.
 * Natural numbers shouldn't exceed this value in this application, as
 * there could result inaccurate calculations due to javascripts
 * floating arithmetic.
 * @method sIsValidNatural
 * @param {number} val The value to test
 * @return {boolean} True if val is a valid natural.
 */
Calculation.sIsValidNatural = function (val){
	if (typeof(val) !== 'number')
		return false;

	return isFinite(val) && val >= 0 && val <= Calculation.maxNatural;
};

//============================================================ //
//===== 05) other helper functions =========================== //
//============================================================ //

/**
 * Converts a value of type 'number' into an Ord object.
 * If num is already an Ord object, it will be returned unchanged.
 * @method natToOrd
 * @param {Ord / number} num
 * @return {Ord} The value num represented by an Ord object
 * @static
 */
Calculation.natToOrd = function natToOrd(num){
	if (typeof(num) === 'number'){
		return new Ord(num);
	}
	if (! (num instanceof Ord)){
		oGui.progError("Calculation.natToOrd: argument should be a natural number or an instance of Ord");
	}
	return num;
};

/**
 * Checks if the operands of the calculation object
 * are of type Ord and have at least
 * one summand (i.e. are not undefined).
 * @method checkOpnds
 * @return {boolean} True if operands are of type Ord and have
 *  one or more summands, False otherwise.
 * @private
 */
Calculation.prototype.checkOpnds = function checkOpnds(){
	if (! (this.left instanceof Ord)){
		oGui.dbgErr("Calculation.checkOpnds: the left operator is not of type \"Ord\"");
		return false;
	}
	if (! (this.right instanceof Ord)){
		oGui.dbgErr("Calculation.checkOpnds: the right operator is not of type \"Ord\"");
		return false;
	}
	
	if (this.left.isUndefined()){
		oGui.dbgErr("Calculation.checkOpnds: the left operand is an undefined Ord object");
		return false;
	}
	if (this.right.isUndefined()){
		oGui.dbgErr("Calculation.checkOpnds: the right operand is an undefined Ord object");
		return false;
	}
	return true;
};