2009-03-30 16 views
6

मैं एक समारोह getSlope जो 4 युगल मानकों और रिटर्न के रूप में लगता है विभाजित एक और डबल निम्नलिखित तरीके से इस दिए गए मापदंडों का उपयोग कर की गणना:अप्रत्याशित नुकसान जब युगल

double QSweep::getSlope(double a, double b, double c, double d){ 
double slope; 
slope=(d-b)/(c-a); 
return slope; 
} 

समस्या यह है कि जब इस कार्यप्रणाली को कॉल है उदाहरण के लिए तर्क के साथ:

getSlope(2.71156, -1.64161, 2.70413, -1.72219); 

लौटे परिणाम है:

10.8557 

और यह मेरे कंप्यूटेशंस के लिए एक अच्छा परिणाम नहीं है। मैं ढलान समान पैरामीटर के लिए ढाल के लिए मेथेमेटिका और परिणाम का उपयोग कर की गणना की है:

10.8452 

या परिशुद्धता के लिए और अधिक अंकों के साथ:

10.845222072678331. 

परिणाम मेरा कार्यक्रम द्वारा लौटाए अच्छा नहीं है मेरे आगे की गणना में। इसके अलावा, मुझे समझ में नहीं आता कि प्रोग्राम 10.8552220678331 से शुरू होने वाले 10.8557 को कैसे लौटाता है (मान लीजिए कि यह विभाजन के लिए अनुमानित परिणाम है)? मैं अपने विभाजन के लिए अच्छा परिणाम कैसे प्राप्त कर सकता हूं?

अग्रिम धन्यवाद, Madalina


मैं कमांड लाइन का उपयोग कर परिणाम मुद्रित:

std::cout<<slope<<endl; 

हो सकता है कि मेरी मापदंडों शायद, अच्छा नहीं कर रहे हैं के रूप में मैं उन लोगों से पढ़ एक और प्रोग्राम (जो एक ग्राफ की गणना करता है; जब मैं अपने ग्राफ से इस पैरामीटर को पढ़ता हूं तो मैंने उन्हें अपने मूल्य को देखने के लिए प्रदर्शित किया है, लेकिन शायद प्रदर्शित वैक्टरों की गणना की गई गणना के लिए समान आंतरिक परिशुद्धता नहीं है .. मुझे नहीं पता कि यह वास्तव में अजीब है कुछ संख्यात्मक अल त्रुटियां प्रकट होती हैं ..)

जब ग्राफ से मैं अपने पैरामीटर पढ़ रहा हूं तो गणना की जाती है, सी ++ (टेम्पलेट्स के साथ) में लिखी गई कुछ संख्यात्मक पुस्तकालयों का उपयोग किया जाता है। इस गणना के लिए कोई ओपनजीएल का उपयोग नहीं किया जाता है।

धन्यवाद, Madalina

+0

जांचें कि विधि को एएसएम में कैसे संकलित किया गया था। आप डीबगर में ऐसा कर सकते हैं मेरा मानना ​​है (कम से कम दृश्य स्टूडियो में)। –

+0

मेरी विंडोज़ कैल्क गणित के रूप में अच्छा परिणाम देता है: डी – klew

+0

कौन सा कंपाइलर, कौन सा मंच? – peterchen

उत्तर

5

यह हो सकता है कि आप अपनी परियोजना में DirectX या OpenGL का उपयोग करें? यदि ऐसा है तो वे डबल परिशुद्धता को बंद कर सकते हैं और आपको अजीब परिणाम मिलेंगे।

आप परिणाम

std::sqrt(x) * std::sqrt(x) 

के साथ अपने सटीक सेटिंग देख सकते हैं सुंदर एक्स के करीब हो गया है। मैं बहुत समय पहले इस समस्या से मुलाकात की और सभी सूत्रों की जांच करने में एक महीने खर्च किया। लेकिन तब मैं

D3DCREATE_FPU_PRESERVE 
+0

वास्तव में वे ऐसा करने के लिए कैसे जाते हैं? –

+0

