/* math.c Numerical Array Extension for Ruby (C) Copyright 1999-2017 by Masahiro TANAKA */ #include #include "numo/narray.h" VALUE numo_mNMath; extern VALUE numo_mDFloatMath, numo_mDComplexMath; extern VALUE numo_mSFloatMath, numo_mSComplexMath; static ID id_send; static ID id_UPCAST; static ID id_DISPATCH; static ID id_extract; VALUE nary_type_s_upcast(VALUE type1, VALUE type2) { VALUE upcast_hash; VALUE result_type; if (type1==type2) return type1; upcast_hash = rb_const_get(type1, id_UPCAST); result_type = rb_hash_aref(upcast_hash, type2); if (NIL_P(result_type)) { if (TYPE(type2)==T_CLASS) { if ( RTEST(rb_class_inherited_p(type2,cNArray)) ) { upcast_hash = rb_const_get(type2, id_UPCAST); result_type = rb_hash_aref(upcast_hash, type1); } } } return result_type; } VALUE nary_math_cast2(VALUE type1, VALUE type2) { if ( RTEST(rb_class_inherited_p( type1, cNArray )) ){ return nary_type_s_upcast( type1, type2 ); } if ( RTEST(rb_class_inherited_p( type2, cNArray )) ){ return nary_type_s_upcast( type2, type1 ); } if ( RTEST(rb_class_inherited_p( type1, rb_cNumeric )) && RTEST(rb_class_inherited_p( type2, rb_cNumeric )) ){ if ( RTEST(rb_class_inherited_p( type1, rb_cComplex)) || RTEST(rb_class_inherited_p( type2, rb_cComplex )) ){ return rb_cComplex; } return rb_cFloat; } return type2; } VALUE na_ary_composition_dtype(VALUE); VALUE nary_mathcast(int argc, VALUE *argv) { VALUE type, type2; int i; type = na_ary_composition_dtype(argv[0]); for (i=1; i1) { type = nary_mathcast(argc-1,argv+1); hash = rb_const_get(mod, id_DISPATCH); typemod = rb_hash_aref( hash, type ); if (NIL_P(typemod)) { rb_raise(rb_eTypeError,"%s is unknown for Numo::NMath", rb_class2name(type)); } ans = rb_funcall2(typemod,id_send,argc,argv); if (!RTEST(rb_class_inherited_p(type,cNArray)) && IsNArray(ans) ) { ans = rb_funcall(ans,id_extract,0); } return ans; } rb_raise(rb_eArgError,"argument or method missing"); return Qnil; } void Init_nary_math() { VALUE hCast; numo_mNMath = rb_define_module_under(mNumo, "NMath"); rb_define_singleton_method(numo_mNMath, "method_missing", nary_math_method_missing, -1); hCast = rb_hash_new(); rb_define_const(numo_mNMath, "DISPATCH", hCast); rb_hash_aset(hCast, numo_cInt64, numo_mDFloatMath); rb_hash_aset(hCast, numo_cInt32, numo_mDFloatMath); rb_hash_aset(hCast, numo_cInt16, numo_mDFloatMath); rb_hash_aset(hCast, numo_cInt8, numo_mDFloatMath); rb_hash_aset(hCast, numo_cUInt64, numo_mDFloatMath); rb_hash_aset(hCast, numo_cUInt32, numo_mDFloatMath); rb_hash_aset(hCast, numo_cUInt16, numo_mDFloatMath); rb_hash_aset(hCast, numo_cUInt8, numo_mDFloatMath); rb_hash_aset(hCast, numo_cDFloat, numo_mDFloatMath); rb_hash_aset(hCast, numo_cDFloat, numo_mDFloatMath); rb_hash_aset(hCast, numo_cDComplex, numo_mDComplexMath); rb_hash_aset(hCast, numo_cSFloat, numo_mSFloatMath); rb_hash_aset(hCast, numo_cSComplex, numo_mSComplexMath); #ifdef RUBY_INTEGER_UNIFICATION rb_hash_aset(hCast, rb_cInteger, rb_mMath); #else rb_hash_aset(hCast, rb_cFixnum, rb_mMath); rb_hash_aset(hCast, rb_cBignum, rb_mMath); #endif rb_hash_aset(hCast, rb_cFloat, rb_mMath); rb_hash_aset(hCast, rb_cComplex, numo_mDComplexMath); id_send = rb_intern("send"); id_UPCAST = rb_intern("UPCAST"); id_DISPATCH = rb_intern("DISPATCH"); id_extract = rb_intern("extract"); }