সংস্কৃতি নির্বিশেষে দশমিক মান দশমিক স্থানের সংখ্যা সন্ধান করুন


91

আমি ভাবছি যে দশমিক মান (একটি অন্তর্নিহিত হিসাবে) এর দশমিক স্থানের সংখ্যাটি বের করার কোনও সংক্ষিপ্ত এবং সঠিক উপায় আছে যা বিভিন্ন সংস্কৃতির তথ্য জুড়ে ব্যবহার করা নিরাপদ হবে?

উদাহরণস্বরূপ:
19.0 এর 1 টি ফিরে
আসা উচিত , 27.5999 4 এ ফিরে উচিত,
19.12 2 ফেরত দেওয়া উচিত,
ইত্যাদি

আমি একটি কোয়েরি লিখেছিলাম যা দশমিক স্থানগুলি খুঁজতে একটি পিরিয়ডে একটি স্ট্রিং বিভক্ত হয়েছিল:

int priceDecimalPlaces = price.ToString().Split('.').Count() > 1 
                  ? price.ToString().Split('.').ToList().ElementAt(1).Length 
                  : 0;

তবে আমার কাছে এটি ঘটে যে এটি কেবল 'অঞ্চল' ব্যবহারকারী অঞ্চলে কাজ করবে। দশমিক বিভাজক হিসাবে এবং তাই বিভিন্ন সিস্টেম জুড়ে এটি খুব ভঙ্গুর।


প্রশ্নের শিরোনাম অনুসারে একটি দশমিক
জেসি কার্টার

বিভক্ত হওয়ার পূর্বে কিছু প্যাটার্ন মিলছে কীভাবে? মূলত \ d + (\ D) \ d + যেখানে \ D বিভাজক (। ইত্যাদি) প্রদান করে
আনশুল

7
এটি কোনও বন্ধ-সমাপ্ত প্রশ্ন নয় কারণ এটি প্রথম ব্লাশে উপস্থিত হতে পারে। 19.0ফেরত জিজ্ঞাসা করা 1হ'ল মানের অভ্যন্তরীণ স্টোরেজ সম্পর্কিত একটি বাস্তবায়ন বিশদ19.0 । যে এটি পুরোপুরি বৈধ জন্য প্রোগ্রাম হিসাবে এই সংরক্ষণ করতে হয় 190×10⁻¹বা 1900×10⁻²বা 19000×10⁻³। এঁরা সকলেই সমান। কোনও মান দেওয়ার সময় এটি প্রথম উপস্থাপনা ব্যবহার করে 19.0Mএবং ToStringবিন্যাস নির্দিষ্টকরণ ছাড়াই ব্যবহার করার সময় এটি প্রকাশিত হয় যেটি কেবল একটি কাকতালীয় বিষয় এবং একটি খুশি-ইশ বিষয়। লোকেরা যখন তাদের উচিত হয় না তখন তাদের ঘাতকের উপর নির্ভর করে যখন খুশি হয় না cept
এরিক

আপনি যদি একটি যে ধরনের বহন করতে পারে "দশমিক স্থান সংখ্যা ব্যবহৃত" যখন এটি তৈরি করা হয়, যাতে আপনি নির্ভরযোগ্যভাবে আলাদা করতে পারেন চান 19Mথেকে 19.0Mথেকে 19.00M, আপনি একটি নতুন শ্রেণী যে এক সম্পত্তি হিসেবে অন্তর্নিহিত মান এবং সংখ্যা থোকায় তৈরি করতে হবে অন্য সম্পত্তি হিসাবে দশমিক স্থান।
এরিক

4
যদিও দশমিক শ্রেণি 1900 মিটার থেকে 19.0 মিটার থেকে 19 মিটার "পার্থক্য" করতে পারে? উল্লেখযোগ্য অঙ্কগুলি এর অন্যতম প্রধান ব্যবহারের ক্ষেত্রে। 19.0m * 1.0m কি? 19.00 মিটার বলে মনে হচ্ছে, সম্ভবত সি # দেবরা গণিতটি ভুল করছেন যদিও: পি? আবার উল্লেখযোগ্য অঙ্কগুলি একটি আসল জিনিস। আপনি যদি উল্লেখযোগ্য অঙ্কগুলি পছন্দ না করেন তবে আপনি সম্ভবত দশমিক শ্রেণি ব্যবহার করবেন না।
নিকোলি

উত্তর:


168

আমি এই সমস্যাটি সমাধান করার জন্য জোয়ের উপায় ব্যবহার করেছি :)

decimal argument = 123.456m;
int count = BitConverter.GetBytes(decimal.GetBits(argument)[3])[2];

6
এটিকে আরও পর্যালোচনা করার পরে এবং এটিকে ক্রিয়াতে দেখার পরে আমি এটিকে উত্তর কারণ হিসাবে চিহ্নিত করছি এটি আমার মতে আমি যে দশমিক স্থানগুলি দেখেছি সেখানে ফিরে আসার সবচেয়ে সংক্ষিপ্ত এবং মার্জিত পদ্ধতি। যদি আমি পারতাম আবার +1 করতাম: ডি
জেসি কার্টার

9
decimalকোমার পরে অঙ্ক গণনা রাখে, এই কারণেই আপনি এই "সমস্যাটি" খুঁজে পান, আপনাকে দশমিক দ্বিগুণ করতে হবে এবং ঠিক করার জন্য আবার দশমিক দশমিক নিক্ষেপ করতে হবে: বিটকনভার্টার.গেটবাইটস (দশমিক G গেটবিটস ((দশমিক) (দ্বিগুণ) যুক্তি)] [3]) [ 2];
বার্নিং_লেগশন

