2013-07-08 5 views
8

मैं बिगइंटर का उपयोग किए बिना जावा में करात्सुबा एल्गोरिदम लागू करने की कोशिश कर रहा हूं। मेरा कोड केवल तभी लागू होता है जब दोनों पूर्णांक समान होते हैं & में अंकों की संख्या समान होती है। मुझे सही जवाब नहीं मिला है, हालांकि मुझे जवाब मिलता है जो सही के करीब है। उदाहरण के लिए मुझे 14 9 मिलते हैं जब 12 * 12। मैं यह नहीं समझ सकता कि मेरे कोड में क्या गलत है क्योंकि मेरा मानना ​​है कि मैंने सबकुछ सही किया है (पुस्तक द्वारा)। मेरा कोड यहाँ है।बिगइंटर उपयोग के बिना करात्सुबा एल्गोरिदम

public static void main(String[] args) { 
    long ans=karatsuba(12,12); 
    System.out.println(ans); 
} 

private static long karatsuba(long i, long j) { 
    if (i<10 || j<10){ 
     return i*j; 
    } 
    int n=getCount(i); 
    long a=(long) (i/Math.pow(10, n/2)); 
    long b=(long) (i%Math.pow(10, n/2)); 
    long c=(long) (j/Math.pow(10, n/2)); 
    long d=(long) (j%Math.pow(10, 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, n))+((third-first-second)*Math.pow(10,n/2))+third)); 
} 

private static int getCount(long i) { 
    String totalN=Long.toString(i); 
    return totalN.length(); 
} 

संपादित करें:

Ziyao वी के लिए धन्यवाद, समस्या "तीसरे" की जगह किया गया था "दूसरी" द्वारा। हालांकि मेरे पास अब एक और मुद्दा है जो है:

अगर करत्सुबा (1234,5678) कहा जाता है तो मुझे सही जवाब मिलता है, हालांकि जब मैं करत्सुबा (5678,1234) कहता हूं तो मुझे सही जवाब नहीं मिलता है। क्या किसी को संभवतः इसके कारण का पता चल सकता है? मेरे अद्यतन कोड है:

public static void main(String[] args) { 
    //wrong answer 
    long ans=karatsuba(5678,1234); 
    System.out.println(ans); 

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

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

    int n=getCount(i); 

    long a=(long) (i/Math.pow(10, n/2)); 
    long b=(long) (i%Math.pow(10, n/2)); 
    long c=(long) (j/Math.pow(10, n/2)); 
    long d=(long) (j%Math.pow(10, 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, n))+((third-first-second)*Math.pow(10, n/2))+second)); 

} 

अद्यतन:

मैं के लिए "n/2" मूल्य को ख़त्म कर में कामयाब रहे, इसलिए यह समस्या लेकिन यदि संख्या चार से अधिक अंक उपयोग किया जाता है बग उत्पन्न हल करती है।

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(); 
} 

किसी BigInteger का उपयोग कर तो कृपया मुझे पता है है बिना बड़ी संख्या (चार से अधिक अंक) के लिए समाधान के साथ आता है: यहाँ मेरी अद्यतन कोड है। धन्यवाद।

+0

आप दौर या विभाजन करने से पहले एक पूर्णांक के लिए Math.pow परिणाम काटना चाहिए? –

+0

आपकी GetCount विधि कैसे कार्यान्वित की जाती है? अगर मुझे सही ढंग से याद आता है और आपकी getCount विधि अपने पैरामीटर में अंकों की संख्या लौटाती है, तो आपको 'n' 'max (getCount (i), getCount (j)) सेट करना चाहिए। – jarnbjo

+0

यह एक साधारण संस्करण है यह मानते हुए कि दोनों संख्याएं भी संख्याओं के बराबर हैं और उनके पास हैं। – Khan

उत्तर

5

आप सूत्र गलत है।

पहले * Math.pow (10, एन) + (तृतीय - पहले - दूसरे) * Math.pow (10, एन/2) + तीसरे

