2010-02-12 11 views
18

मुझे लगता है कि, सी # में, decimal को गोल करके, डिफ़ॉल्ट रूप से MidpointRounding.ToEven का उपयोग करता है। यह उम्मीद की जाती है, और सी # spec dictates क्या है। हालांकि, यह देखते हुए निम्नलिखित:.NET दशमलव.ToString (स्ट्रिंग) शून्य से दूर क्यों है, स्पष्ट रूप से भाषा spec के साथ असंगत है?

  • एक decimal dVal
  • एक प्रारूप string sFmt है कि, जब dVal.ToString(sFmt) करने के लिए पारित किया है, dVal

का पूर्ण बनाया गया संस्करण से युक्त एक स्ट्रिंग में परिणाम होगा ... यह है स्पष्ट है कि decimal.ToString(string)MidpointRounding.AwayFromZero का उपयोग करके एक मान गोल किया गया है। यह सी # spec का प्रत्यक्ष विरोधाभास प्रतीत होता है।

मेरा प्रश्न यह है: क्या ऐसा कोई अच्छा कारण है? या यह भाषा में सिर्फ एक असंगतता है?

नीचे, संदर्भ के लिए, मैं कुछ कोड है कि गोलाई आपरेशन के परिणाम और decimal.ToString(string) आपरेशन के परिणाम, decimal मूल्यों की एक सरणी में हर मूल्य पर प्रत्येक के वर्गीकरण सांत्वना देने लिखते शामिल किया है। वास्तविक आउटपुट एम्बेडेड हैं। इसके बाद, मैंने decimal प्रकार पर सी # भाषा विशिष्टता अनुभाग से प्रासंगिक अनुच्छेद शामिल किया है।

उदाहरण कोड:

static void Main(string[] args) 
{ 
    decimal[] dArr = new decimal[] { 12.345m, 12.355m }; 

    OutputBaseValues(dArr); 
    // Base values: 
    // d[0] = 12.345 
    // d[1] = 12.355 

    OutputRoundedValues(dArr); 
    // Rounding with default MidpointRounding: 
    // Math.Round(12.345, 2) => 12.34 
    // Math.Round(12.355, 2) => 12.36 
    // decimal.Round(12.345, 2) => 12.34 
    // decimal.Round(12.355, 2) => 12.36 

    OutputRoundedValues(dArr, MidpointRounding.ToEven); 
    // Rounding with mr = MidpointRounding.ToEven: 
    // Math.Round(12.345, 2, mr) => 12.34 
    // Math.Round(12.355, 2, mr) => 12.36 
    // decimal.Round(12.345, 2, mr) => 12.34 
    // decimal.Round(12.355, 2, mr) => 12.36 

    OutputRoundedValues(dArr, MidpointRounding.AwayFromZero); 
    // Rounding with mr = MidpointRounding.AwayFromZero: 
    // Math.Round(12.345, 2, mr) => 12.35 
    // Math.Round(12.355, 2, mr) => 12.36 
    // decimal.Round(12.345, 2, mr) => 12.35 
    // decimal.Round(12.355, 2, mr) => 12.36 

    OutputToStringFormatted(dArr, "N2"); 
    // decimal.ToString("N2"): 
    // 12.345.ToString("N2") => 12.35 
    // 12.355.ToString("N2") => 12.36 

    OutputToStringFormatted(dArr, "F2"); 
    // decimal.ToString("F2"): 
    // 12.345.ToString("F2") => 12.35 
    // 12.355.ToString("F2") => 12.36 

    OutputToStringFormatted(dArr, "###.##"); 
    // decimal.ToString("###.##"): 
    // 12.345.ToString("###.##") => 12.35 
    // 12.355.ToString("###.##") => 12.36 

    Console.ReadKey(); 
} 

private static void OutputBaseValues(decimal[] dArr) 
{ 
    Console.WriteLine("Base values:"); 
    for (int i = 0; i < dArr.Length; i++) Console.WriteLine("d[{0}] = {1}", i, dArr[i]); 
    Console.WriteLine(); 
} 

