# = infinity.rb # # == Copyright (c) 2004,2005 Thomas Sawyer # # Ruby License # # This module is free software. You may use, modify, and/or redistribute this # software under the same terms as Ruby. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. # # == Author(s) # # * Thomas Sawyer # # == Developer's Notes # # TODO Could @direction values greater than 1 support Aleph? # Author:: Thomas Sawyer # Copyright:: Copyright (c) 2006 Thomas Sawyer # License:: Ruby License require 'facets/more/multiton' # = Infinity # # A full featured Infinity class, supporting signed direction. # Inifinty is a multiton based on direction The constant INFINITY # is provided as the common case with direction=+1 (positive). # # == Usage # # NaN # Inf # PosInf # NegInf # # These four constants a built from two other basic constants: # # UNDEFINED # INFINITY # # In physical memory there are actually only three objects, namely # three instances of InfinityClass, one for NaN, PosInf and NegInf, # respectively. class InfinityClass < Numeric include Multiton attr_reader :direction def initialize(direction=1) @direction = (direction <=> 0) end # Change direction of infinity. def -@ case @direction when 0 : self.class.instance(0) when 1 : self.class.instance(-1) when -1 : self.class.instance(1) end end # Noop. def +@ self end # Convert to the float version of infinity. def to_f (1.0/0) * @direction end # Gee, a real infinite loop! def times loop do yield end end # Coerce allows other numbers to be # compared to infinity. def coerce(other) case other when InfinityClass super else return -self, other end end # Equality. Note that NaN != NaN. def ==(other) case other when InfinityClass if @direction == 0 and other.direction == 0 false else super end else false end end # Comparision where infinity is alway greatest # and negative infinityalways least. def <=>(other) case other when InfinityClass @direction <=> other.direction else @direction end end # def to_s case @direction when 0 : "NaN" when 1 : "PosInf" when -1 : "NegInf" end end end # class Numeric def finite? not InfinityClass === self end def infinite? return false if NaN == self InfinityClass === self end alias :inf? :infinite? def nan? NaN == self end def posinf? PosInf == self end def neginf? NegInf == self end end # Set constant to positive infinity. UNDEFINED = InfinityClass.instance(0) INFINITY = InfinityClass.instance(1) NaN = UNDEFINED Inf = INFINITY PosInf = +INFINITY NegInf = -INFINITY # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin testing require 'test/unit' class GeneralTest < Test::Unit::TestCase def test_pos assert_equal((1.0/0), INFINITY.to_f) assert_equal(1, INFINITY<=>5) assert_equal(1, INFINITY<=>"a") assert_equal("PosInf", INFINITY.to_s) end def test_neg assert_equal((-1.0/0), -INFINITY.to_f) assert_equal(-1, -INFINITY<=>5) assert_equal(-1, -INFINITY<=>"a") assert_equal("NegInf", (-INFINITY).to_s) end def test_ord assert_equal((-1.0/0), -INFINITY.to_f) assert_equal(-1, 5<=>INFINITY) assert_equal(1, 5<=>-INFINITY) end def test_eq assert_equal(Inf, Inf) assert_equal(-Inf, -Inf) assert_equal(PosInf, PosInf) assert_equal(NegInf, NegInf) assert_not_equal(NaN, NaN) end end =end