আমি কোনও সংখ্যার মোট সংখ্যাগুলির সংখ্যা গণনা করব কীভাবে?


114

সি # তে কোনও সংখ্যার মোট সংখ্যাগুলির সংখ্যা গণনা করব কীভাবে? উদাহরণস্বরূপ, 887979789 সংখ্যাটির 9 টি সংখ্যা রয়েছে।


6
ব্যবহার করে দেখুন। দৈর্ঘ্য যদি এটি প্রথমে একটি স্ট্রিতে রূপান্তর করে কাজ করে না
ব্রিজার

যাক x = 887979789; x.ToString () গণনা ()। তোমাকে দিবে
nPcomp

উত্তর:


174

কোনও স্ট্রিংয়ে রূপান্তর না করে আপনি চেষ্টা করতে পারেন:

Math.Ceiling(Math.Log10(n));

ইয়াসাপের মন্তব্যে নিম্নলিখিত সংশোধন:

Math.Floor(Math.Log10(n) + 1);

10
আমি ভয় পাচ্ছি সিল (লগ 10 (10)) = সিল (1) = 1, এবং এই প্রশ্নটির মতো হওয়া উচিত 2 নয়!
ysap

3
ধন্যবাদ, এটি একটি দুর্দান্ত পদ্ধতি। যদিও এটি int গণনা = 0 এর চেয়ে দ্রুত নয়; do {গণনা ++; } সময় ((i / = 10)> = 1); :(
পুটার্ডো বোরাটো

3
যদি আপনার সংখ্যা পরিসীমা নেতিবাচক অন্তর্ভুক্ত করে তবে আপনাকে ম্যাথ ফ্লোর (ম্যাথ.লগ 10 (ম্যাথ.এবস (এন)) + 1) ব্যবহার করতে হবে;
এমক্রোকল

1
ওয়েল যদি nহয় 0শুধু আসতে পারেন 1:) খুব হ্যান্ডেল নেতিবাচক মান ঠিক প্রতিস্থাপন nসঙ্গে Math.Abs(n)
উমাইর

3
@ পুটারডো বোরাটো: আমার পারফরম্যান্স টেস্টটি প্রকৃতপক্ষে প্রমাণ করেছে যে অঙ্কগুলির সংখ্যা <যখন 5 হয় তখন আপনার পদ্ধতিটি দ্রুত। 5. পাস করুন, স্টিভের ম্যাথ f ফ্লুরটি দ্রুত।
stack247

83

এটা চেষ্টা কর:

myint.ToString().Length

ওইটা কি কাজ করে ?


25
এটি উল্লেখ করার মতো যে আপনি যদি নেতিবাচক সংখ্যার সাথে কাজ করে থাকেন তবে আপনি সম্ভবত এই পদ্ধতিটি নিয়ে সমস্যায় পড়বেন। (এবং স্পষ্টত দশমিক, কিন্তু উদাহরণটি একটি ব্যবহার করে int, সুতরাং আমি ধরে নিই যে এটি কোনও সমস্যা নয়))
কোডি গ্রে

2
@ ক্রাইটিক স্ট্রিং বরাদ্দকরণ। নেট নেট ওয়ার্ল্ডে নতুন ক্রেজ।
নওফাল

1
নতুন? কষ্টসহকারে। আমি গুরুতরভাবে 2010 সালে স্ট্রিংগুলি বরাদ্দ করেছিলাম What কী ট্রেন্ড সেটর। হাঃ হাঃ হাঃ. আপনি যদিও ঠিক আছেন। এই নোংরা!
Andiih

3
@ ক্রিথিক এটি ১৯৮০ এর দশক নয়, আপনার কম্পিউটারে একটি ক্রিয়াকলাপের জন্য 10 অক্ষরের স্ট্রিং মেমরিতে সংরক্ষণ করার জন্য পর্যাপ্ত র‍্যাম রয়েছে।
মিস্টারলরে

2
@ মিঃলোর সরল অ্যাপ্লিকেশনগুলিতে এটি সত্য হতে পারে তবে গেম ডেভলপমেন্ট বিশ্বে এটি সম্পূর্ণ ভিন্ন জন্তু।
ক্রিথিক

48

সমাধান

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

ইন্টার 32 সংস্করণ:

public static class Int32Extensions
{
    // IF-CHAIN:
    public static int Digits_IfChain(this int n)
    {
        if (n >= 0)
        {
            if (n < 10) return 1;
            if (n < 100) return 2;
            if (n < 1000) return 3;
            if (n < 10000) return 4;
            if (n < 100000) return 5;
            if (n < 1000000) return 6;
            if (n < 10000000) return 7;
            if (n < 100000000) return 8;
            if (n < 1000000000) return 9;
            return 10;
        }
        else
        {
            if (n > -10) return 2;
            if (n > -100) return 3;
            if (n > -1000) return 4;
            if (n > -10000) return 5;
            if (n > -100000) return 6;
            if (n > -1000000) return 7;
            if (n > -10000000) return 8;
            if (n > -100000000) return 9;
            if (n > -1000000000) return 10;
            return 11;
        }
    }

