multiply two objects

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tigger

    #1

    multiply two objects

    I have a method that is passed two objects and it needs to return an object
    that represents those two objects multiplied together.

    public object Multiply(object a, object b)
    {
    return a * b;
    }

    The objects can be any type of number and I would like it to do the maths in
    the most efficient and accurate way.

    e.g. if both numbers are double, they are multipled as doubles and a double
    is returned.

    Is there any way to do this in C#?

    Tigger


  • Jon Skeet [C# MVP]

    #2
    Re: multiply two objects

    On Oct 11, 1:00 pm, "Tigger" <mccre...@bigfo ot.comwrote:
    I have a method that is passed two objects and it needs to return an object
    that represents those two objects multiplied together.
    >
    public object Multiply(object a, object b)
    {
    return a * b;
    >
    }
    >
    The objects can be any type of number and I would like it to do the maths in
    the most efficient and accurate way.
    >
    e.g. if both numbers are double, they are multipled as doubles and a double
    is returned.
    >
    Is there any way to do this in C#?
    To be honest, the simplest (if least aesthetically appealing) way of
    doing this is simply to have lots of overloads, one for each numeric
    type.

    Jon

    Comment

    • Marc Gravell

      #3
      Re: multiply two objects

      I almost replied the same... but for that to work, you'd either need
      to know the types in the calling code (so the compiler can resolve),
      or you'd have to use reflection based on a.GetType() and b.GetType().
      The latter isn't very appealing, and the former, well, in that case
      couldn't you just use "a * b" in the calling code, rather than
      Multiply(a,b)?

      Just a thought...

      Marc


      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: multiply two objects

        On Oct 11, 1:34 pm, "Marc Gravell" <marc.grav...@g mail.comwrote:
        I almost replied the same... but for that to work, you'd either need
        to know the types in the calling code (so the compiler can resolve),
        or you'd have to use reflection based on a.GetType() and b.GetType().
        The latter isn't very appealing, and the former, well, in that case
        couldn't you just use "a * b" in the calling code, rather than
        Multiply(a,b)?
        >
        Just a thought...
        True, true. I think it's *got* to use reflection really, hasn't it, if
        the given signature is the desired one.
        I think I'd still have the appropriate overloads, but then do the same
        sort of work that the compiler usually would, working out the right
        conversion to use etc.

        I can't see how this is going to be terribly efficient...

        Jon

        Comment

        • Marc Gravell

          #5
          Re: multiply two objects

          A tedious branch (below) might be an option... certainly faster than
          reflection, but a nightmare to maintain and ugly as sin... but then
          again, all those overloads would be similarly tedious...

          Of course, if you know all the values are likely to be within the
          range of decimal (as an example), then perhaps just use decimal
          arithmetic throughout ;-p

          if(a is decimal) {
          if(b is decimal) {
          return ((decimal)a)*(( decimal)b);
          } else if (b is int) {
          return ((decimal)a)*(( int)b);
          } ...
          } else if (a is int) {
          if(b is decimal) {
          return ((int)a)*((deci mal)b);
          } ...
          } ...
          throw new NotSupportedExc eption();

          Marc


          Comment

          • Tigger

            #6
            Re: multiply two objects


            "Jon Skeet [C# MVP]" <skeet@pobox.co mwrote in message
            news:1192104211 .603458.225910@ y42g2000hsy.goo glegroups.com.. .
            On Oct 11, 1:00 pm, "Tigger" <mccre...@bigfo ot.comwrote:
            >I have a method that is passed two objects and it needs to return an
            >object
            >that represents those two objects multiplied together.
            >>
            >public object Multiply(object a, object b)
            >{
            > return a * b;
            >>
            >}
            >>
            >The objects can be any type of number and I would like it to do the maths
            >in
            >the most efficient and accurate way.
            >>
            >e.g. if both numbers are double, they are multipled as doubles and a
            >double
            >is returned.
            >>
            >Is there any way to do this in C#?
            >
            To be honest, the simplest (if least aesthetically appealing) way of
            doing this is simply to have lots of overloads, one for each numeric
            type.
            >
            Jon
            >
            Quick reply!

            Unfortunately that solution won't work in my case. The way I use it is a bit
            like this....

            int a = 56;
            double b = 78.0;

            object oa = a;
            object ob = b;

            object c = Multiply(oa,ob) ;

            As I am passing objects into the method I have to implement an object based
            overload to make it compile. And this is the one that always get used, even
            if I create many other overloads.

            I've come across this sort of issue before and ended up doing lots of "is"
            tests.

            Im this case it will be many, and I don't want to have to re workout all the
            correct type conversions. e.g. int * double = double, float * decimal = ???

            And I have to do this for +-*/

            Tigger


            Comment

            • Looch

              #7
              Re: multiply two objects

              Just a noob here, but isn't that what generics are for?


              Comment

              • Tigger

                #8
                Re: multiply two objects


                "Marc Gravell" <marc.gravell@g mail.comwrote in message
                news:%23NuZktAD IHA.6012@TK2MSF TNGP03.phx.gbl. ..
                >A tedious branch (below) might be an option... certainly faster than
                >reflection, but a nightmare to maintain and ugly as sin... but then again,
                >all those overloads would be similarly tedious...
                >
                Of course, if you know all the values are likely to be within the range of
                decimal (as an example), then perhaps just use decimal arithmetic
                throughout ;-p
                >
                if(a is decimal) {
                if(b is decimal) {
                return ((decimal)a)*(( decimal)b);
                } else if (b is int) {
                return ((decimal)a)*(( int)b);
                } ...
                } else if (a is int) {
                if(b is decimal) {
                return ((int)a)*((deci mal)b);
                } ...
                } ...
                throw new NotSupportedExc eption();
                >
                Marc
                >
                My current solution is like this (actual code) ...

                protected override object Rule_MultExp_Ti mes(Rule_MultEx p_Times rule)
                {
                object left = this.Do(rule.Le ft); // Do returns an object
                object right = this.Do(rule.Ri ght);

                if (left == null || right == null)
                return null;

                if (IsInteger(left ) && IsInteger(right ))
                return Convert.ToInt64 (left) * Convert.ToInt64 (right);
                else
                return Convert.ToDecim al(left) * Convert.ToDecim al(right);
                }

                protected bool IsInteger(objec t o)
                {
                if (o is Int64)
                return true;
                if (o is Int32)
                return true;
                if (o is Int16)
                return true;
                return false;
                }

                I'm basically rounding up to the most accurate types Int64 or Decimal (I
                should do double as well!)
                Im still not sure if it works with all combinations. Before I was casting to
                double for all types and it caused invalid casts from integers!

                Tigger


                Comment

                • Marc Gravell

                  #9
                  Re: multiply two objects

                  In C++ maybe (since the operations are resolved at compile-time). But
                  in C#, generics rely on methods etc being resolved at compile time
                  *for any T*, since T is essentially a runtime argument (not
                  compile-time). Unfortunately, no methods suitable for generics are
                  defined for the numeric types.

                  Marc


                  Comment

                  • Chris Shepherd

                    #10
                    Re: multiply two objects

                    Looch wrote:
                    Just a noob here, but isn't that what generics are for?
                    Unfortunately int, double, long, etc., don't implement a common
                    interface which dictates that the multiplier operator should be handled.
                    That means you can't come up with a constraint for it. By default object
                    * object doesn't work.

                    My bet is that even if you did this through reflection, it would still
                    be faster to use overloaded methods of every combination of base number
                    types you want to handle.

                    Chris.

                    Comment

                    • Jon Skeet [C# MVP]

                      #11
                      Re: multiply two objects

                      On Oct 11, 2:43 pm, "Tigger" <mccre...@bigfo ot.comwrote:
                      Im this case it will be many, and I don't want to have to re workout all the
                      correct type conversions. e.g. int * double = double, float * decimal = ???
                      In the case of float*decimal, it wouldn't actually work in C#, as
                      neither is implicitly convertible to the other.

                      You could do this with autogenerated code and a dictionary from a pair
                      of types to a delegate, or from a dictionary of type to (a dictionary
                      of type to delegate). Call GetType() on each side, and then call the
                      delegate:

                      return multiplicationD elegates[left.GetType()][right.GetType()](left,
                      right);

                      The autogenerated code would have stuff like:

                      multiplicationD elegates[typeof(int)][typeof(float)] = delegate (object
                      left, object right) { return (int)left*(floa t)right };
                      multiplicationD elegates[typeof(int)][typeof(float)] = delegate (object
                      left, object right) { return (int)left*(doub le)right };

                      Not nice, and you'd need to make sure you excluded operations
                      involving both decimal and float/double, but it should work...

                      Jon

                      Comment

                      Working...