private static void OutputRoundedValues(decimal[] dArr) 
{ 
    Console.WriteLine("Rounding with default MidpointRounding:"); 
    foreach (decimal d in dArr) Console.WriteLine("Math.Round({0}, 2) => {1}", d, Math.Round(d, 2)); 
    foreach (decimal d in dArr) Console.WriteLine("decimal.Round({0}, 2) => {1}", d, decimal.Round(d, 2)); 
    Console.WriteLine(); 
} 

private static void OutputRoundedValues(decimal[] dArr, MidpointRounding mr) 
{ 
    Console.WriteLine("Rounding with mr = MidpointRounding.{0}:", mr); 
    foreach (decimal d in dArr) Console.WriteLine("Math.Round({0}, 2, mr) => {1}", d, Math.Round(d, 2, mr)); 
    foreach (decimal d in dArr) Console.WriteLine("decimal.Round({0}, 2, mr) => {1}", d, decimal.Round(d, 2, mr)); 
    Console.WriteLine(); 
} 

private static void OutputToStringFormatted(decimal[] dArr, string format) 
{ 
    Console.WriteLine("decimal.ToString(\"{0}\"):", format); 
    foreach (decimal d in dArr) Console.WriteLine("{0}.ToString(\"{1}\") => {2}", d, format, d.ToString(format)); 
    Console.WriteLine(); 
} 


सी # भाषा विशिष्टता ("दशमलव प्रकार") की धारा 4.1.7 से पैरा (पूर्ण कल्पना here (.doc प्राप्त)):

टाइप दशमलव के मानों पर एक ऑपरेशन का परिणाम वह है जो सटीक परिणाम (प्रत्येक ऑपरेटर के लिए परिभाषित स्केल को संरक्षित करना) की गणना करने के बाद होता है और फिर प्रतिनिधित्व को फिट करने के लिए गोल करता है। परिणाम निकटतम प्रतिनिधित्व योग्य मूल्य के लिए गोल किए जाते हैं, और, जब परिणाम दो प्रतिनिधित्व योग्य मानों के बराबर होता है, उस मूल्य के लिए जिसमें कम से कम महत्वपूर्ण अंक स्थिति में भी संख्या होती है (इसे "बैंकर राउंडिंग" के रूप में जाना जाता है)। शून्य परिणाम में हमेशा 0 का संकेत होता है और 0.

यह देखना आसान है कि वे इस पैराग्राफ में ToString(string) पर विचार नहीं कर रहे हैं, लेकिन मुझे लगता है कि यह इस विवरण में फिट बैठता है।

+2

यह संभव है कि आपको यह समझना चाहिए कि सी # में 'ToString (string)' विधि नहीं है। .NET Framework करता है। मुझे यकीन नहीं है कि .NET Framework किसी भी विशेष प्रोग्रामिंग भाषा के नियमों का पालन करने के लिए बाध्य है। –

उत्तर

1

ToString() Culture के अनुसार डिफ़ॉल्ट प्रारूपों के अनुसार, विनिर्देश के एक कम्प्यूटेशनल पहलू के अनुसार नहीं। स्पष्ट रूप से Culture आपके लोकेल के लिए (और अधिकतर, इसे देखने से) शून्य से दूर घूमने की अपेक्षा करता है।

आप अलग व्यवहार चाहते हैं, आप में ToString()

को मैं ऊपर सोचा एक IFormatProvider पारित कर सकते हैं, लेकिन आप सही कर रहे हैं कि यह हमेशा शून्य कोई फर्क नहीं पड़ता Culture से दूर दौर। सबूत के लिए टिप्पणियों में लिंक की जांच करें।

+0

मैंने हाल ही में यह भी सोचा था, लेकिन संकेत मिलने के बाद मैं वास्तव में CultureInfo या NumberFormatInfo में कहीं भी नहीं ढूंढ सका जहां गोलिंग निर्दिष्ट या निर्धारित है। क्या आप यह इंगित कर सकते हैं कि यह वास्तव में कहां होता है? –

+0