    // USING LOG10:
    public static int Digits_Log10(this int n) =>
        n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));

    // WHILE LOOP:
    public static int Digits_While(this int n)
    {
        int digits = n < 0 ? 2 : 1;
        while ((n /= 10) != 0) ++digits;
        return digits;
    }

    // STRING CONVERSION:
    public static int Digits_String(this int n) =>
        n.ToString().Length;
}

ইন্টার 64 সংস্করণ:

public static class Int64Extensions
{
    // IF-CHAIN:
    public static int Digits_IfChain(this long n)
    {
        if (n >= 0)
        {
            if (n < 10L) return 1;
            if (n < 100L) return 2;
            if (n < 1000L) return 3;
            if (n < 10000L) return 4;
            if (n < 100000L) return 5;
            if (n < 1000000L) return 6;
            if (n < 10000000L) return 7;
            if (n < 100000000L) return 8;
            if (n < 1000000000L) return 9;
            if (n < 10000000000L) return 10;
            if (n < 100000000000L) return 11;
            if (n < 1000000000000L) return 12;
            if (n < 10000000000000L) return 13;
            if (n < 100000000000000L) return 14;
            if (n < 1000000000000000L) return 15;
            if (n < 10000000000000000L) return 16;
            if (n < 100000000000000000L) return 17;
            if (n < 1000000000000000000L) return 18;
            return 19;
        }
        else
        {
            if (n > -10L) return 2;
            if (n > -100L) return 3;
            if (n > -1000L) return 4;
            if (n > -10000L) return 5;
            if (n > -100000L) return 6;
            if (n > -1000000L) return 7;
            if (n > -10000000L) return 8;
            if (n > -100000000L) return 9;
            if (n > -1000000000L) return 10;
            if (n > -10000000000L) return 11;
            if (n > -100000000000L) return 12;
            if (n > -1000000000000L) return 13;
            if (n > -10000000000000L) return 14;
            if (n > -100000000000000L) return 15;
            if (n > -1000000000000000L) return 16;
            if (n > -10000000000000000L) return 17;
            if (n > -100000000000000000L) return 18;
            if (n > -1000000000000000000L) return 19;
            return 20;
        }
    }

    // USING LOG10:
    public static int Digits_Log10(this long n) =>
        n == 0L ? 1 : (n > 0L ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));

    // WHILE LOOP:
    public static int Digits_While(this long n)
    {
        int digits = n < 0 ? 2 : 1;
        while ((n /= 10L) != 0L) ++digits;
        return digits;
    }

    // STRING CONVERSION:
    public static int Digits_String(this long n) =>
        n.ToString().Length;
}

আলোচনা

এই উত্তরে এলোমেলোভাবে নমুনা / সংখ্যার অ্যারে ব্যবহার করে উভয় Int32এবং Int64প্রকারের জন্য সম্পাদিত পরীক্ষাগুলি অন্তর্ভুক্ত রয়েছে । পরীক্ষাগুলি সম্পাদন করার আগে এলোমেলোভাবে ডেটাসেট একটি অ্যারেতে প্রাক-প্রক্রিয়াজাত করা হয়।100.000.000intlong

4 বিভিন্ন পদ্ধতি মধ্যে সমন্নয় পরীক্ষার এছাড়াও, মৃত্যুদন্ড কার্যকর করা হয় জন্য MinValue, নেতিবাচক সীমান্ত ক্ষেত্রে, -1, 0, 1ইতিবাচক সীমান্ত ক্ষেত্রে, MaxValue, এবং এছাড়াও পুরো র্যান্ডম ডেটা সেটটি জন্য। উপরোক্ত প্রদত্ত পদ্ধতিগুলির জন্য কোনও ধারাবাহিকতা পরীক্ষা ব্যর্থ হয় না, LOG10 পদ্ধতির জন্য ব্যতিক্রম (এটি পরে আলোচনা করা হবে)।

পরীক্ষাগুলি কার্যকর করা হয়েছিল .NET Framework 4.7.2এবং .NET Core 2.2; জন্য x86এবং x64প্ল্যাটফর্মের, একটি 64-বিট Intel প্রসেসর মেশিনে সঙ্গে Windows 10, এবং VS2017 v.15.9.17। নিম্নলিখিত 4 টি ক্ষেত্রে পারফরম্যান্স ফলাফলের ক্ষেত্রে একই প্রভাব রয়েছে:

। নেট ফ্রেমওয়ার্ক (x86)

  • Platform = x86

  • Platform = AnyCPU, Prefer 32-bitপ্রকল্প সেটিংস চেক করা হয়

। নেট ফ্রেমওয়ার্ক (x64)

  • Platform = x64

  • Platform = AnyCPU, Prefer 32-bitপ্রকল্প সেটিংস চেক করা হয়

