C ++ फ़ंक्शन में न्यूमेरिकल त्रुटि का विश्लेषण


20

मान लीजिए कि मेरे पास एक फ़ंक्शन है जो इनपुट के रूप में कई फ़्लोटिंग-पॉइंट मान (एकल या डबल) लेता है, कुछ संगणना करता है, और आउटपुट फ़्लोटिंग-पॉइंट मान (एकल या डबल भी) पैदा करता है। मैं मुख्य रूप से MSVC 2008 के साथ काम कर रहा हूं, लेकिन साथ ही साथ मिनगीडब्ल्यू / जीसीसी के साथ काम करने की भी योजना है। मैं C ++ में प्रोग्रामिंग कर रहा हूं।

परिणामों में कितनी त्रुटि है, यह प्रोग्रामेटिक रूप से मापने का विशिष्ट तरीका है? यह मानते हुए कि मुझे एक मनमाने ढंग से सटीक पुस्तकालय का उपयोग करने की आवश्यकता है: अगर मुझे गति की परवाह नहीं है तो ऐसी सबसे अच्छी लाइब्रेरी क्या है?

जवाबों:


17

यदि आप अपनी राउंडिंग त्रुटि पर एक अच्छी बाध्यता की तलाश कर रहे हैं, तो आपको आवश्यक रूप से एअरट्रिब्यूट-प्रिसिजन लाइब्रेरी की आवश्यकता नहीं है। आप इसके बजाय रनिंग त्रुटि विश्लेषण का उपयोग कर सकते हैं।

मुझे एक अच्छा ऑनलाइन संदर्भ नहीं मिल रहा था, लेकिन यह सब निक हिघम की पुस्तक "शुद्धता और स्थिरता के संख्यात्मक एल्गोरिदम" की धारा 3.3 में वर्णित है। विचार काफी सरल है:

  1. अपने कोड को फिर से कारक करें ताकि आपके पास प्रत्येक पंक्ति पर एक एकल अंकगणितीय ऑपरेशन का एक असाइनमेंट हो।
  2. प्रत्येक चर के लिए, उदाहरण के लिए x, एक चर बनाते हैं x_errजो xएक स्थिरांक को दिए जाने पर शून्य से प्रारंभ होता है।
  3. प्रत्येक ऑपरेशन के लिए, उदाहरण के लिए z = x * y, z_errफ़्लोटिंग-पॉइंट अंकगणित के मानक मॉडल और परिणामस्वरूप zऔर चलने वाली त्रुटियों का उपयोग करके चर को अपडेट करें x_errऔर y_err
  4. आपके फ़ंक्शन का रिटर्न मान तब भी संबंधित _errमान होना चाहिए । यह आपकी कुल राउंडऑफ़ त्रुटि पर एक डेटा-निर्भर बाउंड है।

मुश्किल हिस्सा चरण 3 है। सबसे सरल अंकगणितीय कार्यों के लिए, आप निम्नलिखित नियमों का उपयोग कर सकते हैं:

  • z = x + y -> z_err = u*abs(z) + x_err + y_err
  • z = x - y -> z_err = u*abs(z) + x_err + y_err
  • z = x * y -> z_err = u*abs(z) + x_err*abs(y) + y_err*abs(x)
  • z = x / y -> z_err = u*abs(z) + (x_err*abs(y) + y_err*abs(x))/y^2
  • z = sqrt(x) -> z_err = u*abs(z) + x_err/(2*abs(z))

जहां u = eps/2इकाई राउंडऑफ है। हां, नियम +और -समान हैं। op(x)लागू किए गए परिणाम के टेलर श्रृंखला विस्तार का उपयोग करके किसी भी अन्य ऑपरेशन के नियमों को आसानी से निकाला जा सकता है op(x + x_err)। या आप गुगली करने की कोशिश कर सकते हैं। या निक हिघम की किताब का उपयोग कर रहे हैं।

एक उदाहरण के रूप में, निम्नलिखित मतलाब / ऑक्टेव कोड पर विचार करें जो हॉर्नर योजना का उपयोग करते हुए aएक बिंदु पर गुणांक में एक बहुपद का मूल्यांकन करता है x:

function s = horner ( a , x )
    s = a(end);
    for k=length(a)-1:-1:1
        s = a(k) + x*s;
    end

पहले चरण के लिए, हम दो ऑपरेशनों को विभाजित करते हैं s = a(k) + x*s:

function s = horner ( a , x )
    s = a(end);
    for k=length(a)-1:-1:1
        z = x*s;
        s = a(k) + z;
    end

हम तब _errचरों का परिचय देते हैं। नोट आदानों कि aऔर xग्रहण कर रहे हैं सटीक होना करने के लिए, लेकिन हम अभी भी रूप में अच्छी तरह उपयोगकर्ता के लिए संगत मानों पारित करने के लिए आवश्यक बना सकते हैं a_errऔर x_err:

