Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #39589 > unrolled thread

Compare generics (that are numbers)

Started byCecil Westerhof <Cecil@decebal.nl>
First post2020-07-29 17:19 +0200
Last post2020-07-29 20:59 +0200
Articles 15 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Compare generics (that are numbers) Cecil Westerhof <Cecil@decebal.nl> - 2020-07-29 17:19 +0200
    Re: Compare generics (that are numbers) Arne Vajhøj <arne@vajhoej.dk> - 2020-07-29 13:21 -0400
      Re: Compare generics (that are numbers) Arne Vajhøj <arne@vajhoej.dk> - 2020-07-29 13:27 -0400
    Re: Compare generics (that are numbers) Eric Sosman <esosman@comcast-dot-net.invalid> - 2020-07-29 13:48 -0400
      Re: Compare generics (that are numbers) Cecil Westerhof <Cecil@decebal.nl> - 2020-07-29 20:42 +0200
        Re: Compare generics (that are numbers) Arne Vajhøj <arne@vajhoej.dk> - 2020-07-29 14:50 -0400
          Re: Compare generics (that are numbers) Cecil Westerhof <Cecil@decebal.nl> - 2020-07-29 21:53 +0200
            Re: Compare generics (that are numbers) Arne Vajhøj <arne@vajhoej.dk> - 2020-07-29 21:32 -0400
              Re: Compare generics (that are numbers) Cecil Westerhof <Cecil@decebal.nl> - 2020-07-30 11:33 +0200
                Re: Compare generics (that are numbers) Eric Sosman <esosman@comcast-dot-net.invalid> - 2020-07-30 09:03 -0400
                  Re: Compare generics (that are numbers) Cecil Westerhof <Cecil@decebal.nl> - 2020-07-30 17:00 +0200
                Re: Compare generics (that are numbers) Arne Vajhøj <arne@vajhoej.dk> - 2020-07-30 09:21 -0400
            Re: Compare generics (that are numbers) Silvio <silvio@internet.com> - 2020-07-30 08:51 +0200
              Re: Compare generics (that are numbers) Cecil Westerhof <Cecil@decebal.nl> - 2020-07-30 11:36 +0200
    Re: Compare generics (that are numbers) Marcel Mueller <news.5.maazl@spamgourmet.org> - 2020-07-29 20:59 +0200

#39589 — Compare generics (that are numbers)

FromCecil Westerhof <Cecil@decebal.nl>
Date2020-07-29 17:19 +0200
SubjectCompare generics (that are numbers)
Message-ID<87k0ym73id.fsf@munus.decebal.nl>
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

[toc] | [next] | [standalone]


#39590

FromArne Vajhøj <arne@vajhoej.dk>
Date2020-07-29 13:21 -0400
Message-ID<rfsb7k$4gr$1@gioia.aioe.org>
In reply to#39589
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

[toc] | [prev] | [next] | [standalone]


#39591

FromArne Vajhøj <arne@vajhoej.dk>
Date2020-07-29 13:27 -0400
Message-ID<rfsbik$8v6$1@gioia.aioe.org>
In reply to#39590
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

[toc] | [prev] | [next] | [standalone]


#39592

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2020-07-29 13:48 -0400
Message-ID<rfscpe$doa$1@dont-email.me>
In reply to#39589
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.

[toc] | [prev] | [next] | [standalone]


#39593

FromCecil Westerhof <Cecil@decebal.nl>
Date2020-07-29 20:42 +0200
Message-ID<87ft9a6u35.fsf@munus.decebal.nl>
In reply to#39592
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

[toc] | [prev] | [next] | [standalone]


#39594

FromArne Vajhøj <arne@vajhoej.dk>
Date2020-07-29 14:50 -0400
Message-ID<rfsgek$jm4$1@gioia.aioe.org>
In reply to#39593
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

[toc] | [prev] | [next] | [standalone]


#39596

FromCecil Westerhof <Cecil@decebal.nl>
Date2020-07-29 21:53 +0200
Message-ID<87bljy6qu3.fsf@munus.decebal.nl>
In reply to#39594
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

[toc] | [prev] | [next] | [standalone]


#39597

FromArne Vajhøj <arne@vajhoej.dk>
Date2020-07-29 21:32 -0400
Message-ID<rft7um$17k2$1@gioia.aioe.org>
In reply to#39596
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

[toc] | [prev] | [next] | [standalone]


#39600

FromCecil Westerhof <Cecil@decebal.nl>
Date2020-07-30 11:33 +0200
Message-ID<87zh7h5ouj.fsf@munus.decebal.nl>
In reply to#39597
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

[toc] | [prev] | [next] | [standalone]


#39601

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2020-07-30 09:03 -0400
Message-ID<rfugel$qk$1@dont-email.me>
In reply to#39600
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.

[toc] | [prev] | [next] | [standalone]


#39603

FromCecil Westerhof <Cecil@decebal.nl>
Date2020-07-30 17:00 +0200
Message-ID<87mu3h59qc.fsf@munus.decebal.nl>
In reply to#39601
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

[toc] | [prev] | [next] | [standalone]


#39602

FromArne Vajhøj <arne@vajhoej.dk>
Date2020-07-30 09:21 -0400
Message-ID<rfuhhc$q7p$1@gioia.aioe.org>
In reply to#39600
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

[toc] | [prev] | [next] | [standalone]


#39598

FromSilvio <silvio@internet.com>
Date2020-07-30 08:51 +0200
Message-ID<5f226e02$0$14413$e4fe514c@newszilla.xs4all.nl>
In reply to#39596
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.

[toc] | [prev] | [next] | [standalone]


#39599

FromCecil Westerhof <Cecil@decebal.nl>
Date2020-07-30 11:36 +0200
Message-ID<87v9i55opx.fsf@munus.decebal.nl>
In reply to#39598
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

[toc] | [prev] | [next] | [standalone]


#39595

FromMarcel Mueller <news.5.maazl@spamgourmet.org>
Date2020-07-29 20:59 +0200
Message-ID<rfsgu9$lpn$1@gwaiyur.mb-net.net>
In reply to#39589
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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web