.NET কোর (x86)

  • "C:\Program Files (x86)\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll

  • "C:\Program Files (x86)\dotnet\dotnet.exe" bin\x86\Release\netcoreapp2.2\ConsoleApp.dll

। নেট কোর (x64)

  • "C:\Program Files\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll

  • "C:\Program Files\dotnet\dotnet.exe" bin\x64\Release\netcoreapp2.2\ConsoleApp.dll

ফলাফল

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

হিসাবে @AlanSingfield মন্তব্য বিভাগে নির্দিষ্ট, LOG10 পদ্ধতি করার জন্য একটি ঢালাই সঙ্গে সংশোধন করা হয়েছিল doubleভিতরে Math.Abs()ক্ষেত্রে জন্য যখন ইনপুট মান int.MinValueবা long.MinValue

এই প্রশ্নটি সম্পাদনার আগে আমি প্রাথমিক সম্পাদনা পরীক্ষাগুলি প্রয়োগ করেছি (এটি ইতিমধ্যে এক মিলিয়ন বার সম্পাদনা করতে হয়েছিল), @ গাইরিগেরস্কেগ দ্বারা চিহ্নিত একটি নির্দিষ্ট কেস ছিল , যেখানে আইএফ-চেইন পদ্ধতি LOG10 পদ্ধতির চেয়ে ধীর সম্পাদন করে।

এটি এখনও ঘটে, যদিও @ অ্যালানসিংফিল্ড দ্বারা ইস্যু করা ইস্যুটির স্থিরতার পরে পার্থক্যটির মাত্রা অনেক কম হয়ে গেছেdoubleযখন এই ইনপুট মানটি হুবহু হয় তখন এই সংশোধন (এতে একটি কাস্ট যোগ করা ) একটি গণনা ত্রুটির কারণ ঘটে -999999999999999999: LOG10 পদ্ধতি 20পরিবর্তে ফিরে আসে 19ifইনপুট মানটি শূন্য হলে LOG10 পদ্ধতিতে কেসটির জন্যও একজন প্রহরী থাকতে হবে ।

LOG10 পদ্ধতিটি সমস্ত মানগুলির জন্য কাজ করা বেশ জটিল, যার অর্থ আপনার এড়ানো উচিত। যদি কেউ নীচের সমস্ত ধারাবাহিকতা পরীক্ষার জন্য এটি সঠিকভাবে কাজ করার কোনও উপায় খুঁজে পায় তবে দয়া করে একটি মন্তব্য পোস্ট করুন!

WHILE পদ্ধতিটি একটি সাম্প্রতিক রিফ্যাক্টরড সংস্করণও পেয়েছে যা দ্রুততর তবে এটি এখনও ধীর গতির Platform = x86( এখনও পর্যন্ত এর কারণটি আমি খুঁজে পাইনি)।

STRING পদ্ধতিটি ধারাবাহিকভাবে ধীরে ধীরে: লোভের সাথে কিছুই করার জন্য খুব বেশি মেমরি বরাদ্দ করে। মজার বিষয় হল। নেট কোরে স্ট্রিং বরাদ্দকরণটি নেট ফ্রেমওয়ার্কের চেয়ে অনেক দ্রুত be জানা ভাল.

যদি আইএফ-চেইন পদ্ধতিটি 99.99% ক্ষেত্রে অন্যান্য সমস্ত পদ্ধতিকে ছাড়িয়ে যায়; এবং, আমার ব্যক্তিগত মতে, আপনার সেরা পছন্দ (LOG10 পদ্ধতিটি সঠিকভাবে কাজ করার জন্য প্রয়োজনীয় সমস্ত সামঞ্জস্য এবং অন্য দুটি পদ্ধতির খারাপ পারফরম্যান্স বিবেচনা করে) is

অবশেষে, ফলাফলগুলি হ'ল:

এখানে চিত্র বর্ণনা লিখুন

যেহেতু এই ফলাফলগুলি হার্ডওয়্যার-নির্ভর, তাই আপনার নিজের কম্পিউটারে যদি আপনার সত্যিকারের 100% নিশ্চিত হওয়ার দরকার হয় তবে আমি নীচে আপনার নিজের কম্পিউটারে কর্মক্ষমতা পরীক্ষা চালানোর পরামর্শ দিচ্ছি।

পরীক্ষার কোড

নীচে পারফরম্যান্স টেস্টের কোড, এবং ধারাবাহিকতা পরীক্ষাও। নেট কোড ফ্রেমওয়ার্ক এবং। নেট কোর উভয়ের জন্য একই কোড ব্যবহার করা হয়।

using System;
using System.Diagnostics;

namespace NumberOfDigits
{
    // Performance Tests:
    class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine("\r\n.NET Core");

