Умножение большого числа в java

Я умножаю 2 очень большое число в java, но результат умножения кажется немного странным
Код

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

В первом случае, почему результат отрицательный, если это из-за переполнения, то почему во втором случае результат положительный? Пожалуйста, объясните это поведение? Код

Edit:

Я использую операцию mod=100000000009, но результат отрицательный?

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

person Narendra Modi    schedule 10.01.2017    source источник
comment
Это может быть связано с усечением, так как результат не может быть сохранен в long. Если long недостаточно. Попробуйте использовать BigInteger   -  person Jos    schedule 10.01.2017
comment
@redflar3 это не проблема, главная проблема в том, почему negative в первом случае, а positive во втором случае   -  person Narendra Modi    schedule 10.01.2017
comment
long может содержать до (2 ^ 63-1, что равно 9e18), где результат вашего первого умножения превышает 1e20. это вызывает усечение, поэтому результат неверен. аналогично второй результат также усекается, поскольку он должен быть 1e24. следовательно, используйте BigInteger   -  person Jos    schedule 10.01.2017
comment
@redflar3, я хочу понять, почему java ведет себя так, должно быть -ve для обоих   -  person Narendra Modi    schedule 10.01.2017
comment
возможный дубликат stackoverflow.com/questions/7215411/   -  person dreamer    schedule 10.01.2017
comment
docs.oracle.com/javase/specs/jls/ se8/html/jls-15.html найдите 15.17.1, найдите integer multiplication overflows   -  person Jos    schedule 10.01.2017


Ответы (4)


Результатом, который вы получаете, обычно является проблема переполнения, для long: java выделяет 63 бит для числа и старший бит (MSB) для знака (0 для положительных значений и 1 для отрицательных значений), поэтому всего 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 .

person Nicolas Filotto    schedule 10.01.2017

да. Это проблема переполнения. Длинный размер составляет 8 байт, а диапазон составляет от -9 223 372 036 854 775 808 до 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
}
person Luis Lavieri    schedule 10.01.2017
comment
Импортировать java.math.BigInteger, а не * - person Michael; 10.01.2017

Согласно JLS 15.17.1.

Если целочисленное умножение переполняется, то результатом являются младшие биты математического произведения, представленные в некотором достаточно большом формате с дополнением до двух. В результате, если происходит переполнение, то знак результата может не совпадать со знаком математического произведения двух значений операнда.

Вот почему вы получаете отрицательные значения и не имеете никакой корреляции с входными числами. Это связано с тем, что long в Java может представлять только от -2 ^ 63 до (2 ^ 63) -1, а ваш результат больше этого.

Чтобы избежать этой проблемы, при работе с арифметикой больших чисел всегда следует использовать BigInteger. Пример кода приведен ниже

BigInteger.valueOf(123L).multiply(BigInteger.valueOf(456L));
person Jos    schedule 10.01.2017

Что касается поведения, оба являются примерами переполнения. Тот факт, что один ответ отрицательный, особого смысла не добавляет. Первый набор чисел, который вы умножили, привел к длинному, старший бит которого равен 1, а последний набор - нет.

person Frelling    schedule 10.01.2017