views:

74

answers:

3

We are about to redesign our calculation engine, and want each step in the calculation to be traceable/documented so that the user can get a complete report on what amounts make up each total.

Are there any patterns or good examples on how to implement 'traceable' or 'self-documenting' calculations?

+2  A: 

Yes, log the intermediate steps in the calculation as though you were submitting your work to a fussy mathematics professor.

Ed Guiness
This is the easy way, and most likely the choosen one. Must make the log in a format that would be intepretable for multiple purposes though. I guess a simple textlog want do...
Vegar
+1  A: 

You build the expression you wish to calculate as a tree of operators and operands:

class Node;

class operator : public node { virtual double eval() };

class operand : public node ;

class binary_operator : public operator ;

class addition : public binary_operator;

...etc.

This is the GOF Composite Pattern.

You build a GOF Visitor that visitor that visits nodes and evals recursively, so that by visiting the root of a expression results in evaling the whole tree and retuirning teh result of the expression.

You add reporting to the Visitor or a class derived from it. (It's helpful to have several subclasses of Visitor; one may report, another may verbosely log debug info, whatever, another may report in a different format, etc.)

I put something like this together with JavaCC (Java Compiler Compiler), which took care of generating code to parse an expression (I supplied the expression grammar in modified BNF) and build its expression tree for me; the eval and visitor code I wrote by hand.

tpdi
I have thought about this sort of idea in the past but with an emphasis on ensuring compatible units were used in each step of the process. I have always wondered if the implementations could be made efficient enough that the overhead would not be noticeable
Peter M
+1  A: 

In an RPN-based calculator you could print the top of the stack after each operation.

Otherwise, if your language allow it, you could override the arithmetic operators. Here's a simple example using Ruby

class Fixnum
    alias :plus :"+"
    alias :minus :"-"
    alias :mult :"*"
    alias :divide :"/"

    def +(other)
     res = plus(other)
     puts "#{self} + #{other} = #{res}"
     res
    end

    def -(other)
      res = minus(other)
      puts "#{self} - #{other} = #{res}"
      res
    end

    def *(other)
     res = mult(other)
     puts "#{self} * #{other} = #{res}"
     res
    end

    def /(other)
     res = divide(other)
     puts "#{self} / #{other} = #{res}"
     res
    end 
end

# Example
(1+9) * 10 / 5 + 99 - 3 

=>

1 + 9 = 10
10 * 10 = 100
100 / 5 = 20
20 + 99 = 119
119 - 3 = 116

Another solution is to have a proxy that intercepts all the arithmetic operations and perform the proper logging.

sris
As a delphi-developer, this idea is a little out of reach.. I like the idea though...
Vegar