            RunTests_Int32();
            RunTests_Int64();
        }

        // Int32 Performance Tests:
        private static void RunTests_Int32()
        {
            Console.WriteLine("\r\nInt32");

            const int size = 100000000;
            int[] samples = new int[size];
            Random random = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < size; ++i)
                samples[i] = random.Next(int.MinValue, int.MaxValue);

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
            sw1.Stop();
            Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
            sw2.Stop();
            Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");

            Stopwatch sw3 = new Stopwatch();
            sw3.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_While();
            sw3.Stop();
            Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");

            Stopwatch sw4 = new Stopwatch();
            sw4.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_String();
            sw4.Stop();
            Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");


            // Start of consistency tests:
            Console.WriteLine("Running consistency tests...");
            bool isConsistent = true;

            // Consistency test on random set:
            for (int i = 0; i < samples.Length; ++i)
            {
                int s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test of special values:
            samples = new int[]
            {
                0,
                int.MinValue, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
                int.MaxValue, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9,  1,
            };
            for (int i = 0; i < samples.Length; ++i)
            {
                int s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test result:
            if (isConsistent)
                Console.WriteLine("Consistency tests are OK");
        }

        // Int64 Performance Tests:
        private static void RunTests_Int64()
        {
            Console.WriteLine("\r\nInt64");

            const int size = 100000000;
            long[] samples = new long[size];
            Random random = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < size; ++i)
                samples[i] = Math.Sign(random.Next(-1, 1)) * (long)(random.NextDouble() * long.MaxValue);

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
            sw1.Stop();
            Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
            sw2.Stop();
            Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");

            Stopwatch sw3 = new Stopwatch();
            sw3.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_While();
            sw3.Stop();
            Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");

            Stopwatch sw4 = new Stopwatch();
            sw4.Start();
            for (int i = 0; i < size; ++i) samples[i].Digits_String();
            sw4.Stop();
            Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");

            // Start of consistency tests:
            Console.WriteLine("Running consistency tests...");
            bool isConsistent = true;

            // Consistency test on random set:
            for (int i = 0; i < samples.Length; ++i)
            {
                long s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test of special values:
            samples = new long[] 
            {
                0,
                long.MinValue, -1000000000000000000, -999999999999999999, -100000000000000000, -99999999999999999, -10000000000000000, -9999999999999999, -1000000000000000, -999999999999999, -100000000000000, -99999999999999, -10000000000000, -9999999999999, -1000000000000, -999999999999, -100000000000, -99999999999, -10000000000, -9999999999, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
                long.MaxValue, 1000000000000000000, 999999999999999999, 100000000000000000, 99999999999999999, 10000000000000000, 9999999999999999, 1000000000000000, 999999999999999, 100000000000000, 99999999999999, 10000000000000, 9999999999999, 1000000000000, 999999999999, 100000000000, 99999999999, 10000000000, 9999999999, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9,  1,
            };
            for (int i = 0; i < samples.Length; ++i)
            {
                long s = samples[i];
                int a = s.Digits_IfChain();
                int b = s.Digits_Log10();
                int c = s.Digits_While();
                int d = s.Digits_String();
                if (a != b || c != d || a != c)
                {
                    Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
                    isConsistent = false;
                    break;
                }
            }

            // Consistency test result:
            if (isConsistent)
                Console.WriteLine("Consistency tests are OK");
        }
    }
}

4
আমি এই সমাধানটি পছন্দ করি, এটি গণিতের কৌশলগুলির চেয়ে অনেক বেশি পঠনযোগ্য এবং গতিটি নিজেই কথা বলে, কুডোস।
মিঃলরে

3
কেন এটি সমাধান হিসাবে চিহ্নিত করা হয়নি? পারফরম্যান্সের বিষয়টি গুরুত্বপূর্ণ এবং এটি সর্বাধিক বিস্তৃত উত্তর বলে মনে হচ্ছে।
মারটিয়েন ডি জং

আকর্ষণীয়, আমি বিভিন্ন ফলাফল পেতে । এলোমেলো মানগুলির জন্য লগ 10 এবং ব্রুট ফোর্স প্রায় একই তবে long.MaxValueলগ 10 এর জন্য উল্লেখযোগ্যভাবে ভাল। বা এটি ঠিক। নেট কোর মধ্যে আছে?
গাইরিজিয়ান কাসেজেগ

@ গাইরিগেসকিজেগ: আমি ইন্টার 64৪ এর জন্য পরীক্ষা যোগ করেছি। দয়া করে সচেতন হন যে পরীক্ষাগুলি বিভিন্ন ডেটাসেটের জন্য উত্পন্ন করে Int32এবং Int64উত্পন্ন করে, যা ব্যাখ্যা করতে পারে যে কিছু ক্ষেত্রে কেন Int64দ্রুত Int32হয়েছে। যদিও Int32পরীক্ষার মধ্যে এবং পরীক্ষার মধ্যে Int64বিভিন্ন গণনা পদ্ধতি পরীক্ষা করার সময় ডেটাসেটগুলি পরিবর্তন করা হয় না। নেট নেট সম্পর্কে এখন আমি সন্দেহ করি যে ম্যাথ লাইব্রেরিতে এমন কোনও ম্যাজিক অপ্টিমাইজেশন রয়েছে যা এই ফলাফলগুলিকে বদলে দেবে, তবে আমি সে সম্পর্কে আরও শুনতে পছন্দ করব (আমার উত্তরটি ইতিমধ্যে বিশাল, সম্ভবত এসও এর মধ্যে অন্যতম বৃহত্তম ;-)
sɐunıɔ ןɐ qɐp

