এটি একটি পুরানো প্রশ্ন, তবে অনেক আনোসার খুব ভাল সংখ্যার জন্য ভাল সঞ্চালন বা ওভারফ্লো করে না। আমি মনে করি ডি নেস্টারভ উত্তরটি সবচেয়ে ভাল: শক্ত, সহজ এবং দ্রুত। আমি কেবল আমার দুটি সেন্ট যুক্ত করতে চাই। আমি দশমিকের সাথে প্রায় খেলেছি এবং উত্স কোডটিও দেখেছি । থেকে public Decimal (int lo, int mid, int hi, bool isNegative, byte scale)
কন্সট্রাকটর ডকুমেন্টেশন ।
দশমিক সংখ্যার বাইনারি উপস্থাপনায় একটি 1-বিট চিহ্ন, একটি 96-বিট পূর্ণসংখ্যার সংখ্যা এবং একটি পূর্ণমান সংখ্যাটি ভাগ করতে ব্যবহৃত স্কেলিং ফ্যাক্টর এবং এর অংশটি দশমিক ভগ্নাংশ নির্দিষ্ট করে। স্কেলিং ফ্যাক্টরটি সুস্পষ্টভাবে 0 থেকে 28 এর মধ্যে কোনও এক্সপোনেন্টকে উত্থাপিত 10 নম্বর।
এটি জানতে পেরে আমার প্রথম পদ্ধতির মধ্যে অন্যটি তৈরি করা হয়েছিল 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
এবং বিট দু'বার পুনরুদ্ধার করা এটি ধীর করে দিচ্ছে। আমার দ্বিতীয় প্রচেষ্টায়, আমি নিজেই ডেসিমাল.গেটবিটস (দশমিক d) পদ্ধতি দ্বারা ফিরে আসা উপাদানগুলিকে চালিত করেছিলাম। ধারণাটি হ'ল উপাদানগুলি প্রয়োজন হিসাবে 10 বার হিসাবে বিভক্ত করা এবং স্কেল হ্রাস করা। কোডটি দশমিকের উপর ভিত্তি করে (ভারীভাবে) ইনটার্নালআউন্ডআউন্ড্রোমজিরো (রেফ ডেসিমাল ডি, ইন্টি ডেসিমাল কাউন্ট) পদ্ধতিতে ।
private const Int32 MaxInt32Scale = 9;
private const int ScaleMask = 0x00FF0000;
private const int SignMask = unchecked((int)0x80000000);
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;
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;
}
আমি কঠোর পারফরম্যান্স পরীক্ষা করিনি, তবে একটি ম্যাকওএস সিয়েরা 10.12.6, 3,06 গিগাহার্টজ ইন্টেল কোর আই 3 প্রসেসর এবং লক্ষ্যবস্তুতে। নেটকোর 2.1 এই পদ্ধতিটি ডি নেস্টারভের চেয়ে অনেক দ্রুত বলে মনে হচ্ছে (যেহেতু আমি সংখ্যা দেব না) , যেমনটি আমি বলেছি, আমার পরীক্ষাগুলি কঠোর নয়)। পারফরম্যান্স লাভ কোড যুক্ত জটিলতার জন্য প্রদান করে কি না তা মূল্যায়নের জন্য যে কেউ এটি প্রয়োগ করে এটি নির্ভর করে।