10
votes

Karatsuba algorithme sans usage de BigInteger

J'essaie d'implémenter l'algorithme de Karatsuba en Java sans utiliser BigInteger. Mon code est applicable uniquement lorsque les deux entiers sont identiques et ont le même nombre de chiffres. Je n'ai pas la bonne réponse, mais je reçois une réponse qui est assez proche de la bonne. Par exemple, j'obtiens 149 quand 12 * 12. Je ne peux pas comprendre ce qui ne va pas avec mon code depuis que je crois avoir tout fait de tout droit (par le livre). Voici mon code.

public static void main(String[] args) {
    System.out.println(Math.round(5.00/2));

    //correct answer
    long ans=karatsuba(5678,1234);
    System.out.println(ans);

    //correct answer
    long ans1=karatsuba(1234,5678);
    System.out.println(ans1);

    //wrong answer
    long ans2=karatsuba(102456,102465);
    System.out.println(ans2);
}


private static long karatsuba(long i, long j) {
    if (i<10 || j<10){
        return i*j;
    }

    double n=Math.round(getCount(i));

    long a=(long) (i/Math.pow(10, Math.round(n/2)));
    long b=(long) (i%Math.pow(10, Math.round(n/2)));
    long c=(long) (j/Math.pow(10, Math.round(n/2)));
    long d=(long) (j%Math.pow(10, Math.round(n/2)));

    long first=karatsuba(a,c);
    long second=karatsuba(b,d);

    long third=karatsuba(a+b,c+d);

    return ((long) ((first*Math.pow(10, Math.round(n)))+((third-second-first)*Math.pow(10, Math.round(n/2)))+second));

}

private static double getCount(long i) {
    String totalN=Long.toString(i);

    return totalN.length();
}


3 commentaires

Devez-vous rouler ou tronquer le résultat de Math.Pow à un entier avant de faire la division?


Comment votre méthode getcount est-elle mise en œuvre? Si je vous rappelle correctement et que votre méthode getcount renvoie le nombre de chiffres dans son paramètre, vous devez définir n sur max (getcount (i), getcount (j)) .


Ceci est une simple version en supposant que les deux chiffres sont même et ont un nombre égal de chiffres.


9 Réponses :


5
votes

Votre formule est fausse.

Premier * math.pow (10, N) + (troisième - premier - second) * math.pow (10, n / 2) + troisième

est faux, la formule doit être

Premier * math.pow (10, N) + (troisième - premier - second) * math.pow (10, n / 2) + second

wikipedia: xxx


3 commentaires

Merci, je ne sais pas comment j'ai fait cette erreur cependant après avoir remplacé «troisième» par «deuxième», je suis confronté à un problème: si Karatsuba (1234 5678), je reçois la bonne réponse cependant quand je le fais Karatsuba (5678 , 1234) Je n'ai pas la bonne réponse. Pourriez-vous éventuellement connaître la raison de cela? Encore merci.


Aucune solution facile pour celui-ci - Note 56 + 78 est à trois chiffres. Le calcul devient donc un gâchis après celui-ci.


Bonjour Ziyao, merci pour la réponse que j'ai réussi à tordre le code un peu pour le faire fonctionner, mais j'ai toujours des bugs lors de la résolution de nombres supérieurs à 4 chiffres. J'ai rassemblé la valeur de "n / 2".



0
votes
2*floor(n/2)

0 commentaires

0
votes

Voici la bonne approche (votre réponse modifiée): xxx


0 commentaires

2
votes

Le dernier bogue est que la ronde (n) doit être 2 * ronde (N / 2). Ils diffèrent évidemment pour NI-N.

concernant int n = getcount (i); c'est une source de disshayme, de sorte qu'il devrait être changé.
Pour l'efficacité, il ne doit pas être remplacé par max (getcount (i), getcount (j)) comme je lisais dans un commentaire ci-dessus, mais plutôt avec min .
En effet, Karatsuba n'a de sens que pour scinder des nombres bien équilibrés.
Essayez de décomposer les opérations effectuées avec MAX et MIN pour être sûr ...


0 commentaires

0
votes

vous définissez i = a * b + b et j = c * b + d, où b = 10 ^ m et m = n / 2. Alors xxx

Cependant, dans la moitié des cas B ^ 2 = 10 ^ (2m) n'est pas égal à 10 ^ N, car pour une personne étrange a n = 2 * m + 1, donc Dans ce cas, b ^ 2 = 10 ^ (n-1).

Je suggère donc de définir une fois m = n / 2 ou meilleur m = (n + 1) / 2 < / code>, b = (long) math.pow (10, m) et utilisez-le pour calculer A, B, C, D et dans la sommation finale Utilisez le facteur B * b.


0 commentaires

1
votes

Enfin, après plusieurs heures de pensée, j'ai trouvé la solution correcte: xxx pré>

Je ne peux pas expliquer pourquoi n ne peut pas être étrange fort>, mais juste Maintenant, la multiplication fonctionne correctement pour le tas de tests que j'ai écrit. Je vais expliquer ce comportement dès que je découvrirai. P>