गलत है, सूत्र होना चाहिए

पहले * Math.pow (10, एन) + (तृतीय - पहले - दूसरे) * Math.pow (10, एन/2) + दूसरा

विकिपीडिया:

z0 = karatsuba(low1,low2) 
z1 = karatsuba((low1+high1),(low2+high2)) 
z2 = karatsuba(high1,high2) 
return (z2*10^(m))+((z1-z2-z0)*10^(m/2))+(z0) 
+0

धन्यवाद, मैं नहीं जानता कि मैं कैसे उस गलती क्या किया लेकिन "तीसरे" की जगह एक समस्या "दूसरी" मैं का सामना करना पड़ रहा है, जिसके माध्यम से के बाद: तो karatsuba (1234,5678) मैं सही जवाब हालांकि जब मैं करता हूँ करात्सुबा (5678,1234) मुझे सही जवाब नहीं मिला है। क्या आप संभवतः इसके कारण जान सकते हैं? एक बार फिर से धन्यवाद। – Khan

+0

उस के लिए कोई आसान फिक्स नहीं - नोट 56 + 78 तीन अंक है, इसलिए गणना उसके बाद एक गड़बड़ हो जाती है। –

+0

हैलो Ziyao, उत्तर के लिए धन्यवाद मैं यह काम हालांकि मैं अभी भी कीड़े है जब 4 अंक की तुलना में अधिक से अधिक संख्या के लिए सुलझाने बनाने के लिए कोड एक सा मोड़ में कामयाब रहे। मैंने "एन/2" के मूल्य को गोलाकार किया। – Khan

0
first * Math.pow(10, 2*degree) + (third - first - second) * Math.pow(10, degree) + second 

जहां

degree = floor(n/2) 

कोई roundings, कम से कम है कि मैं क्या पता है ...

उदाहरण के लिए,

normal: 5/2 = 2.5 
floor: 5/2 = 2 
round: 5/2 = 3 

और इसलिए , आप क्या करते हो...

round(n) 

है यही कारण है कि मैं क्या सोचता

2*floor(n/2) 

के समान नहीं है,

सादर

0

यहाँ सही दृष्टिकोण (आपका जवाब संशोधित) है:

public class KaratsubaMultiplication { 

public static void main(String[] args) { 
    //correct answer 
    long ans=karatsuba(234,6788); 
    System.out.println("actual " + ans); 
    System.out.println("expected " + 234*6788); 

    long ans0=karatsuba(68,156); 
    System.out.println("actual " +ans0); 
    System.out.println("expected " + 68*156); 

    long ans1=karatsuba(1234,5678); 
    System.out.println("actual " + ans1); 
    System.out.println("expected " + 1234*5678); 

    long ans2=karatsuba(122,456); 
    System.out.println("actual " +ans2); 
    System.out.println("expected " + 122*456); 

    long ans3=karatsuba(102456,102465); 
    System.out.println("actual " + ans3); 
    System.out.println("expected " + 102456l * 102465l); 
} 


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

    double n=Long.toString(i).length(); 


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

    long first=karatsuba(a,c); 

    long second=karatsuba(b,d); 

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

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

} 

} 
2

अंतिम बग यह है कि दौर (एन) 2 * दौर (एन/2) होना चाहिए। वे स्पष्ट रूप से विषम एन के लिए भिन्न हैं।

int n=getCount(i); से संबंधित यह विघटन का स्रोत है, इसलिए इसे बदला जाना चाहिए।
दक्षता के लिए इसे max(getCount(i),getCount(j)) द्वारा प्रतिस्थापित नहीं किया जाना चाहिए जैसा कि मैंने उपरोक्त टिप्पणी में पढ़ा है, बल्कि min के साथ।
वास्तव में, करात्सुबा केवल संतुलित संख्याओं को विभाजित करते समय समझ में आता है।
प्रयास करें और अधिकतम और न्यूनतम के साथ प्रदर्शन सुनिश्चित करने के लिए आपरेशन विघटित ...

0