4
এটি আমার পক্ষে কাজ করে না। এসকিউএল থেকে ফিরে আসার মান 21.17, যা 4 ডিজিট বলছে। ডেটা-টাইপটিকে ডেসিমাল (12,4) হিসাবে সংজ্ঞায়িত করা হয়েছে তাই সম্ভবত এটি (সত্তা ফ্রেমওয়ার্ক ব্যবহার করে)।
পিটারএক্স

11
@ নিকোলি - না, এটি ব্যতিক্রমীভাবে খারাপ কারণ পদ্ধতিটি দশমিকের অন্তর্নিহিত বিটের স্থান নির্ধারণের উপর নির্ভর করে - এমন একটি অংশ যা একই সংখ্যার প্রতিনিধিত্ব করার অনেকগুলি উপায় রয়েছে । আপনি এটির ব্যক্তিগত ক্ষেত্রগুলির রাজ্যের উপর ভিত্তি করে কোনও ক্লাস পরীক্ষা করবেন না?
এম.এডমন্ডসন

14
এটি সম্পর্কে মার্জিত বা সুন্দর হওয়ার কথাটি নিশ্চিত নয়। এটি এটি যতটা বিস্মৃত হয় ততই পায়। এমনকি এটি সব ক্ষেত্রে কার্যকর হয় কিনা কে জানে। নিশ্চিত করা অসম্ভব।
usr ডিরেক্টরির

24

যেহেতু সরবরাহ করা উত্তরগুলির কোনওটিই ম্যাজিক নম্বর "-0.01f" দশমিক হিসাবে রূপান্তরিত হওয়ার পক্ষে যথেষ্ট ভাল ছিল না ... অর্থাত্: GetDecimal((decimal)-0.01f);
আমি কেবল 3 বছর আগে প্রত্যেকেই আক্রমণাত্মক মাইন্ড-ফার্ট ভাইরাসটিকে ধরে নিয়েছিলাম
বলে মনে করি :) এখানে একটি কাজ বলে মনে হচ্ছে এই অশুভ এবং ভয়াবহ সমস্যাটির বাস্তবায়ন, পয়েন্টের পরে দশমিক স্থানগুলি গণনা করার খুব জটিল সমস্যা - কোনও স্ট্রিং, কোনও সংস্কৃতি নয়, বিটগুলি গণনা করার দরকার নেই এবং গণিত ফোরামগুলি পড়ার দরকার নেই .. কেবল সহজ তৃতীয় শ্রেণির গণিত।

public static class MathDecimals
{
    public static int GetDecimalPlaces(decimal n)
    {
        n = Math.Abs(n); //make sure it is positive.
        n -= (int)n;     //remove the integer part of the number.
        var decimalPlaces = 0;
        while (n > 0)
        {
            decimalPlaces++;
            n *= 10;
            n -= (int)n;
        }
        return decimalPlaces;
    }
}

private static void Main(string[] args)
{
    Console.WriteLine(1/3m); //this is 0.3333333333333333333333333333
    Console.WriteLine(1/3f); //this is 0.3333333

    Console.WriteLine(MathDecimals.GetDecimalPlaces(0.0m));                  //0
    Console.WriteLine(MathDecimals.GetDecimalPlaces(1/3m));                  //28
    Console.WriteLine(MathDecimals.GetDecimalPlaces((decimal)(1 / 3f)));     //7
    Console.WriteLine(MathDecimals.GetDecimalPlaces(-1.123m));               //3
    Console.WriteLine(MathDecimals.GetDecimalPlaces(43.12345m));             //5
    Console.WriteLine(MathDecimals.GetDecimalPlaces(0));                     //0
    Console.WriteLine(MathDecimals.GetDecimalPlaces(0.01m));                 //2
    Console.WriteLine(MathDecimals.GetDecimalPlaces(-0.001m));               //3
    Console.WriteLine(MathDecimals.GetDecimalPlaces((decimal)-0.00000001f)); //8
    Console.WriteLine(MathDecimals.GetDecimalPlaces((decimal)0.0001234f));   //7
    Console.WriteLine(MathDecimals.GetDecimalPlaces((decimal)0.01f));        //2
    Console.WriteLine(MathDecimals.GetDecimalPlaces((decimal)-0.01f));       //2
}

6
আপনার সমাধানটি এমন বেশ কয়েকটি ক্ষেত্রে ব্যর্থ হবে যেগুলিতে শূণ্য শূন্যগুলি রয়েছে এবং অঙ্কগুলি হ'ল স্বাক্ষর। 0.01 মি * 2.0 মি = 0.020 মি। 3 টি সংখ্যার হওয়া উচিত, আপনার পদ্ধতিটি 2 প্রত্যাবর্তন করবে seem ভাসমান পয়েন্টগুলি সহজাতভাবে নির্ভুল নয়, সুতরাং 0.01f এর জন্য সঞ্চিত প্রকৃত বাইনারি মান সঠিক নয়। আপনি যখন দশমিকের কাছে কাস্ট করেন (খুব কাঠামোগত সংখ্যার স্বরলিপি) আপনি 0.01 মিটি পাবেন না (আপনি আসলে 0.010 মিটি পাবেন)। দশমিক থেকে অঙ্কের সংখ্যা পাওয়ার জন্য গেটবিটস সমাধানটি আসলেই সঠিক। আপনি কীভাবে দশমিক রূপান্তর করবেন তা কী।
নিকলি