Mise à jour: strong> Je prends des algorithmes: conception et analyse, cours de la partie 1 sur Coursera et posté une question sur ce comportement. Voici une réponse de Andrew Patton: P>

Comme mentionné ailleurs, la clé avec rupture des entrées consiste à s'assurer que B et D est la même longueur, de sorte que A et C ont la même puissance de 10 coefficients. Quoi que ce pouvoir devienne votre N / 2; ... Donc, la valeur du n dans 10 ^ N n'est pas réellement la longueur totale de vos entrées, mais plutôt N / 2 * 2. p> BlockQuote>

Donc, dans le cas d'un numéro de 3 chiffres Vous suivez Exemple: P>

n = 3;   
n/2 = 2;
n != n/2 * 2;


0 commentaires

-1
votes
/** Function to multiply two numbers **/
    public long multiply(long x, long y)
    {
        int size1 = getSize(x);
        int size2 = getSize(y);
        /** Maximum of lengths of number **/
        int N = Math.max(size1, size2);
        /** for small values directly multiply **/        
        if (N < 10)
            return x * y;
        /** max length divided, rounded up **/    
        N = (N / 2) + (N % 2);    
        /** multiplier **/
        long m = (long)Math.pow(10, N);

        /** compute sub expressions **/        
        long b = x / m;
        long a = x - (b * m);
        long d = y / m;
        long c = y - (d * N);
        /** compute sub expressions **/
        long z0 = multiply(a, c);
        long z1 = multiply(a + b, c + d);
        long z2 = multiply(b, d);          

        return z0 + ((z1 - z0 - z2) * m) + (z2 * (long)(Math.pow(10, 2 * N)));        
    }
    /** Function to calculate length or number of digits in a number **/
    public int getSize(long num)
    {
        int ctr = 0;
        while (num != 0)
        {
            ctr++;
            num /= 10;
        }
        return ctr;
    }
That is realization for BigInteger:http://www.nayuki.io/res/karatsuba-multiplication/KaratsubaMultiplication.java

1 commentaires

Arrondi avec N / D + N% D semble une nouveauté.



0
votes

Au lieu de arrondi avec Math.Round (), j'ajoute 1 à la valeur de la taille d'entrée (la minute du nombre de chiffres dans X ou Y), si la taille d'entrée est impair. Par exemple, si x = 127 & y = 162, la taille d'entrée est ensuite 3. Incrément de 1 pour le faire 4. ALORN, A = X / MATH.POW (10, INPUT_SIZE / 2) = 1. B = x% Math .pow (10, INPUT_SIZE / 2) = 27. De même, C = 1 et D = 62. Maintenant, si nous calculons X * Y = (AC) * Math.Pow (10, INPUT_SIZE) + (AD + BC) * Math.pow (10, INPUT_SIZE / 2) + BD; Cela donne la bonne réponse. N'oubliez pas que nous incrémentons la taille d'entrée de 1 seulement quand c'est étrange. La mise en œuvre complète est ici - https://github.com/ Parag-vijay / data_structures / blob / maître / java / karatsubamultiplication.java


0 commentaires

1
votes

Voici la bonne implémente à l'aide de LIPS:

import java.math.BigInteger;
import java.util.Scanner;

/**
 * x=5678 y=1234
 * 
 * a=56,b=78
 * 
 * c=12,d=34
 * 
 * step 0 = m = n/2 + n%2
 * 
 * step 1 = a*c
 * 
 * step 2 = b*d
 * 
 * step 3 = (a + b)*(c + d)
 * 
 * step 4 = 3) - 2) - 1)
 * 
 * step 5 = 1)*pow(10, m*2) + 2) + 4)*pow(10, m)
 *
 */
public class Karatsuba {

    public static void main(String[] args) {
        BigInteger x, y;
        try (Scanner s = new Scanner(System.in)) {
            x = s.nextBigInteger();
            y = s.nextBigInteger();
        }
        BigInteger result = karatsuba(x, y);
        System.out.println(result);
    }

    private static BigInteger karatsuba(BigInteger x, BigInteger y) {
        if (x.compareTo(BigInteger.valueOf(10)) < 0 && y.compareTo(BigInteger.valueOf(10)) < 0)
            return x.multiply(y);

        int n = Math.max(x.toString().length(), y.toString().length());
        int m = n / 2 + n % 2;

        BigInteger[] a_b = x.divideAndRemainder(BigInteger.valueOf(10).pow(m));
        BigInteger a = a_b[0];
        BigInteger b = a_b[1];
        BigInteger[] c_d = y.divideAndRemainder(BigInteger.valueOf(10).pow(m));
        BigInteger c = c_d[0];
        BigInteger d = c_d[1];

        BigInteger step1 = karatsuba(a, c);
        BigInteger step2 = karatsuba(b, d);
        BigInteger step3 = karatsuba(a.add(b), c.add(d));
        BigInteger step4 = step3.subtract(step2).subtract(step1);
        BigInteger step5 = step1.multiply(BigInteger.valueOf(10).pow(m * 2)).add(step2)
                .add(step4.multiply(BigInteger.valueOf(10).pow(m)));
        return step5;
    }

}


0 commentaires