2010-02-12 11 views
5

मैंने हाल ही में एक कार्यक्रम में कुछ गणित कार्यों को अस्वीकार कर दिया है, जैसे NaN (संभवतः कुछ फ़ंक्शन के इनपुट पैराम की जांच न करने के कारण)। समस्या यह है कि यह ट्रैक करना मुश्किल है कि कौन से फ़ंक्शन गलत मान गुजर रहे हैं। इसके परिणामस्वरूप पूरे कोड में त्रुटियों का प्रचार किया जा रहा है और कार्यक्रम को मिनटों या घंटों बाद दुर्घटनाग्रस्त कर दिया जा सकता है।जब कोई गणित ऑपरेशन 'NaN' उत्पन्न करता है तो मैं अपवाद फेंकने के लिए सी # कंपाइलर को कैसे मजबूर करूं?

मुझे आश्चर्य है कि क्या इन दोषपूर्ण परिचालनों को पकड़ने का कोई तरीका है, इस समय किसी भी ऑपरेशन से NaN मान परिणाम (कुछ सी/सी ++ कंपाइलर्स द्वारा फेंक दिया गया 'डिवीजनबीज़र अपवाद' जैसा ही है, अगर मुझे याद है)।

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

पीडी: कृपया आवश्यकता होने पर मेरे प्रश्न को दोबारा टैग करने के लिए स्वतंत्र महसूस करें।

+0

दुर्घटना का कारण क्या है? –

+0

ऐसा लगता है कि यह एक ऐसा मामला है जहां विकास में परीक्षण शामिल करना चाहिए। यदि आपके गणित कार्य बहुत अधिक नहीं हैं तो आप पहले से ही पूर्व में वापस लौटने से बचने के लिए पूर्व-और पोस्टकंडिशन को सही तरीके से परिभाषित करना और उनके लिए परीक्षण लिखना चाहते हैं। – Frank

+0

इस मामले में एक सरणी का उपयोग जहां सूचकांक = (लंबा) NaNvalue, लेकिन यह कुछ और हो सकता था। – Trap

उत्तर

9

अपने कोड इस जवाब जरूरी अस्पष्ट होने जा रहा है देखकर बिना, लेकिन यह ऐसा करने का एक ही रास्ता अपने कार्य से उत्पादन की जाँच करने के लिए है और यदि यह "NaN" उठाते हैं और अपवाद:

if (double.IsNaN(result)) 
{ 
    throw new ArithmeticException(); 
} 

लेकिन साथ अपवाद के बारे में अधिक जानकारी।

अद्यतन

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

डीबग> अपवाद का चयन करें, फिर आम भाषा रनटाइम अपवादों> सिस्टम> सिस्टम का चयन करने के लिए पेड़ का विस्तार करें। एरिथमेटिक अपवाद और "फेंक दिया गया" विकल्प जांचें।

इससे समस्या यह है कि यह हर जगह तोड़ देगा, न केवल आपके कोड में। कम कोड पर स्पष्ट कोड डालकर इस पर हो जाता है।

+0

मुझे क्या करना चाहते हैं पकड़ने के लिए जहां NaN मूल्य उत्पादन किया जाता है पूछ रहा हूँ पूरे आवेदन डिबग करने के लिए बिना है और युगल स्वीकार करने वाली हर विधि पर आपकी तरह एक चेक लिखना। – Trap

+0

+1 यह वही है जो मैं खोज रहा था, अपडेट के लिए बहुत बहुत धन्यवाद :) – Trap

+0

मुझे एक ही समस्या है, लेकिन मुझे जो कीमत मिल रही है वह NaN नहीं बल्कि 'इन्फिनिटी' है। मैंने उपरोक्त वर्णित सिस्टम। एरिथमेटिक अपवाद की जांच की, लेकिन यह मेरी आग नहीं है, जब मेरी varibale 'इन्फिनिटी' पर सेट है। फेंकने वाले विकल्प की जांच करने के लिए कोई अन्य अपवाद है? – Aaginor

3

क्या आपका मतलब है कि आप कुछ सेटिंग या विकल्प की तलाश में हैं ताकि जैसे ही int को NaN मान दिया जाए, तो आपको फेंकने का अपवाद चाहिए? मुझे यकीन है कि ऐसी कोई चीज़ मौजूद नहीं है। checked विकल्प है जो आपको अतिप्रवाह के बारे में चेतावनी देगा, लेकिन यह वही बात नहीं है।

मुझे लगता है कि हाथ से डीबग करने का एकमात्र विकल्प क्रिसफ के सुझाव के तरीके में कोड को संशोधित करना है। उत्पादन कोड में फेंकने पर रोकने के लिए आप फेंकने के आस-पास डाल सकते हैं।

+0

हां, अधिक विशेष रूप से जब कोई मूल्य प्रकार, न केवल int, NaN के साथ असाइन किया जाता है। – Trap

5

मैं अगर यह CLR पर काम करता है पता नहीं है, लेकिन आप _controlfp_s उपयोग कर सकते हैं से चल बिन्दु अपवादों को गति प्रदान करने:

unsigned int _oldState; 
errno_t err = _controlfp_s(&oldState, 0, MCW_EM); 
assert(!err); 

रीसेट करने के लिए:

errno_t err = _controlfp_s(0, _oldState, MCW_EM); 
assert(!err); 
+0

