2009-03-05 3 views
8

मेरे कोड में मुझे अक्षांश/लंबे मानों के जोड़े के बीच बहुत दूरी की गणना करना है।दूरी गणना फ़ंक्शन का अनुकूलन

कोड इस तरह दिखता है:

double result = Math.Acos(Math.Sin(lat2rad) * Math.Sin(lat1rad) 
+ Math.Cos(lat2rad) * Math.Cos(lat1rad) * Math.Cos(lon2rad - lon1rad)); 

(lat2rad जैसे अक्षांश रेडियंस में बदल जाती है)।

मैंने इस फ़ंक्शन को मेरे एप्लिकेशन की प्रदर्शन बाधा के रूप में पहचाना है। क्या इसे सुधारने का कोई तरीका है?

(निर्देशांक अलग-अलग होने के बाद से मैं लुक-अप टेबल का उपयोग नहीं कर सकता)। मैंने this question पर भी देखा है जहां एक ग्रिड की तरह एक लुकअप योजना सुझाई जाती है, जो एक संभावना हो सकती है।

आपके समय के लिए धन्यवाद! ;-)

+0

आप जानते हैं कि इस एल्गोरिथ्म केवल सही है हो सकता है अगर आप को लगता है कि पृथ्वी एक आदर्श क्षेत्र और सन्निकटन और वास्तविक जवाब सीए के बीच मतभेद है एन काफी महत्वपूर्ण हो (कम से कम मेरी दुनिया में)। http://en.wikipedia.org/wiki/WGS84 –

+0

यह सच है। आपको वास्तव में महान सर्कल मार्गों की गणना करने की आवश्यकता हो सकती है। –

+0

हाँ मुझे पता है, लेकिन मेरे मामले के लिए अनुमान ठीक है। जहां तक ​​मुझे पता है कि पृथ्वी घूर्णन के कारण भूमध्य रेखा के चारों ओर विचलन सबसे बड़ा है। – puls200

उत्तर

5

अपने लक्ष्य को रैंक करने के लिए (तुलना) है, तो दूरी, तो अनुमानों (sin और cos तालिका लुकअप) काफी आवश्यक संगणना (लागू त्वरित अस्वीकार करते हैं।)

की अपनी राशि को कम कर सकता है आपका लक्ष्य केवल वास्तविक त्रिकोणमितीय गणना के साथ आगे बढ़ना है यदि अनुमानित दूरी (रैंक या तुलना करने के लिए) के बीच का अंतर एक निश्चित दहलीज से नीचे आता है।

उदा। 1000 नमूने के साथ लुकअप टेबल का उपयोग करना (यानी sin और cos प्रत्येक 2*pi/1000 नमूना), लुकअप अनिश्चितता अधिकतम 0.006284 पर है। पैरामीटर के लिए uncertainty calculation का उपयोग ACos पर करें, संचयी अनिश्चितता भी थ्रेसहोल्ड अनिश्चितता होगी, जो 0.018731 पर होगी।

तो, Math.Sin(lat2rad) * Math.Sin(lat1rad) + Math.Cos(lat2rad) * Math.Cos(lat1rad) * Math.Cos(lon2rad - lon1rad) का मूल्यांकन दो समन्वय सेट जोड़े (दूरी) के लिए एक निश्चित रैंकिंग sin और cos देखने तालिकाओं का उपयोग पैदावार अगर (एक दूरी अन्य सन्निकटन के आधार पर की तुलना में अधिक दिखाई देता है), और अंतर के मापांक से अधिक है ऊपर सीमा, तो अनुमान वैध है। अन्यथा वास्तविक त्रिकोणमितीय गणना के साथ आगे बढ़ें।

+0

धन्यवाद, आपका उत्तर मुझे सही रास्ते पर रखता है। मुझे यकीन है कि कुछ अन्य उत्तर भी वैध हैं। 50,000 प्रविष्टियों परिशुद्धता के साथ एक लुकअप टेबल का उपयोग करना अभी भी काफी अच्छा है। स्पीडअप पिछले प्रदर्शन के बारे में 3 गुना है। – puls200

0

आपको मूल्यों की कितनी सटीक आवश्यकता है?

यदि आप अपने मूल्यों को थोड़ा सा गोल करते हैं तो आप सभी लुकअप के परिणाम स्टोर कर सकते हैं और जांच सकते हैं कि प्रत्येक गणना के लिए क्या उपयोग किया गया है?