function [ s , s_err ] = horner ( a , x )
    s = a(end);
    s_err = 0;
    for k=length(a)-1:-1:1
        z = x*s;
        z_err = ...;
        s = a(k) + z;
        s_err = ...;
    end

अंत में, हम त्रुटि के नियम प्राप्त करने के लिए ऊपर वर्णित नियम लागू करते हैं:

function [ s , s_err ] = horner ( a , x )
    u = eps/2;
    s = a(end);
    s_err = 0;
    for k=length(a)-1:-1:1
        z = x*s;
        z_err = u*abs(z) + s_err*abs(x);
        s = a(k) + z;
        s_err = u*abs(s) + z_err;
    end

ध्यान दें कि चूंकि हमारे पास कोई a_errया नहीं है x_err, उदाहरण के लिए, उन्हें शून्य माना जाता है, संबंधित शब्दों को केवल त्रुटि अभिव्यक्तियों में अनदेखा किया जाता है।

Et voilà! अब हमारे पास एक हॉर्नर स्कीम है जो डेटा-निर्भर त्रुटि अनुमान (नोट: यह त्रुटि पर एक ऊपरी बाध्य है ) परिणाम के साथ देता है।

एक साइड नोट के रूप में, चूंकि आप C ++ का उपयोग कर रहे हैं, आप फ्लोटिंग-पॉइंट वैल्यूज़ के लिए अपनी खुद की क्लास बनाने पर विचार कर सकते हैं, जो _errशब्द के चारों ओर वहन करती है और ऊपर वर्णित इन मानों को अपडेट करने के लिए सभी अंकगणितीय ऑपरेशनों को ओवरलोड करती है। बड़े कोड के लिए, यह आसान, यद्यपि कम्प्यूटेशनल रूप से कम कुशल, मार्ग हो सकता है। ऐसा कहने के बाद, आप इस तरह की कक्षा ऑनलाइन पा सकते हैं। एक त्वरित Google खोज ने मुझे यह लिंक दिया ।

±ux(1±u)


1
इस विश्लेषण के लिए +1, क्योंकि यह दिलचस्प है। मुझे हिगम का काम पसंद है। मुझे चिंता इस बात की है कि एक उपयोगकर्ता को यह लिखने की आवश्यकता है कि हाथ से अतिरिक्त कोड (अर्ध-स्वचालित रूप से अंतराल अंकगणित की तरह) त्रुटि हो सकता है क्योंकि संख्यात्मक कार्यों की संख्या बड़ी हो जाती है।
ज्योफ ऑक्सबेरी

1
@GeoffOxberry: मैं पूरी तरह से जटिलता के मुद्दे से सहमत हूं। बड़े कोड के लिए, मैं दृढ़ता से एक वर्ग / डेटाटाइप लिखने की सलाह दूंगा जो केवल दो बार सही तरीके से लागू करने के लिए डबल्स पर संचालन को ओवरलोड करता है जैसे कि केवल प्रत्येक को सही ढंग से लागू करना है। मुझे काफी आश्चर्य है कि मतलाब / ऑक्टेव के लिए ऐसा कुछ प्रतीत नहीं होता है।
पेड्रो

मुझे यह विश्लेषण पसंद है, लेकिन चूंकि फ़्लोटिंग-पॉइंट में भी त्रुटि शब्दों की गणना की जाती है, क्या फ़्लोटिंग-पॉइंट त्रुटियों के कारण उन त्रुटि शर्तों को लागू नहीं किया जाएगा?
plasmacel

8

मनमाने ढंग से सटीक फ्लोटिंग पॉइंट अंकगणित (और बहुत कुछ) के लिए एक अच्छा पोर्टेबल और ओपन सोर्स लाइब्रेरी विक्टर शौप का NTL है , जो C ++ सोर्स फॉर्म में उपलब्ध है।

निचले स्तर पर GNU मल्टीपल प्रिसिजन (GMP) बिग्नम लाइब्रेरी है , जो एक ओपन सोर्स पैकेज भी है।

NTL का उपयोग GMP के साथ किया जा सकता है तेज प्रदर्शन की आवश्यकता है, लेकिन NTL अपने स्वयं के आधार रूट प्रदान करता है जो निश्चित रूप से उपयोग करने योग्य हैं यदि आप "गति की परवाह नहीं करते हैं"। GMP का दावा है कि यह "सबसे तेजी से आने वाली लाइब्रेरी" है। GMP मोटे तौर पर C में लिखा गया है, लेकिन इसमें C ++ इंटरफ़ेस है।

