• Compare generics (that are numbers)

    From Cecil Westerhof@21:1/5 to All on Wed Jul 29 17:19:22 2020
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)
    What is the best way to determine which of the two is lower?

    --
    Cecil Westerhof
    Senior Software Engineer
    LinkedIn: http://www.linkedin.com/in/cecilwesterhof

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Arne_Vajh=c3=b8j?=@21:1/5 to Cecil Westerhof on Wed Jul 29 13:21:56 2020
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)
    What is the best way to determine which of the two is lower?

    T extends Number?

    Example:

    public class NumFun {
    public static class Demo<T extends Number> {
    public boolean gt(T a, T b) {
    return a.doubleValue() > b.doubleValue();
    }
    }
    public static void main(String[] args) {
    Demo<Double> dd = new Demo<>();
    System.out.println(dd.gt(1.0, 0.0));
    System.out.println(dd.gt(1.0, 1.0));
    System.out.println(dd.gt(0.0, 1.0));
    Demo<Integer> di = new Demo<>();
    System.out.println(di.gt(1, 0));
    System.out.println(di.gt(1, 1));
    System.out.println(di.gt(0, 1));
    }
    }

    Arne

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eric Sosman@21:1/5 to Cecil Westerhof on Wed Jul 29 13:48:28 2020
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)
    What is the best way to determine which of the two is lower?

    Aside: How can you get `<E>' to be `<int>' or `<float>'? Is that something new? I'm still on Java 8, but the JLS for 14 says "Seq<int>
    is illegal, as primitive types cannot be type arguments." (4.5)

    Anyhow, could you use `CalcValueGeneric<E extends Comparable<E>>' (double-check my syntax)? That would at least handle Integer/Integer
    and Float/Float, though it wouldn't help with Integer/Float.

    --
    esosman@comcast-dot-net.invalid
    Donald Trump is a self-mad man.
    One hundred seventy-five days to go.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Arne_Vajh=c3=b8j?=@21:1/5 to All on Wed Jul 29 13:27:48 2020
    On 7/29/2020 1:21 PM, Arne Vajhøj wrote:
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
         abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)
    What is the best way to determine which of the two is lower?

    T extends Number?

    Example:

    public class NumFun {
        public static class Demo<T extends Number> {
            public boolean gt(T a, T b) {
                return a.doubleValue() > b.doubleValue();
            }
        }
        public static void main(String[] args) {
            Demo<Double> dd = new Demo<>();
            System.out.println(dd.gt(1.0, 0.0));
            System.out.println(dd.gt(1.0, 1.0));
            System.out.println(dd.gt(0.0, 1.0));
            Demo<Integer> di = new Demo<>();
            System.out.println(di.gt(1, 0));
            System.out.println(di.gt(1, 1));
            System.out.println(di.gt(0, 1));
        }
    }

    Note that there are some bad corner cases for long/Long.

    Arne

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Arne_Vajh=c3=b8j?=@21:1/5 to Cecil Westerhof on Wed Jul 29 14:50:59 2020
    On 7/29/2020 2:42 PM, Cecil Westerhof wrote:
    Eric Sosman <esosman@comcast-dot-net.invalid> writes:
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)
    What is the best way to determine which of the two is lower?

    Aside: How can you get `<E>' to be `<int>' or `<float>'? Is that
    something new? I'm still on Java 8, but the JLS for 14 says "Seq<int>
    is illegal, as primitive types cannot be type arguments." (4.5)

    You are completely right, I was not thinking straight. :'-(

    Probably a common miswording.

    class CalcValuesGeneric<E> {
    void something(E v)
    ...
    cvg.something(x);

    E can be Integer or Float but not int or float.

    But x can be int and float as well due to auto boxing.

    Arne

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Marcel Mueller@21:1/5 to All on Wed Jul 29 20:59:17 2020
    Am 29.07.20 um 17:19 schrieb Cecil Westerhof:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)

    Java generics can never hold primitive types. This is prohibited by type erasure. However autoboxing may apply.

    What is the best way to determine which of the two is lower?

    A custom comparer which takes two arguments of type Number.

    Note that this is a multiple dispatch problem since the value domains of
    the different numeric types are not supersets of each other. No number
    type can hold all values of all number types. I.e. the compare function
    depends on both argument types not just a single type like virtual
    functions.

    I.e. to compare Double against BigInteger you cannot convert one
    argument to the domain of the other one because this may cause either an exception or loss of precision. Both prohibit the correct comparison result. Even Integer vs. Float is not possible directly. In this special case
    you may convert both values to double, because its value domain is a
    superset of both types.
    But considering Long vs. Double there is no type that can hold both
    value domains. So you need to check first whether the Double is outside
    the domain of Long (including not finite). In this case the result
    depends only on the sing on the Double. At next you need to round the
    Double down to the next whole number (floor) and convert it to long. In
    case the result compares equal you need to check whether the rounded
    Double value still equals the original and if not the Double was greater.
    Also note that comparison against NaN values always return false except
    for NaN != NaN. I.e. a < b is not equivalent with !(a >= b).

    Since Java does not support multiple dispatch out of the box you need to implement your own dispatch logic. The number of entries grows
    quadratically with the number of types you want to support. E.g.
    AtomicLong or BigInteger are additional types that might occur if you
    restrict the generic type to Number.


    Marcel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cecil Westerhof@21:1/5 to Eric Sosman on Wed Jul 29 20:42:54 2020
    Eric Sosman <esosman@comcast-dot-net.invalid> writes:

    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.)
    What is the best way to determine which of the two is lower?

    Aside: How can you get `<E>' to be `<int>' or `<float>'? Is that something new? I'm still on Java 8, but the JLS for 14 says "Seq<int>
    is illegal, as primitive types cannot be type arguments." (4.5)

    You are completely right, I was not thinking straight. :'-(

    --
    Cecil Westerhof
    Senior Software Engineer
    LinkedIn: http://www.linkedin.com/in/cecilwesterhof

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cecil Westerhof@21:1/5 to arne@vajhoej.dk on Wed Jul 29 21:53:08 2020
    Arne Vajhøj <arne@vajhoej.dk> writes:

    On 7/29/2020 2:42 PM, Cecil Westerhof wrote:
    Eric Sosman <esosman@comcast-dot-net.invalid> writes:
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.) >>>> What is the best way to determine which of the two is lower?

    Aside: How can you get `<E>' to be `<int>' or `<float>'? Is that
    something new? I'm still on Java 8, but the JLS for 14 says "Seq<int>
    is illegal, as primitive types cannot be type arguments." (4.5)

    You are completely right, I was not thinking straight. :'-(

    Probably a common miswording.

    class CalcValuesGeneric<E> {
    void something(E v)
    ...
    cvg.something(x);

    E can be Integer or Float but not int or float.

    But x can be int and float as well due to auto boxing.

    But I do not want auto boxing. The particular case I am working with
    shows that int can take 40% less CPU and memory when using Integer.

    I will find another way. Thanks.

    --
    Cecil Westerhof
    Senior Software Engineer
    LinkedIn: http://www.linkedin.com/in/cecilwesterhof

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Arne_Vajh=c3=b8j?=@21:1/5 to Cecil Westerhof on Wed Jul 29 21:32:08 2020
    On 7/29/2020 3:53 PM, Cecil Westerhof wrote:
    Arne Vajhøj <arne@vajhoej.dk> writes:
    On 7/29/2020 2:42 PM, Cecil Westerhof wrote:
    Eric Sosman <esosman@comcast-dot-net.invalid> writes:
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.) >>>>> What is the best way to determine which of the two is lower?

    Aside: How can you get `<E>' to be `<int>' or `<float>'? Is that >>>> something new? I'm still on Java 8, but the JLS for 14 says "Seq<int> >>>> is illegal, as primitive types cannot be type arguments." (4.5)

    You are completely right, I was not thinking straight. :'-(

    Probably a common miswording.

    class CalcValuesGeneric<E> {
    void something(E v)
    ...
    cvg.something(x);

    E can be Integer or Float but not int or float.

    But x can be int and float as well due to auto boxing.

    But I do not want auto boxing. The particular case I am working with
    shows that int can take 40% less CPU and memory when using Integer.

    I will find another way. Thanks.

    Well - code that handle objects does require objects.

    :-)

    But if this is performance critical then why not just drop the
    generic stuff and write specific code for the types?

    Arne

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Silvio@21:1/5 to Cecil Westerhof on Thu Jul 30 08:51:46 2020
    On 7/29/20 9:53 PM, Cecil Westerhof wrote:
    Arne Vajhøj <arne@vajhoej.dk> writes:

    On 7/29/2020 2:42 PM, Cecil Westerhof wrote:
    Eric Sosman <esosman@comcast-dot-net.invalid> writes:
    On 7/29/2020 11:19 AM, Cecil Westerhof wrote:
    I have a class that starts with:
    abstract class CalcValuesGeneric<E> {

    E will be Integer, int, Float or float. (For now, but always a Number.) >>>>> What is the best way to determine which of the two is lower?

    Aside: How can you get `<E>' to be `<int>' or `<float>'? Is that >>>> something new? I'm still on Java 8, but the JLS for 14 says "Seq<int> >>>> is illegal, as primitive types cannot be type arguments." (4.5)

    You are completely right, I was not thinking straight. :'-(

    Probably a common miswording.

    class CalcValuesGeneric<E> {
    void something(E v)
    ...
    cvg.something(x);

    E can be Integer or Float but not int or float.

    But x can be int and float as well due to auto boxing.

    But I do not want auto boxing. The particular case I am working with
    shows that int can take 40% less CPU and memory when using Integer.

    I will find another way. Thanks.


    You could try Scala. It has type specialization that allows you to
    prevent boxing overhead when using generics with primitive type parameters.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cecil Westerhof@21:1/5 to arne@vajhoej.dk on Thu Jul 30 11:33:40 2020
    Arne Vajhøj <arne@vajhoej.dk> writes:

    But if this is performance critical then why not just drop the
    generic stuff and write specific code for the types?

    Because I want to show the differences between using
    Float/float/Integer/int and different implementations thereof.

    --
    Cecil Westerhof
    Senior Software Engineer
    LinkedIn: http://www.linkedin.com/in/cecilwesterhof

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cecil Westerhof@21:1/5 to Silvio on Thu Jul 30 11:36:26 2020
    Silvio <silvio@internet.com> writes:

    You could try Scala. It has type specialization that allows you to
    prevent boxing overhead when using generics with primitive type
    parameters.

    Is a possibility, but I think it better to do in Java. There is the
    possibility that someone that only uses Java will not be convinced by
    Scala code.

    I think I can manage in Java, but otherwise I can bring your tip into
    practice.

    --
    Cecil Westerhof
    Senior Software Engineer
    LinkedIn: http://www.linkedin.com/in/cecilwesterhof

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eric Sosman@21:1/5 to Cecil Westerhof on Thu Jul 30 09:03:14 2020
    On 7/30/2020 5:33 AM, Cecil Westerhof wrote:
    Arne Vajhøj <arne@vajhoej.dk> writes:

    But if this is performance critical then why not just drop the
    generic stuff and write specific code for the types?

    Because I want to show the differences between using
    Float/float/Integer/int and different implementations thereof.

    Is this a "practical problem," or a "teaching exercise?" If the
    former, I'd be interested to know how it arises -- needing to compare
    one arbitrary Number to another (BigDecimal vs. AtomicLong?) seems not
    out of the question, but surely unusual.

    If it's a teaching tool, you might want to reconsider the vehicle.
    As has been pointed out, some combinations (DoubleAdder vs. BigInteger,
    others) raise a lot of thorny and niggling special cases that might
    tend to obscure whatever point you're trying to put across. Maybe if
    folks had a better idea of the goals they'd suggest better approaches.

    --
    esosman@comcast-dot-net.invalid
    If he's so rich, why ain't he smart?
    One hundred seventy-four days to go.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Arne_Vajh=c3=b8j?=@21:1/5 to Cecil Westerhof on Thu Jul 30 09:21:47 2020
    On 7/30/2020 5:33 AM, Cecil Westerhof wrote:
    Arne Vajhøj <arne@vajhoej.dk> writes:
    But if this is performance critical then why not just drop the
    generic stuff and write specific code for the types?

    Because I want to show the differences between using
    Float/float/Integer/int and different implementations thereof.

    Then 40% difference proves the point.

    Arne

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cecil Westerhof@21:1/5 to Eric Sosman on Thu Jul 30 17:00:11 2020
    Eric Sosman <esosman@comcast-dot-net.invalid> writes:

    On 7/30/2020 5:33 AM, Cecil Westerhof wrote:
    Arne Vajhøj <arne@vajhoej.dk> writes:

    But if this is performance critical then why not just drop the
    generic stuff and write specific code for the types?

    Because I want to show the differences between using
    Float/float/Integer/int and different implementations thereof.

    Is this a "practical problem," or a "teaching exercise?" If the
    former, I'd be interested to know how it arises -- needing to compare
    one arbitrary Number to another (BigDecimal vs. AtomicLong?) seems not
    out of the question, but surely unusual.

    Lets lift a corner of the veil. ;-)

    It is in between. During a whiteboard session during a job interview I
    was asked to optimise something. It started with going from Float to
    Integer. (In this case that was possible.) The functionality of
    Integer was not used, so it was good to switch to int. But a further optimisation would be to use an int array. When back home I was
    curious and started implementing it. For readability I also tried int[number][2], but that did not work at all. I kept it in my program,
    because it is good to show the result in my opinion.
    Then I also tried int[2][number].

    With 25 million records and 250 repeats I got: |-----------------------+--------+----------+---------+---------+---------+----------+----------+----------|
    | Type | Memory | Sys Time | Gen Min | Gen Max | Gen Avg | Calc Min | Calc Max | Calc Avg |
    |-----------------------+--------+----------+---------+---------+---------+----------+----------+----------|
    | Integer Class[number] | 3.8 GB | 34.0 | 5.33E3 | 1.11E4 | 7.65E3 | 367 | 656 | 447.60 |
    | int Class[number] | 2.3 GB | 15.5 | 2.53E3 | 4.64E3 | 3.44E3 | 202 | 340 | 267.40 |
    | int [2 * number] | 0.6 GB | 5.5 | 1.09E3 | 1.52E3 | 1.27E3 | 61 | 112 | 75.10 |
    | int [number][2] | 2.3 GB | 24.0 | 4.23E3 | 7.30E3 | 5.51E3 | 183 | 338 | 239.18 |
    | int [2][number] | 0.6 GB | 6.0 | 1.06E3 | 1.61E3 | 1.30E3 | 81 | 133 | 107.03 |
    |-----------------------+--------+----------+---------+---------+---------+----------+----------+----------|

    System time is in minutes. Other times in milliseconds.

    With Floats the savings on memory will be a lot less, because the
    overhead for objects is less.

    --
    Cecil Westerhof
    Senior Software Engineer
    LinkedIn: http://www.linkedin.com/in/cecilwesterhof

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)