4
@ নিকোলি 0.020 মিটার 0.02 মিটার সমান .. পেছনের শূন্যগুলি তাৎপর্যপূর্ণ নয়। ওপি শিরোনামে "সংস্কৃতি নির্বিশেষে" জিজ্ঞাসা করছে এবং আরও সুনির্দিষ্ট ব্যাখ্যা দিয়েছে ".. এটি বিভিন্ন সংস্কৃতির তথ্য জুড়ে ব্যবহার করা নিরাপদ হবে .." - তাই আমি মনে করি যে আমার উত্তর অন্যদের তুলনায় আরও বেশি বৈধ থাকবে।
জিওয়াই

6
ওপি বিশেষভাবে বলেছিল: "১৯.০ এর উচিত 1 ফিরে"। এই কোডটি সেই ক্ষেত্রে ব্যর্থ হয়।
ড্যানিলোকিও

9
সম্ভবত ওপি যা চেয়েছিল তা নয়, তবে এই প্রশ্নের উত্তরটি আমার প্রশ্নের পক্ষে এই প্রশ্নের শীর্ষের উত্তরের চেয়ে ভাল
মানায়

4
প্রথম দুই লাইন দিয়ে প্রতিস্থাপিত করা উচিত n = n % 1; if (n < 0) n = -n;কারণ একটি মান চেয়ে বড় int.MaxValueএকটি কারণ হবে OverflowException, যেমন 2147483648.12345
21-18

23

আমি সম্ভবত @ ফিক্সাগনের উত্তরে সমাধানটি ব্যবহার করব ।

তবে, দশমিকের কাঠামোর দশমিকের সংখ্যা পাওয়ার জন্য কোনও পদ্ধতি না থাকলেও আপনি ডেসিমালকে কল করতে পারেন et

স্ট্রিং হিসাবে ফর্ম্যাট করার চেয়ে এটি সম্ভবত দ্রুততর হবে, যদিও আপনাকে এই পার্থক্যটি লক্ষ্য করার জন্য দশমিকের একটি ভয়াবহ প্রক্রিয়া করতে হবে।

আমি বাস্তবায়নটি অনুশীলন হিসাবে ছেড়ে দেব।


4
ধন্যবাদ @ জো যে এটি কাছে যাওয়ার সত্যিই ঝরঝরে উপায়। আমার বসের অন্যান্য সমাধানটি ব্যবহার করার বিষয়ে কীভাবে অনুভূত হয় তার উপর নির্ভর করে আমি আপনার ধারণাকে বাস্তবায়নের দিকে একবার নজর রাখব। অবশ্যই একটি মজাদার অনুশীলন হবে :)
জেসি কার্টার

17

দশমিক বিন্দুর পরে সংখ্যাটির সন্ধানের জন্য সেরা সমাধানগুলির একটি বার্ন_এলজিওনের পোস্টে প্রদর্শিত হয় ।

এখানে আমি একটি এসটিএসডিবি ফোরামের নিবন্ধ থেকে অংশগুলি ব্যবহার করছি: দশমিক পয়েন্টের পরে অঙ্কের সংখ্যা

এমএসডিএন-তে আমরা নিম্নলিখিত ব্যাখ্যাটি পড়তে পারি:

"দশমিক সংখ্যা হ'ল একটি ভাসমান-বিন্দু মান যা একটি চিহ্ন, একটি সংখ্যাসূচক মান নিয়ে গঠিত যেখানে মানের প্রতিটি অঙ্ক 0 থেকে 9 এর মধ্যে হয় এবং একটি স্কেলিং ফ্যাক্টর যা ভাসমান দশমিক বিন্দুর অবস্থান নির্দেশ করে যা অবিচ্ছেদ্য এবং ভগ্নাংশকে পৃথক করে সংখ্যার মান অংশ। "

এবং আরো:

"দশমিক মানটির বাইনারি উপস্থাপনায় 1-বিট চিহ্ন, একটি 96-বিট পূর্ণসংখ্যার সংখ্যা এবং 96-বিট পূর্ণসংখ্যা বিভক্ত করতে ব্যবহৃত একটি স্কেলিং ফ্যাক্টর থাকে এবং এর কোন অংশটি দশমিক ভগ্নাংশ নির্দিষ্ট করে। স্কেলিং ফ্যাক্টরটি স্পষ্টতই 10 নম্বর, 0 থেকে 28 এর মধ্যে একটি বেদীকে উত্থাপিত হয়েছিল ""

অভ্যন্তরীণ স্তরে দশমিক মান চারটি পূর্ণসংখ্যার মান দ্বারা প্রতিনিধিত্ব করা হয়।

দশমিক অভ্যন্তরীণ প্রতিনিধিত্ব

অভ্যন্তরীণ উপস্থাপনা পাওয়ার জন্য এখানে সর্বজনীনভাবে উপলব্ধ গেটবিটস ফাংশন রয়েছে। ফাংশনটি একটি int [] অ্যারে প্রদান করে:

[__DynamicallyInvokable] 
public static int[] GetBits(decimal d)
{
    return new int[] { d.lo, d.mid, d.hi, d.flags };
}

ফিরে আসা অ্যারের চতুর্থ উপাদানটিতে একটি স্কেল ফ্যাক্টর এবং একটি চিহ্ন রয়েছে। এবং এমএসডিএন যেমন বলেছে যে স্কেলিং ফ্যাক্টরটি স্পষ্টতই 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 বিট দিয়ে ফলাফলটিকে প্রকৃত স্কেল ফ্যাক্টরটি ডানদিকে সরিয়ে নিয়েছি। এই মানটি শেষ পর্যন্ত দশমিক বিন্দুর পরে অঙ্কের সংখ্যা নির্দেশ করে।