मैं नहीं कर सकता, और ऐसा लगता है कि मैं शायद गलत हूं। * लाइसेंस चेतावनी: लिंक के बाद सीएलआर स्रोत * ऐसा लगता है कि http://www.koders.com/cpp/fid03737280F05F3996789AC863BDE66ACB337C1E9B.aspx?s=NumberToStringFormat#L1457 NumberToStringFormat कॉल http://www.koders.com/cpp/fid03737280F05F3996789AC863BDE66ACB337C1E9B.aspx एस = नंबर टॉस्ट्रिंगफॉर्मैट # एल 838 राउंड नम्बर जो हमेशा शून्य से दूर हो जाता है। –

+1

चूंकि सबसे अच्छा जवाब यह प्रतीत होता है कि यह भाषा में एक असंगतता है, इसलिए मैं इस प्रतिक्रिया को उत्तर के रूप में चिह्नित करने जा रहा हूं। धन्यवाद! – stack

1

सबसे अधिक संभावना है क्योंकि यह मुद्रा से निपटने का मानक तरीका है। दशमलव के निर्माण के लिए प्रोत्साहन यह था कि फ़्लोटिंग पॉइंट मुद्रा मूल्यों से निपटने का एक खराब काम करता है, इसलिए आप गणितीय शुद्धता की तुलना में लेखांकन मानकों के साथ अधिक गठबंधन करने के नियमों की अपेक्षा करेंगे।

+0

टूट गए हैं मुझे यकीन नहीं है कि मैं आपके उत्तर को समझता हूं क्योंकि यह प्रश्न से संबंधित है। – stack

6

यदि आप सावधानी से पढ़ते हैं, तो आप देखेंगे कि यहां कोई असंगतता नहीं है।

यहाँ कि पैरा फिर से है, महत्वपूर्ण भागों के साथ प्रकाश डाला:

दशमलव प्रकार के मूल्यों पर एक आपरेशन का परिणाम है कि जो एक सटीक परिणाम की गणना (पैमाने संरक्षण, के रूप में के लिए परिभाषित से परिणाम होता है प्रत्येक ऑपरेटर) और उसके बाद प्रतिनिधित्व फिट करने के लिए गोल। परिणाम के निकट निकट प्रतिनिधित्व मूल्य पर गोल किए जाते हैं, और जब परिणाम दो प्रतिनिधित्व योग्य मानों के बराबर होता है, उस मूल्य के लिए जिसमें कम से कम महत्वपूर्ण अंक स्थिति में भी संख्या होती है (इसे "बैंकर राउंडिंग" के रूप में जाना जाता है)। एक शून्य परिणाम हमेशा 0 का एक संकेत और 0.

कल्पना के इस भाग को decimal पर अंकगणितीय आपरेशनों पर लागू होता है के पैमाने है; स्ट्रिंग स्वरूपण उनमें से एक नहीं है, और यहां तक ​​कि यदि यह भी था, तो इससे कोई फर्क नहीं पड़ता क्योंकि आपके उदाहरण कम परिशुद्धता हैं।

व्यवहार कल्पना में निर्दिष्ट प्रदर्शित करने के लिए निम्न कोड का उपयोग करें:

Decimal d1 = 0.00000000000000000000000000090m; 
Decimal d2 = 0.00000000000000000000000000110m; 

// Prints: 0.0000000000000000000000000004 (rounds down) 
Console.WriteLine(d1/2); 

// Prints: 0.0000000000000000000000000006 (rounds up) 
Console.WriteLine(d2/2); 

है बस इतना ही कल्पना के बारे में बात कर रहा है। यदि कुछ गणना का नतीजा decimal प्रकार (2 9 अंक) की सटीक सीमा से अधिक होगा, तो बैंकर के गोलाकार का उपयोग यह निर्धारित करने के लिए किया जाता है कि परिणाम क्या होगा।

+0

"यह देखना आसान है कि वे इस पैराग्राफ में ToString (स्ट्रिंग) पर विचार नहीं कर रहे हैं, लेकिन मुझे लगता है कि यह इस विवरण में फिट बैठता है।" – stack

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