initial commit

This commit is contained in:
Sebastian Seedorf
2020-12-06 19:00:51 +01:00
commit 2234d5e7c5
12 changed files with 375 additions and 0 deletions

3
src/META-INF/MANIFEST.MF Normal file
View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: de.sebse.karatsubabiginteger.Main

View File

@@ -0,0 +1,180 @@
package de.sebse.karatsubabiginteger;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static final int LONG_SHIFT = (int) Math.pow(10, (int) Math.log10(Long.MAX_VALUE)/2-1);
//100000000, Die etwas weniger als die Hälfte eines Long als 10er Potenz
public static void main(String[] args) {
//main für Zeittest
/*long zeit=0;
long z=0;
for (int i=0;i<100;i++){
z=testTime(9000);
System.out.println(z+ " Millisek.");
zeit=zeit+ z;
System.out.println("i:"+i);
}
System.out.println(((long) zeit/100)+ " Millisek.");*/
//main für eingabe über die Console
Scanner scanner = new Scanner(System.in);
System.out.println("Number 1: ");
BigInteger a = scanner.nextBigInteger();
System.out.println("Number 2: ");
BigInteger b = scanner.nextBigInteger();
System.out.println("Ergebnis der BigInteger Multiplikation:");
System.out.println(a.multiply(b));
System.out.println("Ergebnis der karatsuba Multiplikation:");
System.out.println(karatsubaMultiplication(a, b));
}
public static Long testTime(int n){//Funktion zum zeitmessen wie lange an einer Multiplikation gerechnet wird
String zufallszahl = "";
for (int i=0; i<n/10;i++){//Zufallszahlen erzeugen
zufallszahl=zufallszahl + String.valueOf((int) (Math.random()*Math.pow(10,17)));
}
BigInteger a = new BigInteger(zufallszahl);
zufallszahl = "";
for (int i=0; i<n/10;i++){
zufallszahl=zufallszahl + String.valueOf((int) (Math.random()*Math.pow(10,17)));
}
BigInteger b = new BigInteger(zufallszahl);
System.out.println(zufallszahl.length());
split(a);
split(b);
final long timeStart = System.currentTimeMillis();
System.out.println(karatsubaMultiplication(a, b));
final long timeEnd = System.currentTimeMillis();
return timeEnd - timeStart;
}
private static BigInteger karatsubaMultiplication(BigInteger a, BigInteger b) {//Muss für die Karatsuba-Multiplikation aufgerufen werden (main)
List<Long> lista = split(a);
List<Long> listb = split(b);
return merge(multiply(lista, listb, 0, 0, listb.size()));
}
private static List<Long> multiply(List<Long> a, List<Long> b, long startA, long startB, long len) {//rekusiver Karatsuba-Algorithmus
if (a.size()!=a.size())
throw new IllegalArgumentException();
// size(a) have to equals size(b)
if (len==1) {
List<Long> ret = new ArrayList<>(); // size(ret) in {1, 2}
long value = a.get((int) startA)*b.get((int) startB);
long carry = value / LONG_SHIFT;
ret.add(value % LONG_SHIFT);
if (carry != 0)
ret.add(carry);
return ret;
} else {
long endA = startA+len;
long endB = startB+len;
long midA = startA+len/2;
long midB = startB+len/2;
// A-low + A-high
List<Long> addA = add(a.subList((int) startA, (int) midA), a.subList((int) midA, (int) endA));
// B-low + B-high
List<Long> addB = add(b.subList((int) startB, (int) midB), b.subList((int) midB, (int) endB));
while (addA.size()>addB.size())
addB.add((long) 0);
while (addB.size()>addA.size())
addA.add((long) 0);
List<Long> retC = multiply(addA, addB, 0, 0, addA.size());
// A-low * B-low
List<Long> retA = multiply(a, b, startA, startB, midA-startA);
// A-high * B-high
List<Long> retB = multiply(a, b, midA, midB, len-(midA-startA));
retC = sub(retC, add(retA, retB));
return add(add(retB, retC, len/2), retA, len/2);
}
}
private static List<Long> sub(List<Long> a, List<Long> b) {//Subtrahieren zweier long[]
// if b smaller than a
for (int i = 0; i < b.size(); i++) {
b.set(i, -b.get(i));
}
return add(a, b);
}
private static List<Long> add(List<Long> a, List<Long> b) {
return add(a, b, 0);
}
private static List<Long> add(List<Long> a, List<Long> b, long shiftA) {//Addieren zweier Long[],
// a kann noch mit shiftA verschoben werden und die Zahlen können unterschiedlich lang sein
List<Long> ret = new ArrayList<>();
long offsetB = 0;
for (; offsetB < shiftA; offsetB++) {
if (offsetB>=b.size())
ret.add((long) 0);
else
ret.add(b.get((int) offsetB));
}
long offsetA = 0;
long carry = 0;
// a[i]+b[i]
for (; offsetB < b.size() && offsetA < a.size(); offsetB++, offsetA++) {
long value = b.get((int) offsetB)+a.get((int) offsetA)+carry;
carry = value / LONG_SHIFT;
ret.add(value % LONG_SHIFT);
}
// b ist länger als a
for (; offsetB < b.size(); offsetB++) {
long value = b.get((int) offsetB)+carry;
carry = value / LONG_SHIFT;
ret.add(value % LONG_SHIFT);
}
// a ist länger als b
for (; offsetA < a.size(); offsetA++) {
long value = a.get((int) offsetA)+carry;
carry = value / LONG_SHIFT;
ret.add(value % LONG_SHIFT);
}
// Evtl. zusätzliche Stelle durch Übertrag
if (carry != 0)
ret.add(carry);
return ret;
}
private static List<Long> split(BigInteger a) {//spaltet ein BigInteger in ein Long ArrayList auf
BigInteger b = BigInteger.valueOf(LONG_SHIFT);
List<Long> list = new ArrayList<>();
//noinspection ComparatorResultComparison
while (a.compareTo(b) != -1) {
list.add(a.mod(b).longValue());
a = a.divide(b);
}
list.add(a.longValueExact());
return list;
}
private static BigInteger merge(List<Long> list) {//Ergebnis zusammen fügen
BigInteger result = new BigInteger("0");
int count = 0;
for (Long val: list) {
result = result.add(BigInteger.valueOf(val).multiply(BigInteger.valueOf(LONG_SHIFT).pow(count)));
count++;
}
return result;
}
}