如何添加任何Java Number对象集,以获得最准确的结果?

时间:2016-03-23 22:39:58

标签: java numbers

我必须编写一个可以获取Number对象(Java)数组的SUM()方法。所以它可能是几个Short对象,然后是几个Floats,然后是BigDecimal。

如果所有内容都是Byte / Short / Integer / Long,那么返回的值应该是Long。

如果所有内容都是Byte / Short / Integer / Long / Float / Double,那么返回的值应该是Double。

如果与上面的混合中有一个BigDecimal,那么结果应该是一个BigDecimal。如果BigInteger在那里,那么我不知道是什么/如何处理它,因为每个BigInteger可以对它处理的数字的大小有不同的值。

目前我收集了一个长的运行总数(所有字节/短/整数/长),双(所有浮点/双)和bigDecimal。然后在最后添加到已使用的任何一个(我有2个布尔跟踪)并返回。

它有效,但它不干净。有没有更简单的方法?一种添加两个Number对象的方法,它返回相应的Number对象?

3 个答案:

答案 0 :(得分:0)

根据您对long / double / BigDecimal返回值的要求,可能没有更好的方法。我会这样离开,或者只返回一个BigDecimal - 支持所有类型和大小。有没有理由你不这样做?

但是,您可以稍微增强设计并创建某种类型的Map或枚举,为每种类型提供返回类型参数并授予它们“强度”,以使BigDecimal覆盖Long等。

答案 1 :(得分:0)

几个月前我写了一篇课Numbers,这对你有所帮助。看一下源代码:

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

一般来说,

  1. 您可以使用determineCommonType方法确定所有Number个实例的常见类型
  2. 您希望使用castToNumber
  3. 将数组中的所有值强制转换为该常见类型
  4. 您为每种可能的类型使用add的实现添加值(因为Number接口不提供这样的方法,您必须自己编写或使用类似longValue的内容,请参阅https://docs.oracle.com/javase/7/docs/api/java/lang/Number.html#longValue())。
  5. 当然,也可以将所有内容映射到BigDecimal,然后使用适当的Number实现将其强制转换回公共类型(例如,如果你想要长的话,可以将longValue)。

    注意

    • GitHub上的实现不支持所有具体的Number实现(例如AtomicInteger),但我认为它可以很容易地增强。
    • 不要忘记对值进行求和可能会导致溢出,例如,添加两个Integers可能需要返回Long

答案 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();
    }
}