@ গাইরিগেসকিজেগ: এছাড়াও, নিম্ন-স্তরের পারফরম্যান্সের পরিমাপগুলি খুব জটিল are আমি সাধারণত যতটা সম্ভব সহজ হিসাবে কোড রাখতে পছন্দ (আমি সহজ পছন্দ forউপর লুপ enumerations, আমি প্রাক প্রক্রিয়া র্যান্ডম ডেটাসেট ও জেনেরিক্স, টাস্ক, ব্যবহার এড়াতে Function<>, Action<>বা কোনো কালো বাক্সযুক্ত পরিমাপ ফ্রেমওয়ার্ক)। সংক্ষেপে, এটি সহজ রাখুন। আমি সমস্ত অপ্রয়োজনীয় অ্যাপ্লিকেশন (স্কাইপ, উইন্ডোজ ডিফেন্ডার, অ্যান্টি-ভাইরাস, ক্রোম, মাইক্রোসফ্ট অফিসের ক্যাশে, ইত্যাদি অক্ষম) কেও হত্যা করি।
সানুন ןɐ কিউপি

13

সরাসরি সি # নয়, তবে সূত্রটি হ'ল: n = floor(log10(x)+1)


2
লগ 10 (0) হ'ল ইনফিনিটি
অ্যালেক্স ক্লাউস

2
@ ক্লাউস - লগ 10 (0) আসলে সংজ্ঞায়িত। তবে, আপনি ঠিক বলেছেন যে এটি একটি বিশেষ ক্ষেত্রে এটির জন্য আলাদাভাবে পরীক্ষা করা এবং চিকিত্সা করা দরকার। এটি কোনও ধনাত্মক পূর্ণসংখ্যার সংখ্যার ক্ষেত্রেও সত্য। স্টিভ এর উত্তর মন্তব্য দেখুন।
ইয়াসাপ

@ysap: লগ 10 সঠিকভাবে কাজ করা বেশ জটিল। সম্ভাব্য ইনপুট মানগুলির সমস্ত ব্যাপ্তির জন্য কীভাবে এটি সঠিকভাবে প্রয়োগ করা যায় সে সম্পর্কে আপনার কোনও ধারণা আছে?
সুনুন ןɐ কিউপি

@ সুনু ıɔ কিউপি - log10বেশিরভাগ ক্ষেত্রেই একটি লাইব্রেরি ফাংশন হয়। আপনি কেন এটি নিজে প্রয়োগ করতে চান এবং কোন সমস্যার মুখোমুখি হন? log10(x) = log2(x) / log2(10), বা সাধারণত logA(x) = logB(x) / logB(A)
ysap

আমি আবার লগ 10 বাস্তবায়ন করতে চাইছিলাম না, তার অর্থ Log10(0)হ'ল -ইনফিনিটি। আপনি যদি লগ 10 Math.Abs()এ মান দেওয়ার আগে ব্যবহার না করেন তবে লগ 10 negative ণাত্মক সংখ্যার সংখ্যা গণনা করতে ব্যবহার করা যাবে না । তবে তারপরে Math.Abs(int.MinValue)একটি ব্যতিক্রম ছোঁড়ে ( long.MinValueইন্টার-এর ক্ষেত্রেও)। যদি আমরা লগ 10 এ পাস করার আগে এই সংখ্যাটি দ্বিগুণ করতে পারি, তবে এটি -999999999999999999(Int64 এর ক্ষেত্রে) বাদে প্রায় সকল সংখ্যার জন্য কাজ করে । লগ 10 ব্যবহার করে এমন কোনও সংখ্যার গণনা করার কোনও সূত্র জানেন যা কোনও ইনট 32 বা ইনট 64 মানকে ইনপুট হিসাবে গ্রহণ করে এবং কেবল বৈধ মানগুলিই আউটপুট করে?
sɐunıɔ ןɐ qɐp

9

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

public static int Length(double number)
{
    number = Math.Abs(number);
    int length = 1;
    while ((number /= 10) >= 1)
        length++;
    return length;
}
//number of digits in 0 = 1,
//number of digits in 22.1 = 2,
//number of digits in -23 = 2

যথাযথতার বিষয়ে doubleআপনি decimalযদি ইনপুট প্রকারটি পরিবর্তন করতে পারেন তবে দশমিকেরও সীমা রয়েছে।


7

স্টিভের উত্তরটি সঠিক , তবে এটি 1 এর চেয়ে কম পূর্ণসংখ্যার জন্য কাজ করে না।

এখানে একটি আপডেট হওয়া সংস্করণ যা নেতিবাচকদের জন্য কাজ করে:

int digits = n == 0 ? 1 : Math.Floor(Math.Log10(Math.Abs(n)) + 1)

আপনি একটি ingালাই হারিয়েছেন:digits = n == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(n)) + 1);
সুনি ıɔ কিউপি

আমি যদি বিবৃতি না দিয়ে এটি করেছি: অঙ্কগুলি = (অবধি) ম্যাথ। ফ্লোর (ম্যাথ.এবস (ম্যাথ.লগ 10 (ম্যাথ.এবস (এন))) + 1)
কলআরহ

এটি যখন একটি ব্যতিক্রম ছোঁড়ে n = int.MinValue
সুনুন ןɐ কিউপি

5

পুনরাবৃত্তি ব্যবহার করা (কখনও কখনও সাক্ষাত্কারে জিজ্ঞাসা করা হয়)

public int CountDigits(int number)
{
    // In case of negative numbers
    number = Math.Abs(number);

    if (number >= 10)
        return CountDigits(number / 10) + 1;
    return 1;
 }

1
এটি যখন একটি ব্যতিক্রম ছোঁড়ে number = int.MinValue
সুনুন ןɐ কিউপি


2

এখানে একটি বাইনারি অনুসন্ধান ব্যবহার করে একটি বাস্তবায়ন। ইন্টি 32 এ এখন পর্যন্ত দ্রুততম বলে মনে হচ্ছে।

পাঠকদের (!) জন্য অনুশীলন হিসাবে বাক্য রেখে দেওয়া হয়েছে!

আমি গাছটিকে হার্ড-কোডিংয়ের চেয়ে অ্যারে.বাইনারি অনুসন্ধান ব্যবহার করার চেষ্টা করেছি, তবে তার গতি প্রায় অর্ধেক ছিল।

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

Lookup-Table: 439 ms
Binary-Search: 1069 ms
If-Chain: 1409 ms
Log10: 1145 ms
While: 1768 ms
String: 5153 ms

সারণী সংস্করণ দেখুন:

static byte[] _0000llll = new byte[0x10000];
static byte[] _FFFFllll = new byte[0x10001];
static sbyte[] _hhhhXXXXdigits = new sbyte[0x10000];

// Special cases where the high DWORD is not enough information to find out how
// many digits.
static ushort[] _lowordSplits = new ushort[12];
static sbyte[] _lowordSplitDigitsLT = new sbyte[12];
static sbyte[] _lowordSplitDigitsGE = new sbyte[12];

static Int32Extensions()
{
    // Simple lookup tables for number of digits where value is 
    //    0000xxxx (0 .. 65535)
    // or FFFFxxxx (-1 .. -65536)
    precomputePositiveLo16();
    precomputeNegativeLo16();

    // Hiword is a little more complex
    precomputeHiwordDigits();
}

private static void precomputeHiwordDigits()
{
    int b = 0;

    for(int hhhh = 0; hhhh <= 0xFFFF; hhhh++)
    {
        // For hiword hhhh, calculate integer value for loword of 0000 and FFFF.
        int hhhh0000 = (unchecked(hhhh * 0x10000));  // wrap around on negatives
        int hhhhFFFF = hhhh0000 + 0xFFFF;

        // How many decimal digits for each?
        int digits0000 = hhhh0000.Digits_IfChain();
        int digitsFFFF = hhhhFFFF.Digits_IfChain();

        // If same number of decimal digits, we know that when we see that hiword
        // we don't have to look at the loword to know the right answer.
        if(digits0000 == digitsFFFF)
        {
            _hhhhXXXXdigits[hhhh] = (sbyte)digits0000;
        }
        else
        {
            bool negative = hhhh >= 0x8000;

            // Calculate 10, 100, 1000, 10000 etc
            int tenToThePower = (int)Math.Pow(10, (negative ? digits0000 : digitsFFFF) - 1);

            // Calculate the loword of the 10^n value.
            ushort lowordSplit = unchecked((ushort)tenToThePower);
            if(negative)
                lowordSplit = unchecked((ushort)(2 + (ushort)~lowordSplit));

            // Store the split point and digits into these arrays
            _lowordSplits[b] = lowordSplit;
            _lowordSplitDigitsLT[b] = (sbyte)digits0000;
            _lowordSplitDigitsGE[b] = (sbyte)digitsFFFF;

            // Store the minus of the array index into the digits lookup. We look for
            // minus values and use these to trigger using the split points logic.
            _hhhhXXXXdigits[hhhh] = (sbyte)(-b);
            b++;
        }
    }
}

private static void precomputePositiveLo16()
{
    for(int i = 0; i <= 9; i++)
        _0000llll[i] = 1;

    for(int i = 10; i <= 99; i++)
        _0000llll[i] = 2;

    for(int i = 100; i <= 999; i++)
        _0000llll[i] = 3;

    for(int i = 1000; i <= 9999; i++)
        _0000llll[i] = 4;

    for(int i = 10000; i <= 65535; i++)
        _0000llll[i] = 5;
}