নোট করুন যে এখানে এমএসডিএন আরও বলেছে যে স্কেলিং ফ্যাক্টরটি কোনও দশমিক সংখ্যায় কোনও পিছনে জিরো সংরক্ষণ করে। ট্রেলিং জিরোগুলি পাটিগণিত বা তুলনামূলক ক্রিয়ায় দশমিক সংখ্যার মানকে প্রভাবিত করে না। তবে, যথাযথ বিন্যাসের স্ট্রিং প্রয়োগ করা হলে ট্যাস্ট্রিং পদ্ধতি দ্বারা অনুসরণযোগ্য জিরোগুলি প্রকাশিত হতে পারে।

এই সমাধানগুলি সেরাটির মতো দেখায় তবে অপেক্ষা করুন, আরও রয়েছে। দ্বারা C # এর ব্যক্তিগত পদ্ধতি অ্যাক্সেস আমরা পতাকা ক্ষেত্রের একটি সরাসরি প্রবেশাধিকার নির্মাণ ও int- এ অ্যারে নির্মাণের এড়াতে এক্সপ্রেশন ব্যবহার করতে পারেন:

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 (value.flags & ~Int32.MinValue) >> 16

        return Expression.Lambda<GetDigitsDelegate>(digits, value);
    }
}

এই সংকলিত কোডটি গেটডিজিটস ক্ষেত্রে বরাদ্দ করা হয়েছে। নোট করুন যে ফাংশনটি দশমিক মান রেফ হিসাবে গ্রহণ করে, তাই কোনও আসল অনুলিপি করা হয় না - কেবলমাত্র মানটির একটি উল্লেখ। ডেসিমেলহেল্পার থেকে গেটডিজিটস ফাংশনটি ব্যবহার করা সহজ:

decimal value = 3.14159m;
int digits = DecimalHelper.Instance.GetDigits(ref value);

দশমিক মানের জন্য দশমিক পয়েন্টের পরে সংখ্যা সংখ্যা পাওয়ার এটি দ্রুততম পদ্ধতি।


4
দশমিক r = (দশমিক) -0.01f; এবং সমাধান ব্যর্থ হয়। (সমস্ত উত্তরগুলিতে আমি এই পৃষ্ঠায় দেখেছি ...) :)
জিওয়াই

4
দ্রষ্টব্য: সম্পূর্ণ (দশমিক) 0.01f জিনিস সম্পর্কে, আপনি একটি দশমিকের মতো খুব কাঠামোগত কিছুতে সহজাতভাবে প্রাক্কলিত নয়, একটি ভাসমান বিন্দু নিক্ষেপ করছেন। কনসোল.রাইটলাইন ((দশমিক) 0.01f) এর আউটপুটটি একবার দেখুন। অভিনেত্রীটিতে বাস্তবে দশমিক দশমিক তিনটি সংখ্যা রয়েছে, সে কারণেই প্রদত্ত সমস্ত সমাধানগুলি 2 এর পরিবর্তে 3 বলে Everything সমস্ত কিছুই আসলে প্রত্যাশার মতো কাজ করছে, "সমস্যা" আপনি ভাসমান পয়েন্টের মানগুলি সঠিক হওয়ার প্রত্যাশা করছেন exact তারা না.
নিকলি

@ নিকোলি আপনার পয়েন্টটি ব্যর্থ হয় যখন আপনি বুঝতে পারবেন যে 0.01এবং 0.010ঠিক সমান সংখ্যায় । তদ্ব্যতীত, একটি সংখ্যাসূচক তথ্য প্রকারের এমন এক ধরণের "ব্যবহৃত সংখ্যার ব্যবহৃত" শব্দার্থক শব্দটির উপর নির্ভর করা যেতে পারে তা সম্পূর্ণ ভুল হয়েছে ("অনুমোদিত সংখ্যাগুলির সাথে বিভ্রান্ত হওয়ার দরকার নেই") উপস্থাপনাটিকে বিভ্রান্ত করবেন না (প্রদর্শন একটি নির্দিষ্ট বেস মধ্যে একটি সংখ্যা মান, উদাহরণস্বরূপ, মান দশমিক সম্প্রসারণ অন্তর্নিহিত মূল্য বাইনারি সম্প্রসারণ 111) দ্বারা নির্দেশিত পুনরাবৃত্তি করা,! সংখ্যার ডিজিট নয়, আর তারা ডিজিটের আপ করা হয়
ErikE

6
এগুলি মান হিসাবে সমান, তবে উল্লেখযোগ্য অঙ্কে নয়। যা দশমিক শ্রেণীর একটি বৃহত ব্যবহারের কেস। আমি যদি জিজ্ঞাসা করি যে আক্ষরিক 0.010 মিটারে কতগুলি সংখ্যা রয়েছে, আপনি কেবল 2 বলবেন? যদিও বিশ্বজুড়ে বেশিরভাগ গণিত / বিজ্ঞান শিক্ষক আপনাকে চূড়ান্ত 0 টি তাৎপর্যপূর্ণ বলবেন? আমরা যে সমস্যার কথা উল্লেখ করছি তা ভাসমান পয়েন্ট থেকে দশমিকের দিকে ingালাই দ্বারা উদ্ভাসিত। গেটবিটস নিজেই ব্যবহার নয়, যা ডকুমেন্ট হিসাবে ঠিক ঠিক করছে। আপনি যদি উল্লেখযোগ্য সংখ্যাগুলির বিষয়ে চিন্তা না করেন তবে হ্যাঁ আপনার সমস্যা আছে এবং সম্ভবত দশমিক শ্রেণিটি প্রথম স্থানে ব্যবহার করা উচিত নয়।
নিকোলি

