【问题标题】:Multiplying Large Number in java在java中乘以大数
【发布时间】:2017-01-11 02:44:54
【问题描述】:

我在 java 中乘以 2 非常大的数字,但乘法输出似乎有点奇怪
代码

long a =  2539586720l;
long b = 77284752003l;
a*=b;
System.out.println(a);
a=(long)1e12;
b=(long)1e12;
a*=b;
System.out.println(a);

输出:

-6642854965492867616
2003764205206896640

在第一种情况下,为什么结果是负数,如果是因为溢出,那么为什么第二个结果是正数?请解释这种行为? Code

Edit:

我正在使用mod=100000000009 操作仍然是负面的?

  a = ((a%mod)*(b%mod))%mod

【问题讨论】:

  • 这可能是由于截断,因为结果无法存储在long 中。如果long 还不够。尝试使用BigInteger
  • @redflar3 这不是问题,主要问题是为什么negative 在第一种情况下,而positive 在第二种情况下
  • long 最多可以容纳 (2^63-1 即 9e18),因为您的第一次乘法结果超过 1e20。这会导致截断,因此结果不正确。同样,第二个结果也被截断,因为它应该是 1e24。因此使用 BigInteger
  • @redflar3 那就是我想了解为什么 java 会出现这样的行为,两者都应该是-ve

标签: java multiplication


【解决方案1】:

对于long,您得到的结果通常是溢出问题:java 为数字分配63 位,为符号分配最高有效位 (MSB)(0 用于正值,@987654325 @ 表示负值)所以总共有 64 位。

所以知道Long.MAX_VALUE + 1 等于-9223372036854775808 因为Long.MAX_VALUE = 2^63 - 1 = 9223372036854775807 = 0x7fffffffffffffffL 所以如果我们添加1 到它,我们得到0x8000000000000000L= Long.MIN_VALUE = -2^63 = -9223372036854775808。在这种情况下,MSB 从0 切换到1,因此结果是否定的,这实际上是您在第一个用例中得到的结果。

如果 MSB 设置为 1 并且您通过一些计算导致新的溢出,它将再次切换到 0(因为我们只保留第一个 64 位)因此结果将为正数,即实际上是你在第二个用例中得到的。

为避免这种情况,您需要使用BigInteger

【讨论】:

    【解决方案2】:

    是的。这是一个溢出问题。 long 大小为 8 个字节,range goes from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

    如果你想乘以非常大的数字。使用BigInteger

    import java.math.*;
    
    public static void main(String[] args){
        BigInteger bi1, bi2, bi3;
    
        bi1 = new BigInteger("2539586720"); //or 1000000000000
        bi2 = new BigInteger("77284752003"); 
    
        // multiply bi1 with bi2 and assign result to bi3
        bi3 = bi1.multiply(bi2);
    
        String str = bi1 + " * " + bi2 + " = " +bi3;
        //Multiplication result is 2539586720 * 77284752003 = 196271329845312200160
    }
    

    【讨论】:

    • 导入 java.math.BigInteger 而不是 *
    【解决方案3】:

    根据JLS 15.17.1

    如果整数乘法溢出,则结果是数学乘积的低位,以某种足够大的二进制补码格式表示。因此,如果发生溢出,则结果的符号可能与两个操作数值的数学乘积的符号不同。

    这就是为什么您得到负值并且与输入数字没有任何相关性的原因。这是因为 Java 中的 long 只能表示从 -2^63 到 (2^63)-1 的范围,而您的结果大于此。

    为了避免这个问题,在处理大数运算时,您应该始终使用BigInteger。下面给出一个示例代码

    BigInteger.valueOf(123L).multiply(BigInteger.valueOf(456L));
    

    【讨论】:

      【解决方案4】:

      关于行为,两个例子都是溢出。一个答案是否定的这一事实并没有增加任何特殊含义。您相乘的第一组数字碰巧产生了最高有效位为 1 的 long,而后一组则没有。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-16
        • 1970-01-01
        相关资源
        最近更新 更多