प्रत्यक्ष 3 डी प्रारंभ करते समय विकल्प हैं। मुझे नाम याद नहीं है, लेकिन मैंने एक महीने में सभी डिप्लोमा सूत्रों की जांच की और केवल तभी मैंने "sqrt (x) * sqrt (x)" के साथ सरल जांच की और सटीकता तब तक टूट गई जब तक कि मैंने विकल्प बंद नहीं किया। –

+0

VS2008 में मानक Win32 कंसोल ऐप के साथ संकलित होने पर यह सही उत्तर देता है। मैं सहमत हूं और कहूंगा कि यह एक कंपाइलर सेटिंग है। –

3

पाया है समस्या है कि यहाँ (ग-एक) छोटा है, तो बिन्दु आपरेशनों चल में निहित राउंडिंग त्रुटियों इस उदाहरण में बढ़ाया जाता है। एक सामान्य समाधान आपके समीकरण को पुन: कार्य करना है ताकि आप एक छोटी संख्या से विभाजित न हों, मुझे यकीन नहीं है कि आप इसे यहां कैसे करेंगे।

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

नील इस सवाल का उसकी टिप्पणी में सही है, मैं VB में जवाब डबल्स के उपयोग से गणना और mathematica रूप में एक ही जवाब मिला है।

+0

मेरे द्वारा पोस्ट किए गए कोड को देखें - यह समस्या नहीं है –

5

निम्नलिखित कोड:

#include <iostream> 
using namespace std; 

double getSlope(double a, double b, double c, double d){ 
    double slope; 
    slope=(d-b)/(c-a); 
    return slope; 
} 

int main() { 
    double s = getSlope(2.71156, -1.64161, 2.70413, -1.72219); 
    cout << s << endl; 
} 

जी ++ के साथ 10.8452 का एक परिणाम देता है। आप अपने कोड में परिणाम कैसे प्रिंट कर रहे हैं?

+0

इससे कोई फर्क नहीं पड़ता कि आप 10 कैसे प्रिंट करते हैं।845222072678331, यह आपके द्वारा पोस्ट किए गए कोड को देखकर 10.8557 –

1

बेहतर तर्क भी प्रिंट करें। जब आप अनुमान लगाते हैं, दशमलव नोटेशन में पैरामीटर स्थानांतरित करते हैं, तो आप उनमें से प्रत्येक के लिए सटीकता खो देंगे। समस्या यह है कि 1/5 बाइनरी में एक अनंत श्रृंखला है, इसलिए उदा। 0.2 बनता है .001001001 .... इसके अलावा, एक बाइनरी फ्लोट को दशमलव में एक पाठपरक प्रतिनिधित्व में परिवर्तित करते समय decimals कटा हुआ कर रहे हैं।

इसके आगे, कभी-कभी संकलक परिशुद्धता पर गति चुनता है। यह एक दस्तावेज संकलक स्विच होना चाहिए।

0

Patrick के बारे में (सीए) सही मुख्य कारण किया जा रहा है लगता है:

db = -1,72219 - (-1,64161) = -0,08058

सीए = 2, 70,413 - 2,71156 = -0,00743

एस = (डाटाबेस)/(सीए) = -0,08058/-0,00743 = 10,845222

आप बाहर छह अंक परिशुद्धता के साथ शुरू , आपको प्राप्त होने वाले घटाव के माध्यम से 3 और चार अंक में कमी। मेरा सबसे अच्छा अनुमान यह है कि आप additonal परिशुद्धता को खो देते हैं क्योंकि संख्या -0,00743 को डबल में एक्साक्लिटी का प्रतिनिधित्व नहीं किया जा सकता है। एक बड़ा परिशुद्धता के साथ मध्यवर्ती वैरिएबल का उपयोग कर, इस तरह का प्रयास करें:

double QSweep::getSlope(double a, double b, double c, double d) 
{ 
    double slope; 
    long double temp1, temp2; 

    temp1 = (d-b); 
    temp2 = (c-a); 
    slope = temp1/temp2; 

    return slope; 
} 
+0

