On Oct 10, 2008, at 11:13 AM, Matthew Moss wrote: > ## Modular Arithmetic (#179) > > [1]: http://mathworld.wolfram.com/ModularArithmetic.html > [2]: http://en.wikipedia.org/wiki/Modular_arithmetic > [3]: http://www.math.harvard.edu/~sarah/magic/topics/division I agreed with Matthew's design choices regarding the type of "Integer {op} Modulo" being Integer. I'd intended to add some tests to show that Modulo.new(0)-10 would give Modulo.new(16) and generally give an integer value in the 0...modulus domain. (Of course, if I were less busy, I'd have taken a shot at division, too.) -Rob ==> modulo.rb <== class Modulo include Comparable # Returns a new object that behaves according to the rules of # Modular Arithmetic, but otherwise responds like an Integer from # the set of integers between 0 and modulus-1. def initialize(value=0, modulus=26) @modulus = modulus @value = value % @modulus end def to_int @value end def to_i self.to_int end def <=>(other) case other when Modulo @value <=> other.to_int when Integer @value <=> other else raise ArgumentError, "I don't know how to compare a #{other.class.name}" end end def coerce(other) case other when Integer return other, self.to_int else super end end [ :+, :-, :* ].each do |method| define_method method do |other| self.class.new(@value.__send__(method, other.to_int), @modulus) end end end __END__ ==> test_modulo.rb <== require 'test/unit' require 'modulo' class TestModulo < Test::Unit::TestCase def test_modulo_equality a = Modulo.new(23) b = Modulo.new(23) c = Modulo.new(179) assert_equal(a, b) assert_equal(a, c) end def test_add_zero a = Modulo.new(15) b = Modulo.new(0) assert_equal(a, a + b) end def test_add a = Modulo.new(15) b = Modulo.new(19) c = Modulo.new(8) assert_equal(c, a + b) end def test_add_int a = Modulo.new(15) c = Modulo.new(10) assert_equal(c, a + 21) end def test_sub a = Modulo.new(15) b = Modulo.new(19) c = Modulo.new(22) assert_equal(c, a - b) end def test_sub_int a = Modulo.new(15) c = Modulo.new(1) assert_equal(c, a - 66) end def test_mul a = Modulo.new(15) b = Modulo.new(7) c = Modulo.new(1) assert_equal(c, a * b) end def test_mul_int a = Modulo.new(15) c = Modulo.new(9) assert_equal(c, a * 11) end # from Ken Bloom def test_add_reverse a = Modulo.new(15) assert_equal(30, 15 + a) end # from Ken Bloom def test_sub_reverse a = Modulo.new(15) assert_equal(-14, 1-a) end def test_mul_int_reverse a = Modulo.new(15, 8) assert_equal(77, 11 * a) end def test_non_default_modulo a = Modulo.new(15, 11) b = Modulo.new(9, 11) assert_equal(2, a + b) assert_equal(6, a - b) assert_equal(3, a * b) end def test_compare assert_equal(1, Modulo.new(15) <=> Modulo.new(30)) end def test_compare_int assert_equal(-1, Modulo.new(15) <=> 35) end def test_sort x = [Modulo.new(15), Modulo.new(29), Modulo.new(-6), Modulo.new(57)] y = [3, 5, 15, 20] assert_equal(y, x.sort) end # def test_value_range # end end __END__ Rob Biedenharn http://agileconsultingllc.com Rob / AgileConsultingLLC.com