private static void precomputeNegativeLo16()
{
    for(int i = 0; i <= 9; i++)
        _FFFFllll[65536 - i] = 1;

    for(int i = 10; i <= 99; i++)
        _FFFFllll[65536 - i] = 2;

    for(int i = 100; i <= 999; i++)
        _FFFFllll[65536 - i] = 3;

    for(int i = 1000; i <= 9999; i++)
        _FFFFllll[65536 - i] = 4;

    for(int i = 10000; i <= 65535; i++)
        _FFFFllll[65536 - i] = 5;
}



public static int Digits_LookupTable(this int n)
{
    // Split input into low word and high word.
    ushort l = unchecked((ushort)n);
    ushort h = unchecked((ushort)(n >> 16));

    // If the hiword is 0000 or FFFF we have precomputed tables for these.
    if(h == 0x0000)
    {
        return _0000llll[l];
    }
    else if(h == 0xFFFF)
    {
        return _FFFFllll[l];
    }

    // In most cases the hiword will tell us the number of decimal digits.
    sbyte digits = _hhhhXXXXdigits[h];

    // We put a positive number in this lookup table when
    // hhhh0000 .. hhhhFFFF all have the same number of decimal digits.
    if(digits > 0)
        return digits;

    // Where the answer is different for hhhh0000 to hhhhFFFF, we need to
    // look up in a separate array to tell us at what loword the change occurs.
    var splitIndex = (sbyte)(-digits);

    ushort lowordSplit = _lowordSplits[splitIndex];

    // Pick the correct answer from the relevant array, depending whether
    // our loword is lower than the split point or greater/equal. Note that for
    // negative numbers, the loword is LOWER for MORE decimal digits.
    if(l < lowordSplit)
        return _lowordSplitDigitsLT[splitIndex];
    else
        return _lowordSplitDigitsGE[splitIndex];
}

বাইনারি অনুসন্ধান সংস্করণ

        public static int Digits_BinarySearch(this int n)
        {
            if(n >= 0)
            {
                if(n <= 9999) // 0 .. 9999
                {
                    if(n <= 99) // 0 .. 99
                    {
                        return (n <= 9) ? 1 : 2;
                    }
                    else // 100 .. 9999
                    {
                        return (n <= 999) ? 3 : 4;
                    }
                }
                else // 10000 .. int.MaxValue
                {
                    if(n <= 9_999_999) // 10000 .. 9,999,999
                    {
                        if(n <= 99_999)
                            return 5;
                        else if(n <= 999_999)
                            return 6;
                        else
                            return 7;
                    }
                    else // 10,000,000 .. int.MaxValue
                    {
                        if(n <= 99_999_999)
                            return 8;
                        else if(n <= 999_999_999)
                            return 9;
                        else
                            return 10;
                    }
                }
            }
            else
            {
                if(n >= -9999) // -9999 .. -1
                {
                    if(n >= -99) // -99 .. -1
                    {
                        return (n >= -9) ? 1 : 2;
                    }
                    else // -9999 .. -100
                    {
                        return (n >= -999) ? 3 : 4;
                    }
                }
                else // int.MinValue .. -10000
                {
                    if(n >= -9_999_999) // -9,999,999 .. -10000
                    {
                        if(n >= -99_999)
                            return 5;
                        else if(n >= -999_999)
                            return 6;
                        else
                            return 7;
                    }
                    else // int.MinValue .. -10,000,000 
                    {
                        if(n >= -99_999_999)
                            return 8;
                        else if(n >= -999_999_999)
                            return 9;
                        else
                            return 10;
                    }
                }
            }
        }

        Stopwatch sw0 = new Stopwatch();
        sw0.Start();
        for(int i = 0; i < size; ++i) samples[i].Digits_BinarySearch();
        sw0.Stop();
        Console.WriteLine($"Binary-Search: {sw0.ElapsedMilliseconds} ms");

খুব আকর্ষণীয় পদ্ধতির। এটি "লগ 10", "স্ট্রিং। দৈর্ঘ্য" এবং অভিন্ন বিতরণকৃত পূর্ণসংখ্যার মানগুলির জন্য "যখন" পদ্ধতিগুলির চেয়ে সত্যই দ্রুত। বাস্তব ক্ষেত্রে পরিস্থিতিতে, পূর্ণসংখ্যার মানগুলির বন্টনকে সর্বদা if-চেনের মতো সমাধানগুলিতে বিবেচনা করা উচিত। +1
সুনুন ןɐ কিউপি

লুকআপ টেবিলটি এমন দৃশ্যের জন্য খুব দ্রুত বলে মনে হচ্ছে যেখানে মেমরির অ্যাক্সেস বাধা নয়। আমি দৃ strongly়ভাবে বিশ্বাস করি যে ঘন ঘন মেমরির অ্যাক্সেস সহ দৃশ্যের জন্য, লুকআপটি আপনার প্রস্তাবিত বিন অনুসন্ধানের মতো চেইন-জাতীয় পদ্ধতিগুলির চেয়ে ধীর হয়ে যায়। যাইহোক, আপনার কি Int64লুকআপের জন্য বাস্তবায়ন আছে ? অথবা আপনি কি মনে করেন এটি কার্যকর করা খুব জটিল? আমি পুরো সেট পরে পারফরম্যান্স পরীক্ষা চালাতে চাই।
সানুন ןɐ কিউপি