पर गोल या छंटनी नहीं करेगा? –

+0

आपको शुद्धता के साथ परिशुद्धता (संख्या का प्रतिनिधित्व कैसे किया जाता है) लगता है (मानों पर सहिष्णुता क्या है)। चाहे आप 2.70413 या 2.7041300000 के रूप में डबल निर्दिष्ट करते हैं, परिणामस्वरूप C++ –

+0

@Pete Kirkham में कोई फर्क नहीं पड़ता: उदाहरण के मान का प्रतिनिधित्व करना संभव नहीं है 0.1 * बिल्कुल * एक डबल में, इसलिए इसे एक बड़े पैमाने पर एक चर में संग्रहीत करने से अलग-अलग परिणाम मिल सकते हैं। – Treb

7

मैं डबल के बजाय नाव के साथ की कोशिश की है और मैं एक परिणाम के रूप १०.८४५११० मिलता है। यह अभी भी पागलिना परिणाम से बेहतर दिखता है।

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

मुझे लगता है कि मैं जानता हूँ कि आप इस परिणाम क्यों मिलता है। यदि आपको कहीं से, बी, सी और डी पैरामीटर मिलते हैं और आप इसे प्रिंट करते हैं, तो यह आपको गोलाकार मान देता है। फिर यदि आप इसे मैथमेटिया (या कैल्क;) में डाल देते हैं) तो यह आपको अलग-अलग परिणाम देगा।

मैंने आपके पैरामीटर में से एक को बदलने की कोशिश की। जब मैंने किया:

double c = 2.7041304; 

मुझे 10.845806 मिलते हैं। मैं केवल सी के लिए 0.0000004 जोड़ता हूँ! तो मुझे लगता है कि आपकी "त्रुटियां" त्रुटियां नहीं हैं। बेहतर परिशुद्धता के साथ ए, बी, सी और डी प्रिंट करें और फिर उन्हें गणित में रखें।

2

जो परिणाम आप प्राप्त कर रहे हैं वे 32 बिट अंकगणितीय के अनुरूप हैं। अपने पर्यावरण के बारे में और जानने के बिना, यह सलाह देना संभव नहीं है कि क्या करना है।

दिखाए गए कोड का मानना ​​है कि क्या चल रहा है, यानी आप स्ट्रिंग या फ्लोट में कुछ भी परिवर्तित नहीं कर रहे हैं, तो सी ++ में कोई फिक्स नहीं है। यह आपके द्वारा दिखाए गए कोड के बाहर है, और पर्यावरण पर निर्भर करता है।

जैसा कि पैट्रिक मैकडॉनल्ड्स और ट्रेब ने आपके इनपुट की सटीकता और a-c पर त्रुटि दोनों को लाया, मैंने सोचा कि मैं इसे देख लूंगा। गोल करने वाली त्रुटियों को देखने के लिए एक तकनीक अंतराल अंकगणितीय है, जो ऊपरी और निचली सीमाओं को स्पष्ट करती है जो मूल्य स्पष्ट रूप से दर्शाती है (वे फ़्लोटिंग पॉइंट नंबरों में निहित हैं, और प्रतिनिधित्व की सटीकता के लिए तय की जाती हैं)। प्रत्येक मान को ऊपरी और निचले बाध्य के रूप में मानकर, और प्रतिनिधित्व में त्रुटि द्वारा सीमाओं को विस्तारित करके (लगभग x * 2^-53 डबल मान x के लिए), आपको एक परिणाम मिलता है जो निम्न और ऊपरी सीमाओं को देता है किसी मूल्य की सटीकता, खाते को सबसे खराब केस परिशुद्धता त्रुटियों को ध्यान में रखते हुए।

उदाहरण के लिए, यदि आपके पास [1.0, 2.0] श्रेणी में कोई मान है और इसके द्वारा [0.0, 1.0] श्रेणी में एक मान घटाया गया है, तो परिणाम ऊपर [0.0), ऊपर की सीमा में झूठ बोलना चाहिए (2.0)] न्यूनतम परिणाम 1.0-1.0 है और अधिकतम 2.0-0.0 है। below और above फर्श और छत के बराबर हैं, लेकिन पूर्णांक के बजाय अगले प्रतिनिधित्व योग्य मूल्य के लिए।

