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) ?
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)