4
@ থেবার্সকার যতদূর আমার মনে আছে, কোনও ধরা পড়েনি - এটি উভয়ভাবেই কাজ করা উচিত।
ক্রিস্টিয়ান দিমিত্রভ

13

দশমিকের অভ্যন্তরীণ উপস্থাপনার উপর নির্ভর করা ভাল নয়।

এটি সম্পর্কে:

    int CountDecimalDigits(decimal n)
    {
        return n.ToString(System.Globalization.CultureInfo.InvariantCulture)
                //.TrimEnd('0') uncomment if you don't want to count trailing zeroes
                .SkipWhile(c => c != '.')
                .Skip(1)
                .Count();
    }

11

আপনি ইনভারেন্টাল কালচার ব্যবহার করতে পারেন

string priceSameInAllCultures = price.ToString(System.Globalization.CultureInfo.InvariantCulture);

আরেকটি সম্ভাবনা হ'ল এটির মতো কিছু করা:

private int GetDecimals(decimal d, int i = 0)
{
    decimal multiplied = (decimal)((double)d * Math.Pow(10, i));
    if (Math.Round(multiplied) == multiplied)
        return i;
    return GetDecimals(d, i+1);
}

দশমিক দশমিক দশকের জায়গাগুলির সংখ্যা খুঁজতে এটি কীভাবে আমাকে সহায়তা করে? দশমিককে কোনও স্ট্রিংয়ে রূপান্তরিত করতে আমার কোনও সমস্যা নেই যা কোনও সংস্কৃতিতে ভাল। প্রশ্ন অনুসারে আমি দশমিক দশমিক যে জায়গাগুলির সংখ্যা ছিল তা সন্ধানের চেষ্টা করছি
জেসি কার্টার

@ জেসকার্টার: এর অর্থ আপনি সর্বদা বিভক্ত হতে পারেন .
অস্টিন সালোনেন

পছন্দ করেছেন আমি অবগত ছিলাম না যে ইনভায়ারান্ট কালচার ব্যবহার দশমিক বিভাজক হিসাবে কোনও সময়ের ব্যবহারকে কার্যকর করবে
জেসি কার্টার

যেমনটি আপনি আগে করেছিলেন, এটি সর্বদা দামের সাথে একটি দিয়ে স্ট্রিং করে cast দশমিক বিভাজক হিসাবে। তবে এটি আমার মতে সবচেয়ে মার্জিত উপায় নয় ...
ফিক্সাগন


8

দশমিক পর্বের পিছনে থাকা শূন্যগুলিকে স্টোরেজ এবং মুদ্রণের জন্য তাৎপর্যপূর্ণ বলে বিবেচনা করে বলে এখানকার বেশিরভাগ লোকই অসচেতন বলে মনে করছেন।

সুতরাং 0.1 মি, 0.10 মি এবং 0.100 মি সমান হিসাবে তুলনা করতে পারে, তারা আলাদাভাবে সংরক্ষণ করা হয় (যথাযথ মান / স্কেল 1/1, 10/2 এবং 100/3 যথাক্রমে), এবং যথাক্রমে 0.1, 0.10 এবং 0.100 হিসাবে মুদ্রিত হবে , দ্বারা ToString()

এই হিসাবে, যে সমাধানগুলি "খুব উচ্চ নির্ভুলতা" হিসাবে রিপোর্ট করে সেগুলি আসলে তার শর্তাদিতে সঠিক নির্ভুলতার রিপোর্ট করে decimal

তদতিরিক্ত, গণিত ভিত্তিক সমাধানগুলি (10 পাওয়ার দ্বারা গুণিত করার মতো) সম্ভবত খুব ধীর হয়ে যাবে (দশমিক দশমের তুলনায় দশমিক x 40x কম) এবং আপনি ভাসমান-বিন্দুতে মিশ্রিত করতে চান না কারণ সম্ভবত ফলশ্রুতি প্রবর্তনের সম্ভাবনা রয়েছে )। একইভাবে, কাটা কাটা উপায় হিসাবে intবা longcastালাই ত্রুটি-প্রবণ (এগুলির decimalউভয়ের চেয়ে অনেক বেশি পরিসীমা রয়েছে - এটি একটি 96-বিট পূর্ণসংখ্যার আশেপাশের) based

