Burn_LEGION की पोस्ट में दशमलव बिंदु दिखाए जाने के बाद अंकों की संख्या खोजने के लिए सबसे अच्छे समाधानों में से एक है ।
यहाँ मैं STSdb फोरम लेख के कुछ हिस्सों का उपयोग कर रहा हूँ: दशमलव बिंदु के बाद अंकों की संख्या ।
MSDN में हम निम्नलिखित स्पष्टीकरण पढ़ सकते हैं:
"एक दशमलव संख्या एक फ़्लोटिंग-पॉइंट मान है जिसमें एक चिन्ह, एक संख्यात्मक मान होता है, जहाँ मूल्य का प्रत्येक अंक 0 से 9 तक होता है, और एक स्केलिंग कारक जो एक अस्थायी दशमलव बिंदु की स्थिति को इंगित करता है जो अभिन्न और आंशिक को अलग करता है संख्यात्मक मान के कुछ हिस्से। "
और भी:
"दशमलव मान के द्विआधारी प्रतिनिधित्व में 1-बिट चिन्ह, 96-बिट पूर्णांक संख्या और 96-बिट पूर्णांक को विभाजित करने के लिए उपयोग किया जाने वाला स्केलिंग कारक होता है और निर्दिष्ट करता है कि इसका कौन सा भाग दशमलव अंश है। स्केलिंग कारक। अनुमानित रूप से संख्या 10, जो 0 से 28 तक के एक घातांक तक बढ़ा दी गई है। "
आंतरिक स्तर पर दशमलव मान चार पूर्णांक मानों द्वारा दर्शाया जाता है।
आंतरिक प्रतिनिधित्व प्राप्त करने के लिए सार्वजनिक रूप से उपलब्ध GetBits फ़ंक्शन है। फ़ंक्शन एक int [] सरणी देता है:
[__DynamicallyInvokable]
public static int[] GetBits(decimal d)
{
return new int[] { d.lo, d.mid, d.hi, d.flags };
}
लौटे सरणी के चौथे तत्व में एक स्केल फैक्टर और एक चिन्ह होता है। और जैसा कि MSDN कहता है कि स्केलिंग फैक्टर संख्या 10 है, जो 0 से 28 तक के एक घातांक तक बढ़ा है। ठीक यही हमें चाहिए।
इस प्रकार, उपरोक्त सभी जांचों के आधार पर हम अपनी विधि का निर्माण कर सकते हैं:
private const int SIGN_MASK = ~Int32.MinValue;
public static int GetDigits4(decimal value)
{
return (Decimal.GetBits(value)[3] & SIGN_MASK) >> 16;
}
यहां साइन को नजरअंदाज करने के लिए एक SIGN_MASK का उपयोग किया जाता है। तार्किक होने के बाद और हमने वास्तविक स्केल फैक्टर प्राप्त करने के लिए 16 बिट्स के साथ परिणाम को दाईं ओर स्थानांतरित कर दिया है। यह मान, अंततः दशमलव बिंदु के बाद अंकों की संख्या को इंगित करता है।
ध्यान दें कि यहाँ MSDN भी कहता है कि स्केलिंग फैक्टर किसी भी अनुगामी शून्य को दशमलव संख्या में संरक्षित करता है। ट्रेलिंग शून्य अंकगणितीय या तुलनात्मक संचालन में एक दशमलव संख्या के मूल्य को प्रभावित नहीं करते हैं। हालाँकि, ट्रेसिंग विधि द्वारा ट्रेलिंग जीरो को प्रकट किया जा सकता है यदि एक उपयुक्त प्रारूप स्ट्रिंग लागू किया जाता है।
यह समाधान सबसे अच्छा लगता है, लेकिन रुको, और भी बहुत कुछ है। C # में निजी विधियों का उपयोग करके हम झंडे के क्षेत्र तक सीधी पहुंच बनाने और अंतर सरणी के निर्माण से बचने के लिए अभिव्यक्ति का उपयोग कर सकते हैं:
public delegate int GetDigitsDelegate(ref Decimal value);
public class DecimalHelper
{
public static readonly DecimalHelper Instance = new DecimalHelper();
public readonly GetDigitsDelegate GetDigits;
public readonly Expression<GetDigitsDelegate> GetDigitsLambda;
public DecimalHelper()
{
GetDigitsLambda = CreateGetDigitsMethod();
GetDigits = GetDigitsLambda.Compile();
}
private Expression<GetDigitsDelegate> CreateGetDigitsMethod()
{
var value = Expression.Parameter(typeof(Decimal).MakeByRefType(), "value");
var digits = Expression.RightShift(
Expression.And(Expression.Field(value, "flags"), Expression.Constant(~Int32.MinValue, typeof(int))),
Expression.Constant(16, typeof(int)));
return Expression.Lambda<GetDigitsDelegate>(digits, value);
}
}
यह संकलित कोड GetDigits फ़ील्ड को सौंपा गया है। ध्यान दें कि फ़ंक्शन दशमलव मान को रेफरी के रूप में प्राप्त करता है, इसलिए कोई वास्तविक नकल नहीं की जाती है - केवल मूल्य के लिए एक संदर्भ। DecimalHelper से GetDigits फ़ंक्शन का उपयोग करना आसान है:
decimal value = 3.14159m;
int digits = DecimalHelper.Instance.GetDigits(ref value);
दशमलव मानों के लिए दशमलव बिंदु के बाद अंकों की संख्या प्राप्त करने के लिए यह सबसे तेज़ संभव विधि है।