यह एक पुराना सवाल है, लेकिन कई खिलाड़ी बड़ी संख्या में अच्छा प्रदर्शन नहीं कर पाते हैं। मुझे लगता है कि डी। नेस्टरोव का उत्तर सबसे अच्छा है: मजबूत, सरल और तेज। मैं सिर्फ अपने दो सेंट जोड़ना चाहता हूं। मैंने दशमलव के साथ खेला और स्रोत कोड भी देखा । से public Decimal (int lo, int mid, int hi, bool isNegative, byte scale)
निर्माता प्रलेखन ।
दशमलव संख्या के द्विआधारी प्रतिनिधित्व में 1-बिट संकेत, 96-बिट पूर्णांक संख्या और पूर्णांक संख्या को विभाजित करने के लिए उपयोग किया जाने वाला स्केलिंग कारक होता है और यह निर्दिष्ट करता है कि इसका कौन सा भाग दशमलव अंश है। स्केलिंग फैक्टर अनुमानित संख्या 10 है जो एक एक्सपोनेंट से 0 से 28 तक है।
यह जानकर, मेरा पहला दृष्टिकोण एक और बनाना था decimal
जिसका पैमाना उन दशमलवों से मेल खाता है जिन्हें मैं त्यागना चाहता था, फिर इसे काटकर अंत में वांछित पैमाने के साथ एक दशमलव बनाएं।
private const int ScaleMask = 0x00FF0000;
public static Decimal Truncate(decimal target, byte decimalPlaces)
{
var bits = Decimal.GetBits(target);
var scale = (byte)((bits[3] & (ScaleMask)) >> 16);
if (scale <= decimalPlaces)
return target;
var temporalDecimal = new Decimal(bits[0], bits[1], bits[2], target < 0, (byte)(scale - decimalPlaces));
temporalDecimal = Math.Truncate(temporalDecimal);
bits = Decimal.GetBits(temporalDecimal);
return new Decimal(bits[0], bits[1], bits[2], target < 0, decimalPlaces);
}
यह विधि डी। नेस्टरोव की तुलना में तेज़ नहीं है और यह अधिक जटिल है, इसलिए मैंने थोड़ा और अधिक खेला। मेरा अनुमान है कि एक परिचित बनाने decimal
और दो बार बिट्स को पुनर्प्राप्त करने से यह धीमा हो रहा है। अपने दूसरे प्रयास में, मैंने Decimal.GetBits (Decimal d) विधि द्वारा वापस लौटाए गए घटकों में हेरफेर किया । विचार 10 से घटकों को आवश्यकतानुसार विभाजित करने और पैमाने को कम करने का है। कोड Decimal.InternalRoundFromZero (Ref Decimal d, int दशमलव) पद्धति पर आधारित (भारी) है ।
private const Int32 MaxInt32Scale = 9;
private const int ScaleMask = 0x00FF0000;
private const int SignMask = unchecked((int)0x80000000);
// Fast access for 10^n where n is 0-9
private static UInt32[] Powers10 = new UInt32[] {
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000
};
public static Decimal Truncate(decimal target, byte decimalPlaces)
{
var bits = Decimal.GetBits(target);
int lo = bits[0];
int mid = bits[1];
int hi = bits[2];
int flags = bits[3];
var scale = (byte)((flags & (ScaleMask)) >> 16);
int scaleDifference = scale - decimalPlaces;
if (scaleDifference <= 0)
return target;
// Divide the value by 10^scaleDifference
UInt32 lastDivisor;
do
{
Int32 diffChunk = (scaleDifference > MaxInt32Scale) ? MaxInt32Scale : scaleDifference;
lastDivisor = Powers10[diffChunk];
InternalDivRemUInt32(ref lo, ref mid, ref hi, lastDivisor);
scaleDifference -= diffChunk;
} while (scaleDifference > 0);
return new Decimal(lo, mid, hi, (flags & SignMask)!=0, decimalPlaces);
}
private static UInt32 InternalDivRemUInt32(ref int lo, ref int mid, ref int hi, UInt32 divisor)
{
UInt32 remainder = 0;
UInt64 n;
if (hi != 0)
{
n = ((UInt32)hi);
hi = (Int32)((UInt32)(n / divisor));
remainder = (UInt32)(n % divisor);
}
if (mid != 0 || remainder != 0)
{
n = ((UInt64)remainder << 32) | (UInt32)mid;
mid = (Int32)((UInt32)(n / divisor));
remainder = (UInt32)(n % divisor);
}
if (lo != 0 || remainder != 0)
{
n = ((UInt64)remainder << 32) | (UInt32)lo;
lo = (Int32)((UInt32)(n / divisor));
remainder = (UInt32)(n % divisor);
}
return remainder;
}
मैंने कठोर प्रदर्शन परीक्षण नहीं किए हैं, लेकिन MacOS Sierra 10.12.6, 3,06 GHz Intel Core i3 प्रोसेसर और लक्ष्यीकरण .NetCore 2.1 पर यह विधि D. Nesterov's की तुलना में बहुत तेज़ प्रतीत होती है (क्योंकि मैं नंबर नहीं दूंगा। , जैसा कि मैंने उल्लेख किया है, मेरे परीक्षण कठोर नहीं हैं)। यह इस पर निर्भर करता है कि प्रदर्शन कोड लाभ जटिलता के लिए भुगतान करते हैं या नहीं, इसका मूल्यांकन करने के लिए इसे कौन लागू करता है।