
module NumRu
  module Misc

    # To be included instead of the Math predefined module (or NMath in NArray).
    # Unlike Math and NMath, EMath handles unknown classes by calling its
    # native instance method (assuming the same name).
    # 
    # Therefore, if included, its function (module method) is used as:
    # 
    #    cos( obj )
    # 
    # and so on. If obj is not of a supported class, EMath calls, obj.cos in
    # this case.  (If cos is not a method of obj, then an exception is
    # raised.)  Supported classes are Numeric (by Math) and NArray (by
    # NMath).  EMath stands for "good Math" (for obvious reason for a
    # Japanese).
    # 
    # Note: as for atan2(a,b), a.atan2(b) will be called if a or b
    # is not supported. This is the case for all functions that take
    # two or more arguments.
    # 
    # require "narray"
    # require "cmath" if RUBY_VERSION.to_f > 1.8
    module EMath

      E = Math::E
      PI = Math::PI

      funcs = ["acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", 
               "cos", "cosh", "erf", "erfc", "exp", "frexp", "hypot", 
               "ldexp", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh"]
               # FUNCS: from ruby 1.8.0, ( Math.methods - Object.methods ).sort

      module_function
      funcs.each{|func|
	eval <<-EOS,nil,__FILE__,__LINE__+1
	def #{func}(*arg)
          case arg[0]
          when Numeric
        if RUBY_VERSION.to_f > 1.8
	    CMath.#{func}(*arg)
        else
	    Math.#{func}(*arg)
        end
	  when NArray
	    NMath.#{func}(*arg)
	  else
	    obj = arg.shift
	    begin
	      obj.#{func}(*arg)
	    rescue NameError
	      raise TypeError,"cannot handle \#{obj.class}: \#{obj.inspect}"
	    end
	  end
	end
	EOS
      }
    end
  end
end

if __FILE__ == $0
  include NumRu::Misc::EMath
  p cos( PI )
  p cos( Complex(0, 1) )
  p cos( NArray[0,PI/3,PI/2] )
  p cos( NArray[ Complex(1,0), Complex(0,1) ] )
  begin
    p cos( "ggg" )
  rescue
    print "* error as expected >>: ",$!,"\n"
  end
  require 'narray_miss'
  nam = NArrayMiss.to_nam( NArray[0,PI/3,PI/2] )
  p cos(nam)
end