जोड़ा गया: जबकि अंतराल अंकगणित एक स्वचालित तरीके से सटीक उत्तर पर ऊपरी और निचले सीमा दे सकता है, यह "मानक" सटीक गणना में त्रुटि को सही ढंग से नहीं मापता है क्योंकि अंतराल आकार आमतौर पर प्रत्येक ऑपरेशन के साथ बढ़ता है (या तो किसी रिश्तेदार में) पूर्ण त्रुटि भावना)।

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

एकल और दोहरे सटीक संगणना की तुलना करके बिंदु को चित्रित किया जा सकता है। ध्यान दें कि C ++ इंटरमीडिएट अभिव्यक्तियों में हमेशा (कम से कम) डबल परिशुद्धता में गणना की जाती है, इसलिए यदि हम यह वर्णन करना चाहते हैं कि "शुद्ध" एकल परिशुद्धता में एक गणना क्या होगी, तो हमें एकल सटीकता में मध्यवर्ती मूल्यों को संग्रहीत करने की आवश्यकता है।

सी कोड स्निपेट

    float fa,fb;
    double da,db,err;
    fa = 4.0;
    fb = 3.0;
    fa = fa/fb;
    fa -= 1.0;

    da = 4.0;
    db = 3.0;
    da = da/db;
    da -= 1.0;

    err = fa - da;
    printf("Single precision error wrt double precision value\n");
    printf("Error in getting 1/3rd is %e\n",err);
    return 0;

ऊपर से उत्पादन (Cygwin / MinGW32 GCC उपकरण श्रृंखला):

Single precision error wrt double precision value
Error in getting 1/3rd is 3.973643e-08

इस प्रकार त्रुटि इस बारे में है कि कोई एकल परिशुद्धता के लिए 1 / 3rd को गोल करने में क्या उम्मीद करता है। त्रुटि को सही करने में दशमलव स्थानों के एक जोड़े से अधिक प्राप्त करने के बारे में एक (मुझे संदेह होगा) देखभाल नहीं होगी , क्योंकि त्रुटि का माप परिमाण के लिए है और सटीकता के लिए नहीं।


आपका दृष्टिकोण निश्चित रूप से गणितीय ध्वनि है। मुझे लगता है कि ट्रेडऑफ कठोर है; जो लोग त्रुटि के बारे में पांडित्यपूर्ण हैं वे अंतराल अंकगणित की कठोरता को इंगित करेंगे, लेकिन मुझे संदेह है कि कई अनुप्रयोगों में, अतिरिक्त परिशुद्धता के लिए कंप्यूटिंग पर्याप्त होगा, और परिणामी त्रुटि अनुमानों की संभावना कम होगी, जैसा कि आप बताते हैं।
ज्यॉफ ऑक्सबेरी

यह वह दृष्टिकोण है जिसकी मैं कल्पना कर रहा था कि मैं इसका उपयोग करूंगा। मैं इनमें से कुछ अलग तकनीकों को देखने की कोशिश कर सकता हूं जो मेरे आवेदन के लिए सबसे उपयुक्त हैं। कोड उदाहरण अद्यतन बहुत सराहना की है!
user_123abc

7

जीएमपी (यानी, जीएनयू मल्टीपल प्रिसिजन लाइब्रेरी) सबसे अच्छी मनमानी सटीक लाइब्रेरी है जिसे मैं जानता हूं।

मैं मनमाने ढंग से फ्लोटिंग पॉइंट फ़ंक्शन के परिणामों में त्रुटि को मापने के लिए किसी भी प्रोग्रामेटिक तरीके के बारे में नहीं जानता। एक चीज़ जो आप आज़मा सकते हैं, वह है एक फ़ंक्शन के अंतराल के विस्तार की गणना करना जो अंतराल अंकगणित का उपयोग करता है । C ++ में, आपको अंतराल एक्सटेंशन की गणना करने के लिए किसी प्रकार की लाइब्रेरी का उपयोग करना होगा; ऐसी ही एक लाइब्रेरी है बूस्ट इंटरवल अरिथमेटिक लाइब्रेरी। मूल रूप से, त्रुटि को मापने के लिए, आप अपने फ़ंक्शन अंतराल के तर्क के रूप में आपूर्ति करेंगे, जिसमें 2 गुना यूनिट राउंडऑफ (मोटे तौर पर) की चौड़ाई होती है, जो ब्याज के मूल्यों पर केंद्रित है, और फिर आपका आउटपुट अंतराल का एक संग्रह होगा, चौड़ाई जो आपको त्रुटि के कुछ रूढ़िवादी अनुमान देगा। इस दृष्टिकोण के साथ एक कठिनाई यह है कि इस फैशन में इस्तेमाल किया गया अंतराल अंकगणित महत्वपूर्ण मात्रा में त्रुटि को पार कर सकता है, लेकिन यह दृष्टिकोण सबसे "प्रोग्रामेटिक" है जिसे मैं सोच सकता हूं।


