2

So I'm trying, for all intents and purposes, to realize for myself a java version of C++'s STL algorithm inner_product for vector parameters. So far, my code(which is probably fundamentally wrong) looks like this:

public static<T,K> double inner_product(Vector<T> v1, Vector<K> v2)
{
    double isum = 0;
    for(int i=0;i<v1.size()&&i<v2.size();i++)
    {
        isum+=v1.elementAt(i)*v2.elementAt(i);
    }

    return isum;
}

The problem is that the operator * is undefined for the types T, K. However my knowledge so far doesn't cover predefining operators, though as far as I know it's not possible in Java as well. Any help would be appreciated in the way of realizing the function to take generics. Thanks in advance.

nutter
  • 35
  • 5

3 Answers3

3

There is no nice way to do this, for two reasons:

  1. Type parameters (T, K) must refer to object types, not primitives.
  2. Java does not have operator overloading.

The closest you can get is something like this (modulo syntax errors, my generics are rusty):

public static<T extends Number,K extends Number> double inner_product(Vector<T> v1, Vector<K> v2)
{
    double isum = 0;
    for(int i=0;i<v1.size()&&i<v2.size();i++)
    {
        isum+=v1.elementAt(i).doubleValue()*v2.elementAt(i).doubleValue();
    }

    return isum;
}

This will work for the object wrappers around primitive types, i.e. Double but not double, etc.

Also, like your version, this returns double no matter what type was passed in. And because of type erasure, this is pretty hard to fix.

Thomas
  • 150,847
  • 41
  • 308
  • 421
2

T must have a method defined like mutliply so you can call it with a V

interface T {
    double multiply(V v);
}

public static<T,K> double inner_product(Vector<T> v1, Vector<K> v2) {
    double isum = 0;
    for(int i=0; i<v1.size() && i<v2.size(); i++) {
        isum += v1.elementAt(i).multiply(v2.elementAt(i));
    }
    return isum;
}

IMHO Vector superseded by List in the Java 1.2 Collections libraries in 1998. Using List may be a better choice.

Do you really need it to be generic? I would just use double

public static double inner_product(List<Double> v1, List<Double> v2) {
    double isum = 0;
    for(int i=0; i<v1.size() && i<v2.size(); i++) 
        isum += v1.get(i) * v2.get(i);

    return isum;
}

or for efficiency use double[] or TDoubleArrayList

public static double inner_product(double[] v1, double[] v2) {
    double isum = 0;
    for(int i=0; i<v1.size() && i<v2.size(); i++) 
        isum += v1[i] * v2[i];

    return isum;
}
Peter Lawrey
  • 498,481
  • 72
  • 700
  • 1,075
  • `Vector` was not replaced; it's still perfectly valid if you need a synchronized resizing array. For the other 99% of cases, use `ArrayList`, which implements `List`, so you can indeed accept `List` arguments here. – Thomas May 06 '12 at 07:21
  • I suspect he doesn't need the array to be synchronized, but I would use `Collections.synchronizedList(new ArrayList())` in preference if you did. IMHO, While valid to use Vector, its pretty rare that its the best choice. – Peter Lawrey May 06 '12 at 07:23
  • Unfortunately I do need to be generic, because otherwise I'm writing two different functions with different operators for the same thing. – nutter May 06 '12 at 07:45
  • The you need the first solution. The problem is that could be more complicated than just writing two methods. What are the types you need? Why can you not use double as this is more efficient than using an object type? – Peter Lawrey May 06 '12 at 07:53
  • On one occasion i need to pass int and double, and on another double and double. – nutter May 06 '12 at 07:55
  • It would be simpler to use `double[]` every where this is much more efficient than a `Vector` (much smaller and faster) – Peter Lawrey May 06 '12 at 07:57
1

There is no operator overloading in Java, and the multiplication operator only applied to numeric primitive types. If you need to do this on generic types, you'll have to make them implement them an interface which allows transforming them into doubles:

public interface DoubleProvider
    double getDouble();
}

And then, you can define the following method:

public static <T extends DoubleProvider, K extends DoubleProvider> double innerProduct(Iterable<T> v1, Iterable<K> v2) {
    Iterator<T> it1 = v1.iterator();
    Iterator<K> it2 = v2.iterator();
    double sum = 0D;
    while (it1.hasNext() && it2.hasNext()) {
        T t = it1.next();
        K k = it2.next();
        sum += t.getDouble() * k.getDouble();
    }
    return sum;
}

Notice how my code

  • respects the Java naming conventions
  • acepts any kind of Iterable, rather than just the obsolete Vector (which should not be used anymore since Java 1.2)
JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174