যেমন মার্জিত না হলেও নীচেরটি যথাযথতা পাওয়ার দ্রুততম উপায়গুলির মধ্যে (যখন "পিছনের শূন্যগুলি বাদ দিয়ে দশমিক স্থান হিসাবে সংজ্ঞায়িত করা হয়) হবে:

public static int PrecisionOf(decimal d) {
  var text = d.ToString(System.Globalization.CultureInfo.InvariantCulture).TrimEnd('0');
  var decpoint = text.IndexOf('.');
  if (decpoint < 0)
    return 0;
  return text.Length - decpoint - 1;
}

আক্রমণকারী সংস্কৃতি একটি 'গ্যারান্টি দেয়।' দশমিক পয়েন্ট হিসাবে, পিছনের শূন্যগুলি ছাঁটাই করা হয়, এবং তারপরে দশমিক পয়েন্টের পরে কতগুলি অবস্থান অবশিষ্ট থাকে তা দেখার বিষয় (যদি সেখানে একটিও থাকে)।

সম্পাদনা: প্রত্যাবর্তনের প্রকারটি ইনট এ পরিবর্তিত হয়েছে


4
@ এমভিমর্টেন নিশ্চিত হন না যে আপনি কেন রিটার্নের ধরণটি ইন্টিতে পরিবর্তন করা প্রয়োজন বলে মনে করেছিলেন; বাইটটি আরও সঠিকভাবে প্রত্যাবর্তিত মানটির প্রতিনিধিত্ব করে: স্বাক্ষরবিহীন এবং ছোট পরিসীমা (0-29, অনুশীলনে)।
জাস্টাই

4
আমি সম্মত হই যে পুনরাবৃত্তি এবং গণনা ভিত্তিক সমাধানগুলি ধীর গতির (পিছনে জিরোগুলির জন্য অ্যাকাউন্টিং নয়)। তবে, এর জন্য একটি স্ট্রিং বরাদ্দ করা এবং তার পরিবর্তে এটি পরিচালনা করাও বিশেষত সম্পাদন সমালোচনামূলক প্রসঙ্গে এবং একটি ধীর গিসির সাথে করা সবচেয়ে পারফরম্যান্স কাজ নয়। পয়েন্টার যুক্তির মাধ্যমে স্কেল অ্যাক্সেস করা ভাল এবং দ্রুত বরাদ্দ বিনামূল্যে deal
মার্টিন টিলো শ্মিটজ

হ্যাঁ, স্কেলটি পাওয়া আরও বেশি দক্ষতার সাথে করা যেতে পারে - তবে এর মধ্যে পিছনের শূন্যগুলি অন্তর্ভুক্ত থাকবে। এবং এগুলি সরানোর জন্য পূর্ণসংখ্যার অংশে পাটিগণিত করা প্রয়োজন।
জাস্টাই

6

এবং এখানে আরও একটি উপায় রয়েছে, স্কেলডিসিমাল টাইপটি ব্যবহার করুন যার দশমিকের ডান সংখ্যার গণনা সহ একটি স্কেল সম্পত্তি রয়েছে। আপনার দশমিক মান SQLDecimal এ কাস্ট করুন এবং তারপরে স্কেলে অ্যাক্সেস করুন।

((SqlDecimal)(decimal)yourValue).Scale

4
মাইক্রোসফ্ট রেফারেন্স কোডের দিকে তাকিয়ে , স্কেলডিসিমালকে কাস্টিং অভ্যন্তরীণভাবে ব্যবহার করে GetBytesতাই এটি কোনও অনিরাপদ প্রসঙ্গে বাইটগুলি অ্যাক্সেস না করে বাইট অ্যারে বরাদ্দ করে। এমনকি একটি নোট আছে এবং রেফারেন্স কোডটিতে কোড মন্তব্য করেছে, উল্লেখ করে যে তারা কীভাবে পরিবর্তে এটি করতে পারে। কেন তারা আমার কাছে রহস্য নয়। আমি এ সম্পর্কে পরিষ্কার থাকব এবং এই কাস্টটিতে জিসি এলোককে লুকানোর পরিবর্তে স্কেল বিটগুলি সরাসরি অ্যাক্সেস করব, কারণ এটি হুডের নীচে কী করে তা খুব স্পষ্ট নয়।
মার্টিন টিলো শ্মিটজ

4

এখন পর্যন্ত, তালিকাভুক্ত প্রায় সমস্ত সমাধান জিসি মেমোরি বরাদ্দ করছে, যা কাজগুলি করার জন্য সি # এর অনেক উপায় তবে কার্য সম্পাদনের সমালোচনামূলক পরিবেশে আদর্শ থেকে অনেক দূরে। (যেগুলি ব্যবহারের লুপগুলি বরাদ্দ করে না এবং পিছনের জিরোগুলিও বিবেচনায় নেয় না))

সুতরাং জিসি অ্যালোকগুলি এড়ানোর জন্য, আপনি কেবল কোনও অনিরাপদ প্রসঙ্গে স্কেল বিট অ্যাক্সেস করতে পারেন। এটি ভঙ্গুর মনে হতে পারে তবে মাইক্রোসফ্টের রেফারেন্স উত্স অনুসারে দশমিকের কাঠামো বিন্যাসটি সিক্যুয়াল এবং এটিতে একটি মন্তব্য আছে, ক্ষেত্রের ক্রম পরিবর্তন করার জন্য নয়:

    // NOTE: Do not change the order in which these fields are declared. The
    // native methods in this class rely on this particular order.
    private int flags;
    private int hi;
    private int lo;
    private int mid;

আপনি দেখতে পাচ্ছেন, এখানে প্রথম ইন্টারটি পতাকা ক্ষেত্র। ডকুমেন্টেশন থেকে এবং এখানে অন্যান্য মন্তব্যে উল্লিখিত হিসাবে, আমরা জানি যে 16-24 থেকে কেবলমাত্র বিটগুলি স্কেলকে এনকোড করে এবং 31 শে বিটটি এড়াতে হবে যা চিহ্নটি এনকোড করে। ইনট 4 বাইটের আকার হওয়ায় আমরা নিরাপদে এটি করতে পারি:

internal static class DecimalExtensions
{
  public static byte GetScale(this decimal value)
  {
    unsafe
    {
      byte* v = (byte*)&value;
      return v[2];
    }
  }
}

বাইট অ্যারে বা টোস্ট্রিং রূপান্তরগুলির কোনও জিসি বরাদ্দ না থাকায় এটি সর্বাধিক পারফরম্যান্স সমাধান হতে হবে। আমি এটি ইউনিট 2019.1 তে নেট 4.x এবং নেট 3.5 এর বিপরীতে পরীক্ষা করেছি। যদি কোনও সংস্করণ থাকে যেখানে এটি ব্যর্থ হয় তবে দয়া করে আমাকে জানান।

সম্পাদনা করুন:

অনিরাপদ কোডের বাইরে একই পয়েন্টার যুক্তি কার্যত ব্যবহার করার জন্য একটি সুস্পষ্ট কাঠামো বিন্যাস ব্যবহার করার সম্ভাবনা সম্পর্কে আমাকে স্মরণ করিয়ে দেওয়ার জন্য @ জাস্টাইকে ধন্যবাদ:

[StructLayout(LayoutKind.Explicit)]
public struct DecimalHelper
{
    const byte k_SignBit = 1 << 7;

    [FieldOffset(0)]
    public decimal Value;

    [FieldOffset(0)]
    public readonly uint Flags;
    [FieldOffset(0)]
    public readonly ushort Reserved;
    [FieldOffset(2)]
    byte m_Scale;
    public byte Scale
    {
        get
        {
            return m_Scale;
        }
        set
        {
            if(value > 28)
                throw new System.ArgumentOutOfRangeException("value", "Scale can't be bigger than 28!")
            m_Scale = value;
        }
    }
    [FieldOffset(3)]
    byte m_SignByte;
    public int Sign
    {
        get
        {
            return m_SignByte > 0 ? -1 : 1;
        }
    }
    public bool Positive
    {
        get
        {
            return (m_SignByte & k_SignBit) > 0 ;
        }
        set
        {
            m_SignByte = value ? (byte)0 : k_SignBit;
        }
    }
    [FieldOffset(4)]
    public uint Hi;
    [FieldOffset(8)]
    public uint Lo;
    [FieldOffset(12)]
    public uint Mid;

    public DecimalHelper(decimal value) : this()
    {
        Value = value;
    }

    public static implicit operator DecimalHelper(decimal value)
    {
        return new DecimalHelper(value);
    }

    public static implicit operator decimal(DecimalHelper value)
    {
        return value.Value;
    }
}

মূল সমস্যাটি সমাধান করার জন্য, আপনি পাশাপাশি সমস্ত ক্ষেত্রগুলি সরিয়ে ফেলতে পারেন Valueএবং Scaleতবে কারও পক্ষে সেগুলি সবই রাখা কার্যকর।


4
আপনি নিজের স্ট্রাক্টকে এক্সপ্লিট লেআউট দিয়ে কোডিং করেও অনিরাপদ কোড এড়াতে পারবেন - 0 অবস্থানের দশমিক স্থানে, তারপরে যথাযথ স্থানে বাইট / ইনটস রাখুন। এর মতো কিছু:[StructLayout(LayoutKind.Explicit)] public struct DecimalHelper { [FieldOffset(0)] public decimal Value; [FieldOffset(0)] public uint Flags; [FieldOffset(0)] public ushort Reserved; [FieldOffset(2)] public byte Scale; [FieldOffset(3)] public DecimalSign Sign; [FieldOffset(4)] public uint ValuePart1; [FieldOffset(8)] public ulong ValuePart2; }
জাস্টাই

ধন্যবাদ @ জাস্টাই, ভাল কথা। আমি এই পদ্ধতির পাশাপাশি সংযুক্ত করেছি। :)
মার্টিন টিলো স্মিটজ