आह, मैंने आपके जवाब में उल्लेखित अंतराल अंकगणित पर ध्यान दिया ... अपवोटेड!
अली

2
रिचर्ड हैरिस ने फ्लोटिंग पॉइंट ब्लूज़ के बारे में ACCU जर्नल ओवरलोड में लेखों की एक उत्कृष्ट श्रृंखला लिखी । के बारे में अपने लेख अंतराल गणित में है अधिभार 103 ( पीडीएफ , p19-24)।
मार्क बूथ

6

अंतराल विश्लेषण द्वारा कठोर और स्वचालित त्रुटि अनुमान प्राप्त किया जा सकता है । आप संख्याओं के बजाय अंतराल के साथ काम करते हैं। उदाहरण के अलावा:

[a,b] + [c,d] = [min(a+c, a+d, b+c, b+d), max (a+c, a+d, b+c, b+d)] = [a+c, b+d]

राउंड-ऑफ को भी सख्ती से नियंत्रित किया जा सकता है, राउंडेड अंतराल अंकगणित देखें ।

जब तक आपके इनपुट में संकीर्ण अंतराल होते हैं, अनुमान ठीक होते हैं और गणना करने के लिए फली सस्ते होते हैं। दुर्भाग्य से, त्रुटि को अक्सर कम कर दिया जाता है, निर्भरता समस्या देखें ।

मैं किसी भी मनमानी परिशुद्धता अंतराल अंकगणित पुस्तकालय के बारे में नहीं जानता।

यह आपकी समस्या पर निर्भर करता है कि अंतराल अंकगणित आपकी आवश्यकताओं की पूर्ति कर सकता है या नहीं।


4

जीएनयू MPFR पुस्तकालय उच्च सटीकता है कि उनके मुख्य लक्ष्य बिंदुओं में से एक के रूप में (सभी कार्यों के लिए विशेष रूप से, सही राउंडिंग है, जो के रूप में आसान के रूप में यह लग रहा है नहीं है में) एक मनमाना परिशुद्धता नाव पुस्तकालय है। यह हुड के तहत GNU MP का उपयोग करता है। इसमें MPFI नामक एक एक्सटेंशन है जो अंतराल अंकगणित करता है, जो - जैसा कि ज्यॉफ का जवाब बताता है - सत्यापन उद्देश्यों के लिए काम में आ सकता है: जब तक परिणामी अंतराल छोटे सीमा के भीतर नहीं आती तब तक कार्यशील सटीकता में वृद्धि करते रहें।

यह हमेशा काम नहीं करेगा, हालांकि; विशेष रूप से यह जरूरी नहीं है कि यदि आप संख्यात्मक एकीकरण जैसा कुछ कर रहे हैं, जहां हर कदम एक "त्रुटि" गोलाई की समस्याओं से स्वतंत्र है। उस स्थिति में, COZY अनन्तता जैसे एक विशेष पैकेज का प्रयास करें जो एकीकरण त्रुटि को बाध्य करने के लिए विशिष्ट एल्गोरिदम का उपयोग करता है (और अंतराल के बजाय तथाकथित टेलर मॉडल का उपयोग करके)।


मैं सहमत हूँ; संख्यात्मक एकीकरण निश्चित रूप से एक ऐसा मामला है जहां भोले अंतराल अंकगणित गड़बड़ा सकते हैं। हालांकि, यहां तक ​​कि टेलर मॉडल अंतराल अंकगणित का उपयोग करते हैं। मैं Makino और Berz के काम से परिचित हूं, और मुझे विश्वास है कि वे RE मूर के अर्थ में टेलर मॉडल का उपयोग करते हैं, हालांकि वे चाल को भी शामिल करते हैं जिसे वे "अंतर बीजगणित" कहते हैं।
ज्योफ ऑक्सबेरी

@GeoffOxberry: हाँ - मुझे लगता है कि यह अंतर बीजगणित एकीकरण कदम में त्रुटि पर बाध्य होने के लिए सामान है।
एरिक पी।

0

मुझे बताया गया है कि यदि आप Visual Studio के साथ काम कर रहे हैं, तो MPIR एक अच्छी लाइब्रेरी है:

http://mpir.org/


SciComp.SE में आपका स्वागत है! क्या आप इस बात पर कुछ विवरण जोड़ सकते हैं कि इस लाइब्रेरी का उपयोग फ्लोटिंग पॉइंट कंप्यूटेशन की त्रुटि को मापने के लिए कैसे किया जा सकता है?
क्रिश्चियन क्लैसन

मै कोशिश करूँगा; मैंने वास्तव में अभी तक अपने कंप्यूटर पर अभी तक एमपीआईआर स्थापित नहीं किया है! मैंने GMP और MPFR की स्थापना की है।
fishermanhat
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.