आपने सीआरटी (सी रनटाइम लाइब्रेरी) सहायता पृष्ठ से लिंक किया है, और नीचे यह इंगित करता है कि यह .NET रनटाइम पर लागू नहीं होता है। ओटीओएच, यह उल्लेख करता है कि आप सी फ़ंक्शन को कॉल करने के लिए पी/Invoke का उपयोग कर सकते हैं। – Lucas

+0

मैं एक .NET उपयोगकर्ता नहीं हूं, लेकिन यह मानना ​​उचित लगता है कि सी # सामान्य फ़्लोटिंग पॉइंट निर्देशों का उपयोग करता है, और फिर इसे पकड़ा जाना चाहिए। यदि सी # इन झंडे से गड़बड़ नहीं करता है, तो _EM_INVALID NaNs के लिए ट्रिगर किया जाना चाहिए, और यदि मास्क बंद है तो आपको एक एफपी अपवाद प्राप्त करना चाहिए। –

+0

मुझे यह भी पता है कि इन अपवादों को डिफ़ॉल्ट रूप से वीसी ++ प्रोग्राम में बंद कर दिया गया है, इसलिए यह एक शॉट के लायक हो सकता है। –

0

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

Conditional Debug

यह आपको शर्तों को पूरा होने पर निष्पादन को रोकने की अनुमति देगा, यह अपवाद नहीं हो सकता है लेकिन यह आपको फिर भी मदद कर सकता है।

7

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

क्या अच्छा है कि सी # फ्लोटिंग पॉइंट अपवादों को सक्षम करने के लिए अपना स्वयं का तरीका प्रदान नहीं करता है, फिर भी यह उन्हें पकड़ सकता है (सी ++ के लिए आपको पहले रूपांतरण की आवश्यकता है)।

सी # -code यहाँ है:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Runtime.InteropServices; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
    [System.Runtime.InteropServices.DllImport("msvcrt.dll")] 
    public static extern uint _control87(uint a, uint b); 

    [System.Runtime.InteropServices.DllImport("msvcrt.dll")] 
    public static extern uint _clearfp(); 

    static void Main(string[] args) 
    { 
     float zero = 0.0f - args.Length; // Want 0.0f. Fool compiler... 
     System.Console.WriteLine("zero = " + zero.ToString()); 

     // A NaN which does not throw exception 
     float firstNaN = zero/0.0f; 
     System.Console.WriteLine("firstNaN= " + firstNaN.ToString()); 

     // Now turn on floating-point exceptions 
     uint empty = 0; 
     uint cw = _control87(empty, empty); // Debugger halts on this one and complains about false signature, but continue works. 
     System.Console.WriteLine(cw.ToString()); 
     uint MCW_EM = 0x0008001f; // From float.h 
     uint _EM_INVALID = 0x00000010; // From float.h (invalid corresponds to NaN 
     // See http://www.fortran-2000.com/ArnaudRecipes/CompilerTricks.html#x86_FP 

     cw &= ~(_EM_INVALID); 
     _clearfp(); // Clear floating point error word. 
     _control87(cw, MCW_EM); // Debugger halts on this one and complains about false signature, but continue works.  
     System.Console.WriteLine(cw.ToString()); 

     // A NaN which does throw exception 
     float secondNaN = 0; 
     try 
     { 
     // Put as much code here as you like. 
     // Enable "break when an exception is thrown" in the debugger 
     // for system exceptions to get to the line where it is thrown 
     // before catching it below. 
     secondNaN = zero/0.0f; 
     } 
     catch (System.Exception ex) 
     { 
     _clearfp(); // Clear floating point error word. 
     }  

     System.Console.WriteLine("secondNaN= " + secondNaN.ToString()); 
    } 
    } 
} 

अपवाद मैं मिलता है { "ओवरफ्लो या अंकगणितीय संचालन में अधःप्रवाह।"} {System.Exception System.ArithmeticException}

सुनिश्चित नहीं हैं कि क्यों डीबगर _control87 के हस्ताक्षर के बारे में शिकायत करता है; कोई भी जो उस पर सुधार कर सकता है? "जारी रखें" मेरे लिए ठीक काम करता है, हालांकि।

1

आप एक कक्षा बना सकते हैं जो एक ही ऑपरेशन को एक int (या डबल) के रूप में परिभाषित करता है, जो int (या डबल) को लपेटता है। यह कक्षा प्रत्येक ऑपरेशन के बाद NaN की जांच करेगी (एनबी यह एक साधारण int या डबल से बहुत धीमी होगी)।

अपने कोड में, फिर आप इस नए वर्ग का उपयोग हर जगह एक int (या डबल, क्रमशः) करेंगे। यह तय करने के लिए कि क्या आप int या आपकी कक्षा SafeInt चाहते हैं, तो आप अपने कोड में टेम्पलेट प्रकार TIntegerType का उपयोग भी कर सकते हैं।

कुछ ऐसे लोग हो सकते हैं जो इस दृष्टिकोण को पसंद नहीं करेंगे, लेकिन मैंने इसे कुछ समस्याओं के लिए सभ्य सफलता के साथ उपयोग किया है (उदाहरण के लिए केवल उच्च परिशुद्धता गणित का उपयोग करने की आवश्यकता है और मशीन परिशुद्धता का उपयोग करके)।

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