अंतराल जो बुरी से बुरी हालत डबल राउंडिंग प्रतिनिधित्व का उपयोग करना:

getSlope(
a = [2.7115599999999995262:2.7115600000000004144], 
b = [-1.6416099999999997916:-1.6416100000000002357], 
c = [2.7041299999999997006:2.7041300000000005888], 
d = [-1.7221899999999998876:-1.7221900000000003317]) 
(d-b) = [-0.080580000000000526206:-0.080579999999999665783] 
(c-a) = [-0.0074300000000007129439:-0.0074299999999989383218] 

to double precision [10.845222072677243474:10.845222072679954195] 
हालांकि c-a

इतना छोटा c या a की तुलना में है, यह अभी भी बड़ी डबल राउंडिंग की तुलना में, इसलिए यदि आप सबसे खराब कल्पना डबल उपयोग कर रहे थे परिशुद्धता गोल करने के बाद, आप उस मान को 12 आंकड़ों के लिए सटीक मान सकते हैं - 10.8452220727। आपने डबल परिशुद्धता से कुछ आंकड़े खो दिए हैं, लेकिन आप अभी भी अपने इनपुट के महत्व से अधिक काम कर रहे हैं।

लेकिन अगर आदानों केवल संख्या महत्वपूर्ण आंकड़े को सही थे, तो बजाय डबल मूल्य २.७१,१५६ +/- ईपीएस होने से, तो इनपुट रेंज [2.711555,2.711565], होगा ताकि आप परिणाम प्राप्त:

getSlope(
a = [2.711555:2.711565], 
b = [-1.641615:-1.641605], 
c = [2.704125:2.704135], 
d = [-1.722195:-1.722185]) 
(d-b) = [-0.08059:-0.08057] 
(c-a) = [-0.00744:-0.00742] 

to specified accuracy [10.82930108:10.86118598] 

जो कि एक विस्तृत श्रृंखला है।

लेकिन गणनाओं में सटीकता को ट्रैक करने के लिए आपको अपने रास्ते से बाहर निकलना होगा, और फ्लोटिंग पॉइंट में अंतर्निहित गोल त्रुटियां इस उदाहरण में महत्वपूर्ण नहीं हैं - यह सबसे खराब मामले डबल परिशुद्धता दौर के साथ 12 आंकड़ों के लिए सटीक है।

दूसरी तरफ, यदि आपके इनपुट केवल 6 आंकड़ों के लिए जाने जाते हैं, तो इससे कोई फर्क नहीं पड़ता कि आपको 10.8557 या 10.8452 मिलते हैं या नहीं। दोनों [10.82930108: 10.861185 9 8] के भीतर हैं।

-1

जबकि प्रोग्रामिंग भाषाओं की सीमाओं के बारे में सीखने के लिए अकादमिक चर्चा चल रही है, तो आपको समस्या का सबसे आसान समाधान मिल सकता है arbitrary precision arithmetic के लिए डेटा संरचना।

इसमें कुछ ओवरहेड होगा, लेकिन आपको काफी गारंटी योग्य सटीकता के साथ कुछ ढूंढने में सक्षम होना चाहिए।

+1

मनमाने ढंग से सटीक अंकगणित की सिफारिश करना, हालांकि स्टैक ओवरव्लो पर लोकप्रिय, फ़्लोटिंग-पॉइंट गणनाओं के बारे में हर प्रश्न का सबसे अच्छा जवाब नहीं है। –

+0

यह सच है, लेकिन फिर भी सबसे सरल काम करने योग्य समाधान। चीजों को करने के लिए अक्सर बेहतर, तेज़ और अधिक जटिल तरीके होते हैं, लेकिन अकेले सादगी के पास सॉफ्टवेयर प्रोजेक्ट में बहुत अधिक मूल्य होता है। – IanGilham