आप सेट मैं = एक * बी + ख और j = ग * बी + घ, जहां बी = 10^मीटर और मीटर = n/2। तब

i*j=B^2*(a*c)+B*(a*c+b*d-(a-b)*(c-d))+c*d 

हालांकि, आधा मामलों में बी^2 = 10^(2m) नहीं 10^n के बराबर है, के बाद से के लिए अजीब n एक है एन = है 2 * मीटर + 1, इसलिए इस मामले में, बी^2 = 10^(एन -1)।

तो मैं परिभाषित करने के लिए सुझाव है कि एक बार मीटर = n/2 या बेहतर m=(n+1)/2, B=(long)Math.pow(10,m) और इसका इस्तेमाल गणना करने के लिए ए, बी, सी, डी और अंतिम योग में उपयोग कारक बी * बी।

1

अंत में, सोच के कई घंटे के बाद मैंने पाया सही समाधान:

public static long karatsuba(long i, long j) { 
    if (i < 10 || j < 10) { 
     return i * j; 
    } 
    double n = Math.round(getCount(i)); 
    if (n % 2 == 1) { 
     n++; 
    } 
    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, n)) + ((third - first - second) * Math.pow(10, Math.round(n/2))) + second)); 
} 

मैं व्याख्या नहीं कर सकते क्यों n विषम नहीं किया जा सकता है, लेकिन अभी गुणा गुच्छा के लिए सही ढंग से काम कर रहा है मैंने परीक्षण किए हैं। जैसे ही मुझे पता चल जाएगा मैं इस व्यवहार को समझाऊंगा।

अद्यतन: मैं एल्गोरिदम ले रहा हूं: डिजाइन और विश्लेषण, coursera पर भाग 1 कोर्स, और इस व्यवहार के बारे में एक प्रश्न पोस्ट किया। एंड्रयू पैटन द्वारा यहां एक उत्तर दिया गया है:

जैसा कि कहीं और बताया गया है, इनपुट को तोड़ने की कुंजी यह सुनिश्चित करने के लिए है कि बी और डी एक ही लंबाई हैं, ताकि ए और सी में 10 की समान शक्ति हो गुणांक। जो भी शक्ति आपके एन/2 बन जाती है; ... तो, 10^एन में n का मान वास्तव में आपके इनपुट की कुल लंबाई नहीं है, बल्कि n/2 * 2 है।

तो 3 अंकों की संख्या के मामले में आप उदाहरण का पालन करना:

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

तो n इस उदाहरण में बराबर n/2 * 2 = 4 होना चाहिए।

आशा है कि यह समझ में आता है।

-1
/** 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; 
    } 

BigInteger के लिए अहसास है कि: इसके बजाय

http://www.nayuki.io/res/karatsuba-multiplication/KaratsubaMultiplication.java

+0

एन/डी + एन% डी का उपयोग करके गोल करना एक नवीनता दिखता है। – greybeard

0

गणित.गोल() के साथ बंद गोलाई की, मैं इनपुट आकार (के # मिनट के मूल्य के 1 द्वारा जोड़ा जा रहा या तो x या y में अंक), यदि इनपुट आकार विषम है। उदाहरण के लिए यदि एक्स = 127 & वाई = 162, तो इनपुट आकार 3. बढ़ते क्रम में यह 1 से यह एक = एक्स/Math.pow (10, input_size/2) = 1. ख = एक्स% मठ तब 4. बनाने के लिए है .pow (10, input_size/2) = 27. इसी तरह, ग = 1 और डी = 62. अब, अगर हम गणना एक्स * वाई = (एसी) * Math.pow (10, input_size) + (विज्ञापन + bc) * Math.pow (10, input_size/2) + bd; यह सही जवाब देता है। बस याद रखें, हम इनपुट आकार को केवल 1 तक बढ़ाते हैं जब यह विषम है। पूर्ण कार्यान्वयन यहाँ है - https://github.com/parag-vijay/data_structures/blob/master/java/KaratsubaMultiplication.java

संबंधित मुद्दे