আরে, 64-বিট এক হিসাবে পাওয়া যায় নি। নীতিটি কিছুটা আলাদা হতে হবে যে আপনার কেবলমাত্র উচ্চতর শব্দ এবং নিম্নচাপের চেয়ে 4x স্তর প্রয়োজন। নিশ্চিতভাবেই সম্মত হন যে সত্যিকারের বিশ্বে আপনার সিপিইউ ক্যাশে জায়গার জন্য প্রচুর পরিমাণে অন্যান্য প্রতিযোগিতামূলক প্রয়োজনীয়তা থাকবে এবং দেখার আকার কমানোর ক্ষেত্রে উন্নতির অনেক জায়গা রয়েছে (>> 1 তারপরেও কেবল সংখ্যাগুলি কেবল মাথায় আসে) । আপনার র্যান্ডম ডেটা সেট বিতরণ করে বাইনারি অনুসন্ধানটি 1,2,3,4 এর পরিবর্তে 9,10,8 ডিজিটের দিকে বায়সিং করে উন্নত করা যেতে পারে -
অ্যালান সিঙ্গফিল্ড

1

একটি সংখ্যাকে 10 দ্বারা বিভক্ত করা আপনাকে বাম সর্বাধিক অঙ্ক দেবে তারপরে সংখ্যায় একটি মোড 10 করা প্রথম সংখ্যা ছাড়াই নম্বর দেয় এবং পুনরাবৃত্তি করে যে আপনার সমস্ত সংখ্যা না হওয়া পর্যন্ত


0
int i = 855865264;
int NumLen = i.ToString().Length;

2
নেতিবাচক int এর জন্য এবং 23.00 এর মতো সংখ্যার জন্য ব্যর্থ হয়। আরও string.TrimStart('-')ভাল করুন
নওফাল

0

এমন একটি পদ্ধতি তৈরি করুন যা সমস্ত অঙ্কগুলি ফেরত দেয় এবং অন্য একটি যা তাদের গণনা করে:

public static int GetNumberOfDigits(this long value)
{
    return value.GetDigits().Count();
}

public static IEnumerable<int> GetDigits(this long value)
{
    do
    {
        yield return (int)(value % 10);
        value /= 10;
    } while (value != 0);
}

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

আমি দেখতে দেখতে ifকিছুটা কুৎসিত করার জন্য অন্য উত্তরে প্রস্তাবিত-চেইনটিও পেয়েছি ।

আমি জানি এটি সর্বাধিক দক্ষ পদ্ধতি নয় তবে এটি আপনাকে অন্যান্য ব্যবহারের জন্য অঙ্কগুলি ফেরত দেওয়ার জন্য অন্যান্য এক্সটেনশন দেয় (আপনি privateযদি শ্রেণীর বাইরে এটি ব্যবহার না করে থাকেন তবে আপনি এটি চিহ্নিত করতে পারেন)।

মনে রাখবেন যে এটি negativeণাত্মক চিহ্নটিকে একটি সংখ্যা হিসাবে বিবেচনা করে না।


-2

স্ট্রিংয়ে রূপান্তর করুন এবং তারপরে আপনি। দৈর্ঘ্যের পদ্ধতিতে টেটাল নম্বরের সংখ্যা গণনা করতে পারেন। ভালো লেগেছে:

String numberString = "855865264".toString();
int NumLen = numberString .Length;

1
স্ট্রিং বরাদ্দ করা সম্পূর্ণ অপ্রয়োজনীয়।
ক্রিথিক

-2

এটি নির্ভর করে যে আপনি অঙ্কগুলির সাথে ঠিক কী করতে চান। আপনি সর্বশেষ থেকে শুরু করে প্রথমটির মতো অঙ্কগুলির মাধ্যমে পুনরাবৃত্তি করতে পারেন:

int tmp = number;
int lastDigit = 0;
do
{
    lastDigit = tmp / 10;
    doSomethingWithDigit(lastDigit);
    tmp %= 10;
} while (tmp != 0);

1
আপনার যুক্তি বিপরীত। ডিজিটটি %পেতে আপনাকে এটি ব্যবহার করতে হবে এবং তারপরে /=এটি কেটে ফেলতে হবে।
জুলাইলেগন


-3

ধরে নিচ্ছি আপনার প্রশ্নটি কোনও আন্তঃকে নির্দেশ করছে, নিম্নলিখিতটি নেতিবাচক / ধনাত্মক এবং শূন্যের জন্যও কাজ করে:

Math.Floor((decimal) Math.Abs(n)).ToString().Length
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.