1

पाप/कॉस/एकोस के लिए लुकअप टेबल पर स्विचिंग। तेजी से होगा, सी/सी ++ निश्चित बिंदु पुस्तकालयों में से बहुत सारे हैं जो उनको भी शामिल करते हैं।

यहां Memoization पर किसी और से कोड है। यदि वास्तविक मूल्यों का उपयोग अधिक क्लस्टर किया जाता है तो कौन सा काम कर सकता है।

यहां Fixed Point पर एक SO प्रश्न है।

4

क्या CORDIC एल्गोरिदम आपके लिए काम करेगा (गति/सटीकता के संबंध में)?

+0

इस विचार के लिए धन्यवाद, मैं यह देखने के लिए विभिन्न दृष्टिकोणों का प्रयास करूंगा कि सबसे अच्छा क्या काम करता है। – puls200

0

ठीक है, चूंकि लैट और लॉन एक निश्चित सीमा के भीतर गारेन किए गए हैं, इसलिए आप मैथ के लिए लुकअप टेबल के कुछ रूपों का उपयोग करने का प्रयास कर सकते हैं। * विधि कॉल। कहते हैं, एक Dictionary<double,double>

3

@ ब्रैन से प्रेरणा का उपयोग करना मुझे लगता है कि आप गणना को थोड़ा कम कर सकते हैं (यह लंबे समय तक चेतावनी दे रहा है क्योंकि मैंने इनमें से कोई भी किया है और इसे सत्यापित करने की आवश्यकता होगी)। precalculated मूल्यों के देखने के कुछ प्रकार शायद सबसे तेजी से हालांकि

आपके पास:

1: ACOS (SIN एक पाप बी + भंडार नियंत्रक एक भंडार नियंत्रक बी भंडार नियंत्रक (एबी))

लेकिन 2: भंडार नियंत्रक (एबी) = SIN एक पाप बी + भंडार नियंत्रक एक भंडार नियंत्रक बी

जो के रूप में 3 फिर से लिखा है: SIN एक पाप बी = भंडार नियंत्रक (एबी) - भंडार नियंत्रक एक भंडार नियंत्रक बी

1 में SIN एक पाप बी की जगह आप:

4: एसीओएस (सीओएस (एबी) - सीओएस ए सीओएस बी + सीओएस ए सीओएस बी सीओएस (एबी))

आप एक्स = सीओएस (एबी) और वाई = सीओएस ए सीओएस बी की पूर्व-गणना करते हैं और आप मूल्य डालते हैं 4

में देने के लिए:

ACOS (XY + XY)

4 ट्रिग के बजाय गणना 6!

1

बोतल गर्दन क्या है? क्या साइन/कोसाइन फ़ंक्शन कॉल या आर्केसिन कॉल है?

अपने ज्या/कोज्या कॉल धीमी गति से कर रहे हैं, आप इतने सारे कॉल को रोकने के लिए निम्नलिखित प्रमेय इस्तेमाल कर सकते हैं:

1 = sin(x)^2 + cos(x)^2 
cos(x) = sqrt(1 - sin(x)^2) 

लेकिन मैं मानचित्रण विचार पसंद है, ताकि आप की जरूरत नहीं है मानों आप recompute करने ' पहले से ही गणना की है। हालांकि सावधान रहें क्योंकि मानचित्र बहुत तेज़ी से बहुत बड़ा हो सकता है।

0

मैं तर्क दूंगा कि आप फिर से जांच कर सकते हैं कि आपने उस कार्य को बाधा कैसे पाया। (आईई आपने एप्लिकेशन को प्रोफाइल किया था?)

मेरे समीकरण मुझे बहुत हल्का वजन लगता है और कोई समस्या नहीं होनी चाहिए। अनुमोदित, मुझे आपका आवेदन नहीं पता है और आप कहते हैं कि आप इन गणनाओं में से बहुत कुछ करते हैं।

फिर भी यह विचार करने के लिए कुछ है।

+0

मैंने अपने आवेदन की जांच करने के लिए वीएस 2008 प्रोफाइलर का उपयोग किया। गणना कुछ समय (कई मिनट) के लिए चलती है, इसलिए मुझे पूरा यकीन है कि नमूना उत्पादन सही है। – puls200

+0