4
একটি বিষয় লক্ষণীয়: 0-28 ব্যাপ্তির বাইরে স্কেল সেট করা বিরতি সৃষ্টি করে। টোস্ট্রিং () কাজ করতে ঝোঁক দেয়, তবে গাণিতিক ব্যর্থ হয়।
জাস্টাই

আবার জাস্টাইকে ধন্যবাদ, আমি তার জন্য একটি চেক যুক্ত করেছি :)
মার্টিন টিলো শ্মিতজ

আরেকটি বিষয়: এখানে বেশিরভাগ লোকেরা দশমিক শূন্যগুলি অ্যাকাউন্টে নিতে চান না। আপনি যদি এর মাধ্যমে const decimal Foo = 1.0000000000000000000000000000m;দশমিক বিভাজনকে সংজ্ঞায়িত করেন তবে এটি সর্বনিম্ন স্কেলে পুনরুদ্ধার করবে (অর্থাত্ দশমিক শূন্যগুলি ছাড়াই আর থাকবে না)। আমি অন্য কোথাও প্রস্তাবিত স্ট্রিং-ভিত্তিক পদ্ধতির চেয়ে দ্রুততর কিনা তা দেখার জন্য আমি এটি বেঞ্চমার্ক করে নেই।
জাস্টাই

2

আমি গতকাল একটি সংক্ষিপ্ত ছোট্ট পদ্ধতি লিখেছিলাম যা দশমিক জায়গাগুলির সংখ্যাও ফিরে আসে যা কোনও স্ট্রিং স্প্লিট বা সংস্কৃতিতে নির্ভর করে না যা আদর্শ:

public int GetDecimalPlaces(decimal decimalNumber) { // 
try {
    // PRESERVE:BEGIN
        int decimalPlaces = 1;
        decimal powers = 10.0m;
        if (decimalNumber > 0.0m) {
            while ((decimalNumber * powers) % 1 != 0.0m) {
                powers *= 10.0m;
                ++decimalPlaces;
            }
        }
return decimalPlaces;

@ ফিক্স-লাইক-কোডিং আপনার দ্বিতীয় উত্তরের অনুরূপ যদিও এর মতো কোনও কিছুর জন্য আমি পুনরাবৃত্তি ব্যবহার না করে পুনরাবৃত্ত পদ্ধতির পক্ষে
জেসি কার্টার

আসল পোস্ট যে: 19.0 should return 1। এই দ্রবণটি সর্বদা সর্বনিম্ন 1 দশমিক স্থান গ্রহণ করে এবং পিছনে জিরো উপেক্ষা করবে। দশমিকের এগুলি থাকতে পারে কারণ এটি একটি স্কেল ফ্যাক্টর ব্যবহার করে। স্কোর ফ্যাক্টরটি এলিমেন্টের 16-2-24 ব্রেটের মতো অ্যারে ইনডেক্স 3 এর সাথে Decimal.GetBytes()পয়েন্টার যুক্তি থেকে বা ব্যবহার করে অ্যাক্সেস করা যায় ।
মার্টিন টিলো স্মিটজ

2

আমি ক্লিমেন্টের জবাবের সাথে খুব মিলপূর্ণ কিছু ব্যবহার করছি:

private int GetSignificantDecimalPlaces(decimal number, bool trimTrailingZeros = true)
{
  string stemp = Convert.ToString(number);

  if (trimTrailingZeros)
    stemp = stemp.TrimEnd('0');

  return stemp.Length - 1 - stemp.IndexOf(
         Application.CurrentCulture.NumberFormat.NumberDecimalSeparator);
}

অ্যাপ্লিকেশন.সামগ্রী সংস্কৃতিতে অ্যাক্সেস পেতে সিস্টেম.বাইন্ডস.ফর্মগুলি ব্যবহার করতে ভুলবেন না


1

আপনি চেষ্টা করতে পারেন:

int priceDecimalPlaces =
        price.ToString(System.Globalization.CultureInfo.InvariantCulture)
              .Split('.')[1].Length;

7
দশমিক সম্পূর্ণ সংখ্যা হলে এটি ব্যর্থ হবে না? [1]
সিলভারমাইন্ড

1

আমি আমার কোডে নিম্নলিখিত পদ্ধতিটি ব্যবহার করি

  public static int GetDecimalLength(string tempValue)
    {
        int decimalLength = 0;
        if (tempValue.Contains('.') || tempValue.Contains(','))
        {
            char[] separator = new char[] { '.', ',' };
            string[] tempstring = tempValue.Split(separator);

            decimalLength = tempstring[1].Length;
        }
        return decimalLength;
    }

দশমিক ইনপুট = 3.376; var ইনস্ট্রিং = ইনপুট.টোস্ট্রিং ();

গেটডিসিমাল লেন্থ (ইন্সট্রিং) কল করুন


4
ডেসিমাল মানটির টোস্ট্রিং () উপস্থাপনা হিসাবে আমার ডেটা শেষে "00" যুক্ত হয় - এটি এসকিউএল সার্ভার থেকে আমি একটি দশমিক (12,4) ডেটাটাইপ ব্যবহার করছি।
পিটারএক্স

আপনি কি সি # টাইপ দশমিকের জন্য আপনার ডেটা কাস্ট করতে পারেন এবং সমাধানটি চেষ্টা করতে পারেন? আমার জন্য যখন আমি সি # দশমিক মানের উপর টস্ট্রিং () ব্যবহার করি আমি কখনই "00" দেখি না।
শ্রীকান্ত

1

পুনরাবৃত্তি ব্যবহার করে আপনি করতে পারেন:

private int GetDecimals(decimal n, int decimals = 0)  
{  
    return n % 1 != 0 ? GetDecimals(n * 10, decimals + 1) : decimals;  
}

আসল পোস্ট যে: 19.0 should return 1। এই সমাধানটি অনুসরণীয় শূন্যগুলি উপেক্ষা করবে। দশমিকের এগুলি থাকতে পারে কারণ এটি একটি স্কেল ফ্যাক্টর ব্যবহার করে। Decimal.GetBytes()অ্যারেতে ইনডেক্স 3 সহ উপাদানটির বাইট 16-24 এর মতো স্কেল ফ্যাক্টরটি অ্যাক্সেস করা যেতে পারে বা পয়েন্টার যুক্তি ব্যবহার করে।
মার্টিন টিলো শ্মিতজ


0

আমি এই পদ্ধতিটি ব্যবহার করার পরামর্শ দিচ্ছি:

    public static int GetNumberOfDecimalPlaces(decimal value, int maxNumber)
    {
        if (maxNumber == 0)
            return 0;

        if (maxNumber > 28)
            maxNumber = 28;

        bool isEqual = false;
        int placeCount = maxNumber;
        while (placeCount > 0)
        {
            decimal vl = Math.Round(value, placeCount - 1);
            decimal vh = Math.Round(value, placeCount);
            isEqual = (vl == vh);

            if (isEqual == false)
                break;

            placeCount--;
        }
        return Math.Min(placeCount, maxNumber); 
    }

0

দশমিক এক্সটেনশন পদ্ধতি যা অ্যাকাউন্টে নেয়:

  • ভিন্ন সংস্কৃতি
  • সম্পূর্ণ সংখ্যা
  • নেতিবাচক সংখ্যা
  • দশমিক স্থানে ট্রেলিং সেট শিরোগুলি (উদাহরণস্বরূপ 1.2300M 2 2 না 4 ফিরে আসবে)
public static class DecimalExtensions
{
    public static int GetNumberDecimalPlaces(this decimal source)
    {
        var parts = source.ToString(CultureInfo.InvariantCulture).Split('.');

        if (parts.Length < 2)
            return 0;

        return parts[1].TrimEnd('0').Length;
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.