如何对两个 Number 实例使用模数?
How to use modulo with two instances of Number?
我遇到了一个场景,我有两个 Number
个实例,我需要检查一个是否是另一个的倍数。
我尝试使用模数来检查,例如:
public static boolean isMultipleOf(Number a, Number b) {
return a % b == 0;
}
但是编译器不喜欢它:
Operator '%' cannot be applied to 'java.lang.Number',
'java.lang.Number'
我明白为什么会这样,但我的问题是实现这一目标的最简单方法是什么?
实际值可以是任何类型的数字,我想避免检查他们每个人的实际数字类型是什么,然后才执行操作。
有什么想法吗?
谢谢!
你可以这样做:
public static boolean isMultipleOf(Number a, Number b) {
return a.longValue() % b.longValue() == 0;
}
当然,这假设 a
和 b
在数学上是整数(因此是 Short、Integer 或 Long)。您可以改用 doubleValue()
,但要注意浮点代数比较...
您可以使用 doubleValue
方法将参数转换为 double
并应用 %
,例如:
private static boolean isMultipleOf(Number a, Number b){
return (a.doubleValue() % b.doubleValue()) == 0.0;
}
它也适用于 int
和 float
,例如:
public static void main(String[] args) throws Exception{
System.out.println(isMultipleOf(20, 10));
System.out.println(isMultipleOf(20.0, 10));
System.out.println(isMultipleOf(20, 10.0));
System.out.println(isMultipleOf(20.0, 10.0));
}
以上打印true
4次。
更新
如果你正在处理大量的数字,那么你可以使用 BigDecimal
class' remainder
方法,例如:
private static boolean isMultipleOf(Number a, Number b){
return new BigDecimal(a.doubleValue()).remainder(new BigDecimal(b.doubleValue())).doubleValue() == 0.0;
}
不,如果不进行类型检查,你就做不到
一个Number只提供了转换为图元的方法,每个图元都不足以给出准确的答案。
doubleValue 不起作用
static boolean wrongIsMultipleOfUsingDouble(Number a, Number b) {
return (a.doubleValue() % b.doubleValue()) == 0;
}
由于double
只有53位精度,当输入long
需要63位精度时会给出错误答案:
System.out.println(wrongIsMultipleOfUsingDouble(6969696969696969696L, 3L));
// prints `false`, but should be `true`
System.out.println(wrongIsMultipleOfUsingDouble(7777777777777777777L, 2L));
// prints `true`, but should be `false`.
longValue 不起作用
static boolean wrongIsMultipleOfUsingLong(Number a, Number b) {
return (a.longValue() % b.longValue()) == 0;
}
显然它因为截断而不起作用。
System.out.println(wrongIsMultipleOfUsingLong(5.0, 2.5));
// prints `false`, but should be `true`
System.out.println(wrongIsMultipleOfUsingLong(4.5, 2.0));
// prints `true`, but should be `false`.
类型检查仅适用于已知类型。
尽管 OP 喜欢避免类型检查,但这确实是接近可接受解决方案的唯一方法。
static boolean wrongIsMultipleOfUsingTypeChecking(Number a, Number b) {
// pseudo-code for simplicity
if (a, b instanceof (AtomicInteger | AtomicLong | Byte | Integer | Long | ...)) {
return (a.longValue() % b.longValue()) == 0;
} else if (a, b instanceof (Double | DoubleAccumulator | DoubleAdder | Float) {
return (a.doubleValue() % b.doubleValue()) == 0;
} else if (a, b instanceof (BigInteger | BigDecimal)) {
return a.remainder(b) == ZERO;
} else {
throw new RuntimeError("I give up");
}
}
这在大多数情况下都很好,但它仍然无法正常工作,因为它无法处理 Number 的第三方子 classes,例如 org.apache.commons.math4.fraction.Fraction
?
仅限 JSON 个号码?
现在 OP 声明使用 Number
因为数字来自 JSON。这些数字通常只有 long
或 double
,因此类型检查方法就足够了。
但是,most popular libraries in Java 也支持将数字解释为 BigDecimal:
- Org.JSON 有
.getBigDecimal()
- GSON 有
.getAsBigDecimal()
- Jackson 支持
BigDecimal
个字段
- JavaEE 7 的
javax.json
(JSR 353) 有 .bigDecimalValue()
BigDecimal 涵盖了 double
和 long
的范围,并且有一个实际的 .remainder()
method 解决了 OP 的问题。如果我们只想使用单个 class 来执行算术运算,并且 BigDecimal 的价格被认为不是一个大问题,这可能是一个可行的选择。
我遇到了一个场景,我有两个 Number
个实例,我需要检查一个是否是另一个的倍数。
我尝试使用模数来检查,例如:
public static boolean isMultipleOf(Number a, Number b) {
return a % b == 0;
}
但是编译器不喜欢它:
Operator '%' cannot be applied to 'java.lang.Number', 'java.lang.Number'
我明白为什么会这样,但我的问题是实现这一目标的最简单方法是什么?
实际值可以是任何类型的数字,我想避免检查他们每个人的实际数字类型是什么,然后才执行操作。
有什么想法吗?
谢谢!
你可以这样做:
public static boolean isMultipleOf(Number a, Number b) {
return a.longValue() % b.longValue() == 0;
}
当然,这假设 a
和 b
在数学上是整数(因此是 Short、Integer 或 Long)。您可以改用 doubleValue()
,但要注意浮点代数比较...
您可以使用 doubleValue
方法将参数转换为 double
并应用 %
,例如:
private static boolean isMultipleOf(Number a, Number b){
return (a.doubleValue() % b.doubleValue()) == 0.0;
}
它也适用于 int
和 float
,例如:
public static void main(String[] args) throws Exception{
System.out.println(isMultipleOf(20, 10));
System.out.println(isMultipleOf(20.0, 10));
System.out.println(isMultipleOf(20, 10.0));
System.out.println(isMultipleOf(20.0, 10.0));
}
以上打印true
4次。
更新
如果你正在处理大量的数字,那么你可以使用 BigDecimal
class' remainder
方法,例如:
private static boolean isMultipleOf(Number a, Number b){
return new BigDecimal(a.doubleValue()).remainder(new BigDecimal(b.doubleValue())).doubleValue() == 0.0;
}
不,如果不进行类型检查,你就做不到
一个Number只提供了转换为图元的方法,每个图元都不足以给出准确的答案。
doubleValue 不起作用
static boolean wrongIsMultipleOfUsingDouble(Number a, Number b) {
return (a.doubleValue() % b.doubleValue()) == 0;
}
由于double
只有53位精度,当输入long
需要63位精度时会给出错误答案:
System.out.println(wrongIsMultipleOfUsingDouble(6969696969696969696L, 3L));
// prints `false`, but should be `true`
System.out.println(wrongIsMultipleOfUsingDouble(7777777777777777777L, 2L));
// prints `true`, but should be `false`.
longValue 不起作用
static boolean wrongIsMultipleOfUsingLong(Number a, Number b) {
return (a.longValue() % b.longValue()) == 0;
}
显然它因为截断而不起作用。
System.out.println(wrongIsMultipleOfUsingLong(5.0, 2.5));
// prints `false`, but should be `true`
System.out.println(wrongIsMultipleOfUsingLong(4.5, 2.0));
// prints `true`, but should be `false`.
类型检查仅适用于已知类型。
尽管 OP 喜欢避免类型检查,但这确实是接近可接受解决方案的唯一方法。
static boolean wrongIsMultipleOfUsingTypeChecking(Number a, Number b) {
// pseudo-code for simplicity
if (a, b instanceof (AtomicInteger | AtomicLong | Byte | Integer | Long | ...)) {
return (a.longValue() % b.longValue()) == 0;
} else if (a, b instanceof (Double | DoubleAccumulator | DoubleAdder | Float) {
return (a.doubleValue() % b.doubleValue()) == 0;
} else if (a, b instanceof (BigInteger | BigDecimal)) {
return a.remainder(b) == ZERO;
} else {
throw new RuntimeError("I give up");
}
}
这在大多数情况下都很好,但它仍然无法正常工作,因为它无法处理 Number 的第三方子 classes,例如 org.apache.commons.math4.fraction.Fraction
?
仅限 JSON 个号码?
现在 OP 声明使用 Number
因为数字来自 JSON。这些数字通常只有 long
或 double
,因此类型检查方法就足够了。
但是,most popular libraries in Java 也支持将数字解释为 BigDecimal:
- Org.JSON 有
.getBigDecimal()
- GSON 有
.getAsBigDecimal()
- Jackson 支持
BigDecimal
个字段 - JavaEE 7 的
javax.json
(JSR 353) 有.bigDecimalValue()
BigDecimal 涵盖了 double
和 long
的范围,并且有一个实际的 .remainder()
method 解决了 OP 的问题。如果我们只想使用单个 class 来执行算术运算,并且 BigDecimal 的价格被认为不是一个大问题,这可能是一个可行的选择。