Skip to content

The Math Evaluator

Dave DeLong edited this page Sep 13, 2015 · 1 revision

Evaluation is part of the expression's logic, but it uses the Math Evaluator quite extensively.

Evaluating numbers

Evaluating a number expression is trivial. It simply returns the underlying NSNumber object.

Evaluating variables

Evaluating a variable is also relatively straight-forward. First, the variable is looked up in the passed substitutions dictionary. If the substitutions dictionary doesn't contain a match, then the expression consult's the math evaluator's variable resolver block. If no replacement is available, then an error is generated and evaluation aborts.

Otherwise, the object is examined:

  • if the substitution value is another expression, that expression is evaluated and its return value becomes the variables value.
  • if the substitution value is a string, that string is evaluated as an expression, and its return value becomes the variables value
  • if the substitution value is a number, the number is used directly
  • any other substitution value generates an error

Evaluating functions

Evaluating a function is where the math evaluator is used. First, the math evaluator looks to see if the function is one of the built-in functions. If it is, it invokes the default implementation.

If the function is not one of the built-in functions, then the evaluator checks to see if a function has been registered for the defined name. If it has, then that function is used. If not, then the math evaluator attempts to resolve the function as a variable (if that property is enabled), which goes the the variable evaluation route, explained above.

If a value still has not been obtained, the math evaluator attempts to consult the function resolver to acquire a "just in time" function definition.

Finally, if that fails, an error is generated and evaluation aborts.

If a function definition is found, it is invoked with four arguments:

  1. the array of DDExpression objects that are the arguments to the function
  2. the substitution dictionary
  3. the math evaluator
  4. the NSError** (for reporting errors)

The return value of the DDMathFunction is another DDExpression object, although some leniency is allowed: NSNumbers are returned directly and NSStrings are parsed and evaluated to extract a numerical value.

Angle Measurement Mode

The math evaluator allows you to specify the unit in which angles are measured. The two options are DDAngleMeasurementModeRadians (the default) and DDAngleMeasurementModeDegrees.

When the measurement mode is in radians, the following is true:

sin(π/2) = 1
asin(0.7071067811865475) = .785398163
sin(45) = 0.8509035245341184

However, the when measurement mode is in degrees, the evaluation changes:

sin(π/2) = 0.02741213359204429
asin(0.7071067811865475) = 45
sin(45) = 0.7071067811865475

Lazy Resolution

DDMathEvaluator has two properties that allow you to lazily resolve functions and variables: functionResolver and variableResolver.

Function Resolution

Lazy function resolution can be very handy when using DDMathParser to process user-generated input. For example, you can use lazy function resolution to process a string like this:

"age/2 + 7"

According to the rules of argumentless functions, this will be parsed as:

(age() / 2) + 7

The advantage of this is that users do not need to understand the syntax for variables and their need for the leading $ character.

By specifying the appropriate block for the functionResolver, you can process these functions as if they were variables. The Demo in the repository contains an example of a function resolver. Alternatively, you could simply specify that unknown functions should be resolved as variables, and specify a the value through the variables dictionary or via the variable resolver.

Variable Resolution

Like with functions, you can specify a block to lazily resolve unknown variables. The block, however, is much simpler: it takes a single string argument (the name of the variable) and returns an NSNumber.