Java 如何对两个数字实例使用模?
我遇到了一个场景,其中我有两个Java 如何对两个数字实例使用模?,java,numbers,modulo,Java,Numbers,Modulo,我遇到了一个场景,其中我有两个Number实例,我需要检查其中一个是否是另一个的倍数。 我尝试使用模来检查,例如: public static boolean isMultipleOf(Number a, Number b) { return a % b == 0; } 但是编译器不喜欢它: 运算符“%”不能应用于“java.lang.Number”, “java.lang.Number” 我明白为什么会这样,但我的问题是,实现这一点最简单的方法是什么? 实际值可以是任何类型的数字,我
Number
实例,我需要检查其中一个是否是另一个的倍数。我尝试使用模来检查,例如:
public static boolean isMultipleOf(Number a, Number b) {
return a % b == 0;
}
但是编译器不喜欢它:
运算符“%”不能应用于“java.lang.Number”,
“java.lang.Number”
我明白为什么会这样,但我的问题是,实现这一点最简单的方法是什么?实际值可以是任何类型的数字,我希望避免检查每个值的实际数字类型,然后才执行操作 有什么想法吗?
谢谢 您可以这样做:
public static boolean isMultipleOf(Number a, Number b) {
return a.longValue() % b.longValue() == 0;
}
当然,这假设
a
和b
在数学上是整数(短、整数或长)。您可以使用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'余数
方法,例如:
private static boolean isMultipleOf(Number a, Number b){
return new BigDecimal(a.doubleValue()).remainder(new BigDecimal(b.doubleValue())).doubleValue() == 0.0;
}
不,没有类型检查你是做不到的
A仅提供转换为原语的方法,并且每个原语都不足以给出准确的答案
doubleValue不起作用
由于double
只有53位精度,因此当输入是需要63位精度的long
时,它会给出错误的答案:
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不起作用
显然,由于截断,它不起作用
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的第三方子类,比如
仅限于JSON数字?
现在OP声明使用Number
,因为数字来自JSON。这些数字通常只有long
或double
,因此类型检查方法就足够了
但是,也支持将数字解释为BigDecimal:
- Org.JSON已经
- 格森有
- Jackson支持
字段BigDecimal
- JavaEE7的
(JSR353)具有javax.json
BigDecimal同时覆盖了
double
和long
的范围,并具有解决OP问题的实际值。如果我们只想使用单个类执行算术,而BigDecimal的价格不被认为是一个大问题,那么这是一个可行的选择。您不能,不能,不能这样做。放弃试图概括不同类型的数字
;它真的不是为了能做那样的事情而设计的。每个人都试着去做,但每个人都失败了。不要尝试。使用数字
可以做的唯一一件事就是在可能的情况下将其转换为原始数字类型,即使这样,您也无法知道是否降低了精度。@LouisWasserman我只使用数字
,因为我希望能够使用null
,而原始数字不允许这样做。显然,我需要转换为原语(编译器不允许我这样做),问题是“最简单的方法是什么”,似乎使用doubleValue
是。这不一定会产生有效的结果long
值在转换为double
时会四舍五入,这会弄乱%
结果。为什么要空值?空数字没有意义。我建议重新设计你的整个程序,这样你就只能用一种类型来表示你的数字。那么?将它们都转换为BigDecimal,并普遍使用。@kennytm添加了一个应该与BigDecimal一起使用的版本。谢谢,我接受它。我不会使用大数字,所以你的第一个选项就可以了。@DarshanMehta不,我说的是数字a
和b
已经是BigDecimal
,以及a=newbigdecimal(“3E+1000”)
和b=newbigdecimal(“2E+1000”)
。谢谢你深刻的回答。使用BigDecimal
对我来说可能是一种过度使用,因为我们将使用的数字只有两倍长。但它是教育性的!
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`.
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");
}
}