2016-03-23 6 views
0

Numberオブジェクト(Java)の配列を取得できるSUM()メソッドを記述する必要があります。したがって、いくつかのShortオブジェクト、次に2つのFloat、次にBigDecimalがあります。最も正確な結果を得るために、Java Numberオブジェクトのセットを追加するにはどうすればよいですか?

すべてがByte/Short/Integer/Longの場合、返される値はLongでなければなりません。

すべてがByte/Short/Integer/Long/Float/Doubleの場合、返される値はDoubleである必要があります。

上記のミックスにBigDecimalがある場合、結果はBigDecimalでなければなりません。 BigIntegerがそこにある場合、各BigIntegerが扱う数値の大きさが異なるため、どのBigIntegerがどのように扱われるかはわかりません。

現在のところ、long(すべてのByte/Short/Integer/Long)、double(すべてのFloat/Double)およびbigDecimalの合計を収集しています。その後、最後に使用されているものを追加し(2つのブール値を追跡している)、それを返します。

動作しますが、きれいではありません。簡単な方法がありますか? 2つのNumberオブジェクトを追加する方法は、適切なNumberオブジェクトを返しますか?

+1

あなたが言うすべてのタイプは、正確に「BigDecimal」として表現できます。すべての入力を 'BigDecimal'に変換して追加するだけです。正確な答えではなく、正確に正しい答えになります。 –

+0

これを行うための明確な方法はありません。 Javaは、あなたがしようとしているような異なる 'Number'型を混在させるつもりはありません。 –

+0

@PaulBoddington - 細部に入ることなく、Long(小数点なし)またはDouble(BigDecimalから変換する必要はありません)であることがわかったら、できることがあります。さらに、私たちは速いパフォーマンスを望んでおり、ほとんどの時間はすべて長いか2倍です。 –

答えて

0

を返却する必要があるかもしれませんが、あなたはより小さく、より簡単な方法の多くにそれを破ることができます。私のアプローチは、型の階層を設定することです。理想的には、加算にはより低いランクのタイプのみが含まれます。適切なレベルで作業を進めたら、適切な方法を呼び出すことができます。ここに私のコード(テストされていない)です。

private static final Map<Class<? extends Number>, Integer> RANKS; 

static { 
    Map<Class<? extends Number>, Integer> map = new IdentityHashMap<>(); 
    map.put(Byte.class, 0); 
    map.put(Short.class, 1); 
    map.put(Integer.class, 2); 
    map.put(Long.class, 3); 
    map.put(BigInteger.class, 4); 
    map.put(Float.class, 5); 
    map.put(Double.class, 6); 
    map.put(BigDecimal.class, 7); 
    RANKS = Collections.unmodifiableMap(map); 
} 

private static Number addBytes(Number... numbers) { 
    byte a = 0; 
    for (Number number : numbers) 
     a += number.byteValue(); 
    return a; 
} 

private static Number addShorts(Number... numbers) { 
    short a = 0; 
    for (Number number : numbers) 
     a += number.shortValue(); 
    return a; 
} 

private static Number addInts(Number... numbers) { 
    int a = 0; 
    for (Number number : numbers) 
     a += number.intValue(); 
    return a; 
} 

private static Number addLongs(Number... numbers) { 
    long a = 0; 
    for (Number number : numbers) 
     a += number.longValue(); 
    return a; 
} 

private static Number addBigIntegers(Number... numbers) { 
    BigInteger a = BigInteger.ZERO; 
    for (Number number : numbers) 
     a = a.add(number instanceof BigInteger ? (BigInteger) number : BigInteger.valueOf(number.longValue())); 
    return a; 
} 

private static Number addFloats(Number... numbers) { 
    float a = 0; 
    for (Number number : numbers) 
     a += number.floatValue(); 
    return a; 
} 

private static Number addDoubles(Number... numbers) { 
    double a = 0; 
    for (Number number : numbers) 
     a += number.doubleValue(); 
    return a; 
} 

private static Number addBigDecimals(Number... numbers) { 
    BigDecimal a = BigDecimal.ZERO; 
    for (Number number : numbers) { 
     a = a.add(
       number instanceof BigDecimal ? (BigDecimal) number 
         : number instanceof BigInteger ? new BigDecimal((BigInteger) number) 
         : new BigDecimal(number.doubleValue())); 
    } 
    return a; 
} 

public static Number add(Number... numbers) { 
    if (numbers.length == 0) 
     return 0; 
    int max = -1; 
    for (Number number : numbers) { 
     Integer rank = RANKS.get(number.getClass()); 
     if (rank == null) 
      throw new IllegalArgumentException(); 
     max = Math.max(max, rank); 
    } 
    switch (max) { 
     case 0: return addBytes(numbers); 
     case 1: return addShorts(numbers); 
     case 2: return addInts(numbers); 
     case 3: return addLongs(numbers); 
     case 4: return addBigIntegers(numbers); 
     case 5: return addFloats(numbers); 
     case 6: return addDoubles(numbers); 
     case 7: return addBigDecimals(numbers); 
     default: throw new IllegalStateException(); 
    } 
} 
0

long/double/BigDecimalの戻り値が必要な場合は、おそらく良い方法はありません。私はそれを好きにしておくか、BigDecimalを返します。すべての型とサイズをサポートします。あなたがそうしない理由はありますか?

あなたは、しかし、私が書いた

0

のBigDecimal等のロングを上書きするために、デザインを少し高め、地図や列挙型のいくつかのタイプを作成し、それぞれのタイプに戻り値の型パラメータを与え、「強さ」、それらを付与できます数ヶ月前のクラスNumbersをご利用ください。ソースコードを見て:一般的に

https://github.com/pmeisen/gen-misc/blob/master/src/net/meisen/general/genmisc/types/Numbers.java

  1. あなたはあなたが欲しい
  2. を持つすべてのNumberインスタンスの一般的なタイプを決定するためにdetermineCommonTypeメソッドを使用することができますcastToNumber
  3. を使用して配列のすべての値をその共通タイプにキャストするには、可能なタイプごとにaddの実装を使用して値を追加します(Numberインターフェイスではこのようなメソッドは提供されません。あなた自身で書くか、またはlongValueのようなものを使用する必要があります(https://docs.oracle.com/javase/7/docs/api/java/lang/Number.html#longValue()を参照)。

もちろん、BigDecimalにすべてをマップし、(あなたが長いをしたい場合などのlongValue)し、適切なNumber実装を使用して共通の型に戻ってそれをキャストすることも可能です。

  • GitHubの上の実装では、すべての具体的なNumber実装(たとえば、AtomicInteger)をサポートしていませんが、私はそれが簡単に向上させることができると思います。
  • 値を合計するとオーバーフローする可能性があることを忘れないでください。、2 Integersを追加すると、これを行うには良い方法はありませんLong
関連する問題