1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
class ENumber attr_accessor :n, :e def initialize( number, error ) @n = number @e = error end # Basic arithmetic. Call like (ENumber1 + ENumber2) def +(o); ENumber.new(@n+o.n, @e+o.e); end def -(o); ENumber.new(@n-o.n, @e+o.e); end def *(o); ENumber.new(@n*o.n, multError(o)); end def /(o); ENumber.new(@n/o.n, multError(o)); end # Trigonometric functions. Call like "myENumber.cos" def tan; trig(:tan); end def sin; trig(:sin); end def cos; trig(:cos); end # Print this ENumber with the number and error rounded to x and y, respectively. # Probably should find the real way to print a +/-. since it screws up when I edit # this file on a terminal without UTF-8 (ie. almost any terminal) def to_s(x=4,y=x) "%.#{x}f±%.#{y}f" % [@n, @e] end private def trig(type) fcn = Math.method(type) ENumber.new(fcn.call(@n), 0.5*(fcn.call(@n+@e)-fcn.call(@n-@e)).abs ) end def multError(o) (@n * o.n).abs * ((@e / (@n.abs)) + (o.e / (o.n.abs))) end end # Normally this file will be included as a library. # If it's loaded directly, run the below. Demo/example/cheap-ass-unittest. if __FILE__ == $0 n = ENumber.new(3,0.5) m = ENumber.new(4,0.25) puts (((m*n).tan)+n).to_s(5,6) end
Refactorings
No refactoring yet !
Chris Jester-Young
June 30, 2008, June 30, 2008 00:08, permalink
I don't know whether your specific problem domain can be solved using interval arithmetic, but if so, a search for "ruby interval arithmetic" came up with http://intervals.rubyforge.org/. Hope it helps. :-)
Alan Hensel
June 30, 2008, June 30, 2008 00:29, permalink
Hmm, first of all, are you sure those are the error propagation formulas you want to use? They aren't the ones I remember from school....
See http://instructor.physics.lsa.umich.edu/ip-labs/tutorials/errors/prop.html
In any case, here's one suggestion. You could extend Float with a plusminus method. Which is prettier code? ENumber.new(5.3, 0.1) or 5.3.plusminus(0.1) ?
1 2 3 4 5
class Float def plusminus(error) ENumber.new(self, error) end end
We needed to do a bunch of calculations in our Physics labs with numbers that have an error attached. These turned out to be a pain in the ass, so...
By way of example, (3±0.5) + (4±0.1) = (7±0.6)