यदि वह रेखा _minutes_ ले रही है तो कुछ ख़राब हो रहा है। –

2

बदलें जिस तरह से आप की दुकान देशांतर/अक्षांश:

struct LongLat 
{ 
    float 
    long, 
    lat, 
    x,y,z; 
} 

जब बनाने एक देशांतर/अक्षांश, भी (एक्स, वाई, जेड) 3 डी का कहना है कि एक इकाई क्षेत्र पर केन्द्रित पर बराबर स्थिति का प्रतिनिधित्व करता है की गणना मूल।

अब, अगर बिंदु बी बिंदु सी की तुलना में एक बात करने के लिए नजदीक है निर्धारित करने के लिए, निम्न करें:

// is B nearer to A than C? 
bool IsNearer (LongLat A, LongLat B, LongLat C) 
{ 
    return (A.x * B.x + A.y * B.y + A.z * B.z) < (A.x * C.x + A.y * C.y + A.z * C.z); 
} 

और दो अंक के बीच की दूरी पाने के लिए:

float Distance (LongLat A, LongLat B) 
{ 
    // radius is the size of sphere your mapping long/lats onto 
    return radius * acos (A.x * B.x + A.y * B.y + A.z * B.z); 
} 

आप को दूर कर सकता है 'त्रिज्या' शब्द, दूरी को प्रभावी ढंग से सामान्यीकृत करता है।

0

किसी रूप में किसी और ने कहा, आपको यह सुनिश्चित कर रहे हैं कि यह आपके टोंटी है?

मैं एक ऐसी ही आवेदन जहाँ मैं एक साधारण विधि कॉल मानक ट्रिग का उपयोग कर दो अंक के बीच एक दूरी पर लौटने के लिए मैं निर्माण कर रहा हूँ के कुछ निष्पादन परीक्षण किया है। इसके लिए 20,000 कॉल प्रोफाइलिंग आउटपुट के शीर्ष पर इसे सही तरीके से दिखाते हैं, फिर भी कोई रास्ता नहीं है कि मैं इसे तेज़ी से बना सकूं ... यह कॉल की कतरनी # है।

इस मामले में, मैं यह करने के लिए # कॉल को कम करने के ... ऐसा नहीं है कि इस अड़चन है की जरूरत है।

+0

हां, आप त्रिकोणमिति को समाप्त करके इसे तेज़ी से बना सकते हैं। विधि कॉल वास्तव में वास्तव में सस्ते हैं। – mquander

0

2 Lati/longi पदों के बीच की दूरी की गणना के लिए एक अलग एल्गोरिथ्म उपयोग करें, यह बाद से यह केवल करता है 1 क्योंकि फोन और 1 Sqrt कॉल तुम्हारा की तुलना में हल्का हो सकता है।

public static double GetDistanceBetweenTwoPos(double lat1, double long1, double lat2, double long2) 
{ 
    double distance = 0; 
    double x = 0; 
    double y = 0; 

    x = 69.1 * (lat1 - lat2); 
    y = 69.1 * (long1 - long2) * System.Math.Cos(lat2/57.3); 

    //calculation base : Miles 
    distance = System.Math.Sqrt(x * x + y * y); 

    //Distance calculated in Kilometres 
    return distance * 1.609; 
} 
+0

महान होगा यदि आप पृथ्वी के माध्यम से यात्रा कर सकते हैं :) – leppie

0

किसी ने पहले ही ज्ञापन का उल्लेख किया है और यह थोड़ा समान है। यदि आप एक ही बिंदु की तुलना अन्य बिंदुओं से करते हैं तो उस समीकरण के हिस्सों को पूर्वनिर्धारित करना बेहतर होता है।

 
double result = Math.Acos(Math.Sin(lat2rad) * Math.Sin(lat1rad) 
+ Math.Cos(lat2rad) * Math.Cos(lat1rad) * Math.Cos(lon2rad - lon1rad)); 

के बजाय

है:

 
double result = Math.Acos(lat2rad.sin * lat1rad.sin 
+ lat2rad.cos * lat1rad.cos * (lon2rad.cos * lon1rad.cos + lon1rad.sin * lon2rad.sin)); 

और मुझे लगता है कि कि एक ही सूत्र के रूप में किसी और पोस्ट किया गया है क्योंकि समीकरण का हिस्सा है जब आप कोष्ठक का विस्तार गायब हो जाएगा :)