সি ++ পারফরম্যান্স চ্যালেঞ্জ: স্ট্যান্ড :: স্ট্রিং রূপান্তরটির পূর্ণসংখ্যা


123

নীচের লিঙ্ক করা কি কেউ আমার পূর্ণসংখ্যার স্ট্যান্ডিং :: স্ট্রিং কোডের পারফরম্যান্সকে মারতে পারে?

ইতিমধ্যে বেশ কয়েকটি প্রশ্ন রয়েছে যা ব্যাখ্যা করে যে কীভাবে একটি পূর্ণসংখ্যাটিকে std::stringসি ++ তে রূপান্তর করতে হয় , যেমন এই একটি , তবে প্রদত্ত সমাধানগুলির কোনওটিই কার্যকর নয়।

প্রতিযোগিতা করার জন্য কয়েকটি সাধারণ পদ্ধতির জন্য এখানে সংকলিত-প্রস্তুত কোডটি দেওয়া হল:

  • স্ট্রিংস্ট্রিম ব্যবহার করে "সি ++ উপায়": http://ideone.com/jh3Sa
  • স্প্রিন্টফ, যা SO-এর সাধারণত সম্পাদন সচেতনতার জন্য সুপারিশ করে: http://ideone.com/82kwR

জনপ্রিয় বিশ্বাসের বিপরীতে , boost::lexical_castএর নিজস্ব বাস্তবায়ন রয়েছে ( শ্বেত কাগজ ) stringstreamএবং সংখ্যার সন্নিবেশ অপারেটরগুলি ব্যবহার করে না । আমি এর পারফরম্যান্সের তুলনা দেখতে সত্যিই চাই, কারণ এই অন্যান্য প্রশ্ন থেকেই বোঝা যায় যে এটি দু: খজনক

এবং আমার নিজের অবদান, যা ডেস্কটপ কম্পিউটারগুলিতে প্রতিযোগিতামূলক এবং এমন একটি পদ্ধতির প্রদর্শন করে যা এম্বেডড সিস্টেমে পুরো গতিতে চলে, পূর্ণসংখ্যার মডুলোর উপর নির্ভরশীল অ্যালগরিদমের বিপরীতে:

আপনি যদি এই কোডটি ব্যবহার করতে চান তবে আমি এটিকে একটি সরলীকৃত BSD লাইসেন্সের অধীনে উপলব্ধ করব (বাণিজ্যিক ব্যবহারের অনুমতি দেওয়া হয়েছে, এ্যাট্রিবিউশন আবশ্যক)। জিজ্ঞেস করে দেখুন.

অবশেষে, ফাংশনটি ltoaমানহীন তবে ব্যাপকভাবে উপলব্ধ।

  • ltoa সংস্করণ, যার কাছে একটি সংকলক রয়েছে যা এটি সরবরাহ করে (আদর্শটি তা করে না): http://ideone.com/T5Wim

আমি শীঘ্রই উত্তর হিসাবে আমার কর্মক্ষমতা পরিমাপ পোস্ট করব।

অ্যালগরিদমের জন্য বিধি

  • কমপক্ষে 32-বিট স্বাক্ষরিত এবং স্বাক্ষরযুক্ত স্বাক্ষর দশমিকের পরিবর্তনের জন্য কোড সরবরাহ করুন।
  • ক হিসাবে আউটপুট উত্পাদন std::string
  • থ্রেডিং এবং সিগন্যালের সাথে বেমানান এমন কোনও কৌশল নেই (উদাহরণস্বরূপ, স্ট্যাটিক বাফার)।
  • আপনি একটি ASCII অক্ষর সেট ধরে নিতে পারেন।
  • INT_MINদু'জনের পরিপূরক মেশিনে আপনার কোডটি পরীক্ষা করে নেওয়ার বিষয়টি নিশ্চিত করুন যেখানে নিখুঁত মানটি উপস্থাপনযোগ্য নয়।
  • আদর্শভাবে, আউটপুটটি ক্যানোনিকাল সি ++ সংস্করণ stringstream, http://ideone.com/jh3Sa ব্যবহার করে চরিত্রের জন্য চরিত্রের মতো হওয়া উচিত তবে সঠিক নম্বর হিসাবে স্পষ্টভাবে বোধগম্য এমন কোনও কিছুই ঠিক আছে।
  • নতুন : যদিও আপনি তুলনার জন্য যা চান সংকলক এবং অপ্টিমাইজার বিকল্পগুলি (সম্পূর্ণ অক্ষম ব্যতীত) ব্যবহার করতে পারেন, কোডটি কমপক্ষে ভিসি ++ ২০১০ এবং জি ++ এর অধীনে সঠিক সংকলন এবং সঠিক ফলাফলও দেওয়া দরকার।

আশা-আলোচনার জন্য

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

উপসংহার:

বিভিন্ন অ্যালগরিদমগুলি g ++ এবং VC2010 এর জন্য সঞ্চালিত হয়, সম্ভবত প্রতিটিটির বিভিন্ন বাস্তবায়নের কারণে std::string। ভিসি 2010 স্পষ্টতই এনআরভিওর সাথে আরও ভাল কাজ করে, কেবলমাত্র জিসিসিতে রিটার্ন-বাই-ভ্যালু থেকে মুক্তি পেয়ে।

কোডটি পাওয়া গেছে যে sprintfপ্রস্থের আদেশ দ্বারা ছাপিয়ে গেছে । ostringstream50 এবং আরও বেশি একটি ফ্যাক্টর দ্বারা পিছনে পড়ে।

চ্যালেঞ্জটির বিজয়ী ব্যবহারকারীর নাম 344507 যিনি এমন কোড তৈরি করেন যা জিসিসিতে আমার নিজের গতির 350% রান করে। এসও সম্প্রদায়ের ঝাঁকুনির কারণে আরও এন্ট্রিগুলি বন্ধ রয়েছে।

বর্তমান (চূড়ান্ত?) গতির চ্যাম্পিয়নরা হ'ল:

  • জিসিসি: ব্যবহারকারীর জন্য 3445050, এর চেয়ে 8 গুণ বেশি দ্রুত sprintf: http://ideone.com/0uhhX
  • ভিজ্যুয়াল সি ++ এর জন্য: টিমো, এর চেয়ে 15 গুণ বেশি দ্রুত sprintf: http://ideone.com/VpKO3

5
আমি মনে করি এই "প্রশ্ন" এখানে আরও ভাল ফিট করে প্রোগ্রামার্স.স্ট্যাকেক্সচেঞ্জ.কম
জুয়ারো

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

7
আমি এই প্রশ্নটি পুনরায় খোলার পক্ষে ভোট দিয়েছি, এটি বন্ধ হওয়ার কোনও কারণ নেই।
কুকুরছানা

4
এই প্রশ্নে, আদর্শ লিঙ্কগুলি বেশিরভাগ মৃত। আপনি দয়া করে কোডটি আরও নির্ভরযোগ্য কোথাও অন্তর্ভুক্ত করবেন?
nhahtdh

6
@ বেনভয়েট আমিও এটিই জিজ্ঞাসা করব। লিঙ্কগুলি সমস্ত মারা গেছে। আমি এগুলি আরও ঘনিষ্ঠভাবে দেখে নিতে চাই
ম্যান্ড

উত্তর:


33
#include <string>

const char digit_pairs[201] = {
  "00010203040506070809"
  "10111213141516171819"
  "20212223242526272829"
  "30313233343536373839"
  "40414243444546474849"
  "50515253545556575859"
  "60616263646566676869"
  "70717273747576777879"
  "80818283848586878889"
  "90919293949596979899"
};


std::string& itostr(int n, std::string& s)
{
    if(n==0)
    {
        s="0";
        return s;
    }

    int sign = -(n<0);
    unsigned int val = (n^sign)-sign;

    int size;
    if(val>=10000)
    {
        if(val>=10000000)
        {
            if(val>=1000000000)
                size=10;
            else if(val>=100000000)
                size=9;
            else 
                size=8;
        }
        else
        {
            if(val>=1000000)
                size=7;
            else if(val>=100000)
                size=6;
            else
                size=5;
        }
    }
    else 
    {
        if(val>=100)
        {
            if(val>=1000)
                size=4;
            else
                size=3;
        }
        else
        {
            if(val>=10)
                size=2;
            else
                size=1;
        }
    }
    size -= sign;
    s.resize(size);
    char* c = &s[0];
    if(sign)
        *c='-';

    c += size-1;
    while(val>=100)
    {
       int pos = val % 100;
       val /= 100;
       *(short*)(c-1)=*(short*)(digit_pairs+2*pos); 
       c-=2;
    }
    while(val>0)
    {
        *c--='0' + (val % 10);
        val /= 10;
    }
    return s;
}

std::string& itostr(unsigned val, std::string& s)
{
    if(val==0)
    {
        s="0";
        return s;
    }

    int size;
    if(val>=10000)
    {
        if(val>=10000000)
        {
            if(val>=1000000000)
                size=10;
            else if(val>=100000000)
                size=9;
            else 
                size=8;
        }
        else
        {
            if(val>=1000000)
                size=7;
            else if(val>=100000)
                size=6;
            else
                size=5;
        }
    }
    else 
    {
        if(val>=100)
        {
            if(val>=1000)
                size=4;
            else
                size=3;
        }
        else
        {
            if(val>=10)
                size=2;
            else
                size=1;
        }
    }

    s.resize(size);
    char* c = &s[size-1];
    while(val>=100)
    {
       int pos = val % 100;
       val /= 100;
       *(short*)(c-1)=*(short*)(digit_pairs+2*pos); 
       c-=2;
    }
    while(val>0)
    {
        *c--='0' + (val % 10);
        val /= 10;
    }
    return s;
}

এটি এমন সিস্টেমগুলিতে ফুঁসে উঠবে যা স্বাক্ষরবিহীন মেমরির অ্যাক্সেসগুলি অস্বীকার করে (এই ক্ষেত্রে, প্রথম স্বাক্ষরিত অ্যাসাইনমেন্টটি সেগফাল্টের *(short*)কারণ হতে পারে), তবে অন্যথায় খুব সুন্দরভাবে কাজ করা উচিত।

একটি গুরুত্বপূর্ণ জিনিস হ'ল ব্যবহারকে হ্রাস করা std::string। (অলৌকিক, আমি জানি)) ভিজ্যুয়াল স্টুডিওতে, উদাহরণস্বরূপ, std :: স্ট্রিংয়ের পদ্ধতিগুলির বেশিরভাগ কলগুলি ইনল্যান্ডার করা হয় না, আপনি সংকলক বিকল্পগুলিতে / ওবি 2 নির্দিষ্ট করে দিলেও। এমনকি কলটির মতো তুচ্ছ কিছু std::string::clear(), যা আপনি খুব দ্রুত বলে আশা করতে পারেন, সিআরটিকে একটি স্ট্যাটিক লাইব্রেরি হিসাবে সংযুক্ত করার সময় 100 টি ক্লকটিক নিতে পারে এবং ডিএলএল হিসাবে সংযোগ করার সময় 300 টি ক্লকটিক নিতে পারে।

একই কারণে, রেফারেন্সের মাধ্যমে ফেরত দেওয়া ভাল কারণ এটি একটি কার্যনির্বাহী, একজন নির্মাতা এবং একটি ডেস্ট্রাক্টর এড়ায়।


আপনার চেষ্টার জন্য ধন্যবাদ। আইডিয়নে ( আইডিয়োনা / বিবিসিপি 5 আর ), এটি 18.5 এমবি / সেকেন্ড করে, এর গতি প্রায় অর্ধেক sprintf। এবং ভিসি ++ ২০১০ এর সাথে এটি স্প্রিন্টফের প্রায় দ্বিগুণ গতিবেগ প্রায় 50 এমবি / সেকেন্ড পায়।
বেন ভয়েগট

এমবি / এস হ'ল একটি অদ্ভুত মেট্রিক, বিশেষত আপনি কীভাবে আপনার প্রয়োগের স্ট্রিং থেকে পেছনের শ্বেত স্থানগুলি সরিয়ে ফেলেন না তা দেখে। আমার আপডেট কোডটি কোড i7 920 (16.2M ops / s বনাম 14.8M ops / s) এর x64 ভিসি ++ 2005 এর সাথে আপনার প্রয়োগের চেয়ে দ্রুত গতিতে চলেছে, _ltoa 8.5M অপ্স / সে এবং স্প্রিন্টফ () 3.85M অপ্স / গুলি করে।
ইউজিন স্মিথ

আপনার কোডটি স্ট্রিংকে যথাযথ আকার পরিবর্তন করতে পারে না, আমারটি করে (81, 198 এবং 290 লাইন দেখুন)। আমি sprintfবাস্তবায়নে কিছু শর্টকাট নিয়েছি, আমি ইতিমধ্যে আমার প্রশ্নে এটি উল্লেখ করেছি, তবে আমি বিশ্বাস করি যে কোড-টু-বিট স্ট্রিং স্ট্রিমের মতো ঠিক একই ফলাফল দেয়।
বেন ভয়েগট

sprintfবিভ্রান্তি এড়াতে আমি মোড়ক ঠিক করেছি ।
বেন ভয়েগট

বিটিডাব্লু , আপনার উন্নত সংস্করণ ( আইডিয়োনা / জিএলএবিএস ) আইডিয়নে ৪১..7 এমবি / সেকেন্ড পেয়েছে, এবং ভিসি ++ ২০১২ 32-বিটে প্রায় 120 এমবি / সেকেন্ডের দিকে।
বেন ভয়েগট

21

আহ্, দারুণ চ্যালেঞ্জ ... আমি এর সাথে অনেক মজা করেছি।

আমার কাছে জমা দেওয়ার জন্য দুটি অ্যালগরিদম রয়েছে (আপনি যদি এটিকে এড়াতে চান তবে কোডটি নীচে রয়েছে)। আমার তুলনাগুলিতে আমার প্রয়োজন যে ফাংশনটি কোনও স্ট্রিং ফিরিয়ে দেয় এবং এটি ইনট এবং স্বাক্ষরবিহীন কোনটি হ্যান্ডেল করতে পারে। এমন জিনিসগুলির সাথে তুলনা করা যা সত্যিকার অর্থে বোঝায় না এমনগুলির সাথে স্ট্রিং তৈরি করে না।

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

আমার মনে হয় এমএসভিসির কিছু ফলাফল খুব ভাল কেন আমি জানি। std :: স্ট্রিংয়ের দুটি প্রাসঙ্গিক কনস্ট্রাক্টর রয়েছে std::string(char* str, size_t n)
এবং
std::string(ForwardIterator b, ForwardIterator e)
জিসিসি তাদের উভয়ের জন্য একই কাজ করে ... এটি প্রথমটি প্রয়োগ করতে দ্বিতীয়টি ব্যবহার করে। প্রথম কনস্ট্রাক্টর এর চেয়ে উল্লেখযোগ্যভাবে আরও দক্ষতার সাথে প্রয়োগ করা যেতে পারে এবং এমএসভিসি তা করে। এর পার্শ্ব সুবিধাটি হ'ল কিছু ক্ষেত্রে (আমার ফাস্ট কোড এবং টিমোর কোডের মতো) স্ট্রিং কনস্ট্রাক্টর ইনলাইন করা যেতে পারে। আসলে, এমএসভিসিতে এই কনস্ট্রাক্টরগুলির মধ্যে স্যুইচ করা আমার কোডের জন্য প্রায় 2x পার্থক্য।

আমার কর্মক্ষমতা পরীক্ষার ফলাফল:

কোড সূত্র:

- Voigt
- টিমো
- ergosys
- user434507
- ব্যবহারকারী-voigt-Timo
- hopman-মজা
- hopman-ফাস্ট

উবুন্টু 10.10 64-বিটে জিসিসি 4.4.5 -O2, কোর আই 5

হপম্যান_ফুন: 124.688 এমবি / সেকেন্ড --- 8.020 এস
হপম্যান_ফেস: 137.552 এমবি / সেকেন্ড --- 7.270 এস
ভয়েগট: 120.192 এমবি / সেকেন্ড --- 8.320 এস
ব্যবহারকারী_ভ্যাগট_টিমো: 97.9432 এমবি / সেকেন্ড --- 10.210 এস
টিমো: 120.482 এমবি / সেকেন্ড --- 8.300 এস
ব্যবহারকারী: 97.7517 এমবি / সেকেন্ড --- 10.230 এস
এরগোসিস: 101.42 এমবি / সেকেন্ড --- 9.860 এস

এমএসভিসি 2010 64-বিট / উইন্ডোজ 7 64-বিটে অক্স, কোর আই 5

হপম্যান_ফুন: 127 এমবি / সেকেন্ড --- 7.874 এস
হপম্যান_ফেলা: 259 এমবি / সেকেন্ড --- 3.861 এস
ভয়েগট: 221.435 এমবি / সেকেন্ড --- 4.516 এস
ব্যবহারকারী_ভ্যাজিট_টিমো: 195.695 এমবি / সেকেন্ড --- 5.110 এস
টিমো: 253.165 এমবি / সেকেন্ড --- 3.950 এস
ব্যবহারকারী: 212.63 এমবি / সেকেন্ড --- 4.703 এস
এরগোসিস: 78.0518 এমবি / সেকেন্ড --- 12.812 এস

আইডিয়োন
http://ideone.com/XZRqp এ এখানে কিছু ফলাফল এবং একটি পরীক্ষার / সময় কাঠামো রয়েছে তা
নোট করুন যে আদর্শ একটি 32-বিট পরিবেশ। আমার উভয় অ্যালগরিদম এ থেকে ভোগে তবে হপম্যান_ফেষ্ট অন্তত এখনও প্রতিযোগিতামূলক।

মনে রাখবেন যে দু'টি বা তার জন্য যাতে কোনও স্ট্রিং তৈরি না করে আমি নিম্নলিখিত ফাংশন টেম্পলেটটি যুক্ত করেছি:

template <typename T>
std::string itostr(T t) {
    std::string ret;
    itostr(t, ret);
    return ret;
}

এখন আমার কোডের জন্য ... প্রথমে একটি মজাদার:

    // hopman_fun

template <typename T> 
T reduce2(T v) {
    T k = ((v * 410) >> 12) & 0x000F000F000F000Full;
    return (((v - k * 10) << 8) + k);
}

template <typename T>
T reduce4(T v) {
    T k = ((v * 10486) >> 20) & 0xFF000000FFull;
    return reduce2(((v - k * 100) << 16) + (k));
}

typedef unsigned long long ull;
inline ull reduce8(ull v) {
    ull k = ((v * 3518437209u) >> 45);
    return reduce4(((v - k * 10000) << 32) + (k));
}

template <typename T>
std::string itostr(T o) {
    union {
        char str[16];
        unsigned short u2[8];
        unsigned u4[4];
        unsigned long long u8[2];
    };

    unsigned v = o < 0 ? ~o + 1 : o;

    u8[0] = (ull(v) * 3518437209u) >> 45;
    u8[0] = (u8[0] * 28147497672ull);
    u8[1] = v - u2[3] * 100000000;

    u8[1] = reduce8(u8[1]);
    char* f;
    if (u2[3]) {
        u2[3] = reduce2(u2[3]);
        f = str + 6;
    } else {
        unsigned short* k = u4[2] ? u2 + 4 : u2 + 6;
        f = *k ? (char*)k : (char*)(k + 1);
    }
    if (!*f) f++;

    u4[1] |= 0x30303030;
    u4[2] |= 0x30303030;
    u4[3] |= 0x30303030;
    if (o < 0) *--f = '-';
    return std::string(f, (str + 16) - f);
}

এবং তারপরে দ্রুত:

    // hopman_fast

struct itostr_helper {
    static unsigned out[10000];

    itostr_helper() {
        for (int i = 0; i < 10000; i++) {
            unsigned v = i;
            char * o = (char*)(out + i);
            o[3] = v % 10 + '0';
            o[2] = (v % 100) / 10 + '0';
            o[1] = (v % 1000) / 100 + '0';
            o[0] = (v % 10000) / 1000;
            if (o[0]) o[0] |= 0x30;
            else if (o[1] != '0') o[0] |= 0x20;
            else if (o[2] != '0') o[0] |= 0x10;
            else o[0] |= 0x00;
        }
    }
};
unsigned itostr_helper::out[10000];

itostr_helper hlp_init;

template <typename T>
std::string itostr(T o) {
    typedef itostr_helper hlp;

    unsigned blocks[3], *b = blocks + 2;
    blocks[0] = o < 0 ? ~o + 1 : o;
    blocks[2] = blocks[0] % 10000; blocks[0] /= 10000;
    blocks[2] = hlp::out[blocks[2]];

    if (blocks[0]) {
        blocks[1] = blocks[0] % 10000; blocks[0] /= 10000;
        blocks[1] = hlp::out[blocks[1]];
        blocks[2] |= 0x30303030;
        b--;
    }

    if (blocks[0]) {
        blocks[0] = hlp::out[blocks[0] % 10000];
        blocks[1] |= 0x30303030;
        b--;
    }

    char* f = ((char*)b);
    f += 3 - (*f >> 4);

    char* str = (char*)blocks;
    if (o < 0) *--f = '-';
    return std::string(f, (str + 12) - f);
}


আমি বুঝতে পারি না প্রথমটি কীভাবে মন্তব্য দিয়েও কাজ করে। : ডি দ্রুততমটি সত্যিই দুর্দান্ত, যদিও এর স্মৃতি ব্যবহারে এর দাম রয়েছে। তবে আমার ধারণা 40 কেবি এখনও গ্রহণযোগ্য। আমি 4 টি চরিত্রের গ্রুপও ব্যবহার করতে আমার নিজের কোডটি সংশোধন করেছি এবং একই গতি পেয়েছি। আইডোন.কম
টিমো

Uint64_t এর সাথে কাজ করা কি এটি সংশোধন করা কঠিন হবে? আমি এই কোডটি সি-তে স্থানান্তরিত করেছি এবং 'টি' -কে ইনট টাইপের সাথে প্রতিস্থাপন করেছি এবং এটি কাজ করে, তবে এটি uint64_t এর জন্য কাজ করে না এবং কীভাবে এটি কাস্টমাইজ করা যায় তা সম্পর্কে আমার কোনও ধারণা নেই।
পিবিএন

11

প্রশ্নে প্রদত্ত কোডটির জন্য বেঞ্চমার্কের ডেটা:

আইডিয়নে (জিসিসি 4.3.4):

কোর আই 7, উইন্ডোজ 7 64-বিট, 8 জিবি র‌্যাম, ভিজ্যুয়াল সি ++ 2010 32-বিট:

cl /Ox /EHsc

  • স্ট্রিং স্ট্রিমস: 3.39 এমবি / গুলি, 3.67 এমবি / সে
  • স্প্রিন্টফ: 16.8 এমবি / সে, 16.2 এমবি / সে
  • খনি: 194 এমবি / সে, 207 এমবি / গুলি (পিজিও সক্ষম সহ: 250 এমবি / গুলি)

কোর আই 7, উইন্ডোজ 7 64-বিট, 8 জিবি র‌্যাম, ভিজ্যুয়াল সি ++ 2010 64-বিট:

cl /Ox /EHsc

  • স্ট্রিং স্ট্রিমস: 4.42 এমবি / সেকেন্ড, 4.92 এমবি / সে
  • স্প্রিন্টফ: 21.0 এমবি / সেকেন্ড, 20.8 এমবি / সে
  • আমার: 238 এমবি / সে, 228 এমবি / সে

কোর আই 7, উইন্ডোজ 7 64-বিট, 8 জিবি র‌্যাম, সিগুইন জিসিসি 4.3.4:

g++ -O3

  • স্ট্রিং স্ট্রিমস: ২.১৯ মেগাবাইট / সে, ২.১17 এমবি / সে
  • স্প্রিন্টফ: ১৩.১ এমবি / সে, ১৩.৪ এমবি / সে
  • আমার: 30.0 এমবি / গুলি, 30.2 এমবি / সে

সম্পাদনা : আমি আমার নিজের উত্তর যুক্ত করছিলাম, তবে প্রশ্নটি বন্ধ ছিল তাই আমি এটি এখানে যুক্ত করছি। :) আমি আমার নিজস্ব অ্যালগরিদম লিখেছি এবং বেনের কোডের তুলনায় একটি ভাল উন্নতি অর্জন করতে সক্ষম হয়েছি, যদিও আমি এটি কেবল এমএসভিসি ২০১০-তে পরীক্ষা করেছি Ben বেনের মূলটিতে একই পরীক্ষার সেটআপ ব্যবহার করে আমি এখনও অবধি উপস্থাপিত সমস্ত বাস্তবায়নের একটি মানদণ্ড তৈরি করেছি কোড। - টিমো

ইন্টেল Q9450, উইন এক্সপি 32 বিট, এমএসভিসি 2010

cl /O2 /EHsc

  • স্ট্রিংস্ট্রিম: ২.8787 এমবি / সে
  • স্প্রিন্টফ: 16.1 এমবি / সে
  • বেন: 202 এমবি / সে
  • বেন (স্বাক্ষরযুক্ত বাফার): 82.0 এমবি / সে
  • এরগোসিস (আপডেট হওয়া সংস্করণ): .2৪.২ এমবি / এস
  • ব্যবহারকারী434507: 172 এমবি / সে
  • টিমো: 241 এমবি / সে

-

const char digit_pairs[201] = {
  "00010203040506070809"
  "10111213141516171819"
  "20212223242526272829"
  "30313233343536373839"
  "40414243444546474849"
  "50515253545556575859"
  "60616263646566676869"
  "70717273747576777879"
  "80818283848586878889"
  "90919293949596979899"
};

static const int BUFFER_SIZE = 11;

std::string itostr(int val)
{
  char buf[BUFFER_SIZE];
  char *it = &buf[BUFFER_SIZE-2];

  if(val>=0) {
    int div = val/100;
    while(div) {
      memcpy(it,&digit_pairs[2*(val-div*100)],2);
      val = div;
      it-=2;
      div = val/100;
    }
    memcpy(it,&digit_pairs[2*val],2);
    if(val<10)
      it++;
  } else {
    int div = val/100;
    while(div) {
      memcpy(it,&digit_pairs[-2*(val-div*100)],2);
      val = div;
      it-=2;
      div = val/100;
    }
    memcpy(it,&digit_pairs[-2*val],2);
    if(val<=-10)
      it--;
    *it = '-';
  }

  return std::string(it,&buf[BUFFER_SIZE]-it);
}

std::string itostr(unsigned int val)
{
  char buf[BUFFER_SIZE];
  char *it = (char*)&buf[BUFFER_SIZE-2];

  int div = val/100;
  while(div) {
    memcpy(it,&digit_pairs[2*(val-div*100)],2);
    val = div;
    it-=2;
    div = val/100;
  }
  memcpy(it,&digit_pairs[2*val],2);
  if(val<10)
    it++;

  return std::string((char*)it,(char*)&buf[BUFFER_SIZE]-(char*)it);
}

এই ইনফোগুলির জন্য ধন্যবাদ, দয়া করে জিসিসির গতি সম্পর্কে ব্যাখ্যা করুন! এটি খুব কম :(
Behrouz.M

@ বেহরুজ: আসলেই। আমি ঠিক নিশ্চিত না কেন জিসিসি এত ধীর, এটি গিসিটির সংস্করণ std::stringবা পাটিগণিত কোডটির দুর্বল অপ্টিমাইজেশন কিনা । আমি অন্য একটি সংস্করণ তৈরি করব std::stringযা শেষে রূপান্তরিত হবে না এবং জিসিসি ভাড়া আরও ভাল কিনা তা দেখুন।
বেন ভয়েগট

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

আমি মনে করি আপনার এমন একটি সংস্করণ যুক্ত করা উচিত যা স্টাড :: স্ট্রিংয়ে রূপান্তর না করে। কোডের কেবল একটি লাইন পরিবর্তন করে ফাংশনটি আমার মেশিনে আধা সময়ের মধ্যে জিসিসি ব্যবহার করে চলে। এবং std :: স্ট্রিং সরিয়ে লোকেরা সি প্রোগ্রামের ভিতরে এই ফাংশনটি ব্যবহার করতে সক্ষম হবে।
ব্যবহারকারীর 1593842

11

অ্যালগরিদমের জন্য আমরা এখানে যে তথ্য পেয়েছি তা বেশ সুন্দর হলেও আমি মনে করি প্রশ্নটি "ভাঙ্গা", এবং আমি কেন এটি মনে করি তা ব্যাখ্যা করব:

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

সংক্ষেপে, আমার মনে হয় সময়গুলি বিভক্ত হওয়া উচিত:

  • প্রথম, দ্রুততম (ইনট -> ফিক্সড বাফার) রূপান্তর।
  • দ্বিতীয়ত (স্থির বাফার -> স্টাড :: স্ট্রিং) অনুলিপি করার সময়।
  • তৃতীয়ত, অনুলিপি সংরক্ষণ করতে কীভাবে std :: স্ট্রিং বরাদ্দ সরাসরি বাফার হিসাবে ব্যবহার করা যেতে পারে checking

আইএমএইচও, এই দিকগুলিকে এক সময়ে মিশ্রিত করা উচিত নয়।


3
<quot >> int2string সর্বদা std :: স্ট্রিং থেকে হিপ বরাদ্দের সাথে জড়িত থাকবে </ quot> ছোট স্ট্রিং অপ্টিমাইজেশানের সাথে নয়, এটি স্ট্যান্ডার্ড লাইব্রেরির বেশিরভাগ বর্তমান বাস্তবায়নে উপস্থিত রয়েছে।
বেন ভয়েগট

যদিও শেষ পর্যন্ত, std::stringসমস্ত আবেদনের জন্য জিনিসগুলি সুষ্ঠু এবং সামঞ্জস্যপূর্ণ করার জন্য "আউটপুট হিসাবে " প্রয়োজনীয়তাটি সেখানে রাখা হয়েছিল। std::stringফলাফল তৈরি করতে দ্রুতগতিযুক্ত অ্যালগরিদমগুলি একটি পূর্বনির্ধারিত বাফারটি পূরণ করতে আরও দ্রুত হবে।
বেন ভয়েগট

3
@ বেন - ভাল মন্তব্য। ESP। sm.str.opt। std.string এর পারফরম্যান্স বিচার করার সময় ভবিষ্যতে আমার মনে রাখতে হবে।
মার্টিন বা

6

আমি ভিএস এর অধীনে পরীক্ষা করতে পারছি না, তবে এটি জি ++ এর জন্য আপনার কোডের চেয়ে প্রায় 10% বেশি দ্রুত বলে মনে হচ্ছে। এটি সম্ভবত সুর করা যেতে পারে, নির্বাচিত সিদ্ধান্তের মানগুলি অনুমান। দুঃখিত, দুঃখিত।

typedef unsigned buf_t; 

static buf_t * reduce(unsigned val, buf_t * stp) {
   unsigned above = val / 10000; 
   if (above != 0) {
      stp = reduce(above, stp); 
      val -= above * 10000; 
   }

   buf_t digit  = val / 1000; 
   *stp++ = digit + '0'; 
   val -= digit * 1000; 

   digit  = val / 100; 
   *stp++ = digit + '0'; 
   val -= digit * 100; 

   digit  = val / 10; 
   *stp++ = digit + '0'; 
   val -= digit * 10; 
   *stp++ = val + '0'; 
   return stp; 
}

std::string itostr(int input) {

   buf_t buf[16]; 


   if(input == INT_MIN) {  
      char buf2[16]; 
      std::sprintf(buf2, "%d", input); 
      return std::string(buf2); 
   }

   // handle negative
   unsigned val = input;
   if(input < 0) 
      val = -input;

   buf[0] = '0'; 
   buf_t* endp = reduce(val, buf+1); 
   *endp = 127; 

   buf_t * stp = buf+1; 
   while (*stp == '0') 
      stp++;
   if (stp == endp)
      stp--; 

   if (input < 0) { 
      stp--; 
      *stp = '-'; 
   }
   return std::string(stp, endp); 
}

স্বাক্ষরযুক্ত বৈকল্পিক সহ: আদর্শ one.com/pswq9 । মনে হচ্ছে যে থেকে বাফার টাইপ পরিবর্তন charকরার জন্য unsignedআমার কোডে একটি অনুরূপ গতি উন্নতি উৎপন্ন করে অন্তত জিসিসি / ideone উপর ideone.com/uthKK । আমি আগামীকাল ভিসিতে পরীক্ষা করব।
বেন ভয়েগট

6

ব্যবহারকারী 2985907 এর উত্তর আপডেট হয়েছে ... মোডপ_উফাস্ট ...

Integer To String Test (Type 1)
[modp_ufast]Numbers: 240000000  Total:   657777786      Time:  1.1633sec        Rate:206308473.0686nums/sec
[sprintf] Numbers: 240000000    Total:   657777786      Time: 24.3629sec        Rate:  9851045.8556nums/sec
[karma]   Numbers: 240000000    Total:   657777786      Time:  5.2389sec        Rate: 45810870.7171nums/sec
[strtk]   Numbers: 240000000    Total:   657777786      Time:  3.3126sec        Rate: 72450283.7492nums/sec
[so   ]   Numbers: 240000000    Total:   657777786      Time:  3.0828sec        Rate: 77852152.8820nums/sec
[timo ]   Numbers: 240000000    Total:   657777786      Time:  4.7349sec        Rate: 50687912.9889nums/sec
[voigt]   Numbers: 240000000    Total:   657777786      Time:  5.1689sec        Rate: 46431985.1142nums/sec
[hopman]  Numbers: 240000000    Total:   657777786      Time:  4.6169sec        Rate: 51982554.6497nums/sec
Press any key to continue . . .

Integer To String Test(Type 2)
[modp_ufast]Numbers: 240000000  Total:   660000000      Time:  0.5072sec        Rate:473162716.4618nums/sec
[sprintf] Numbers: 240000000    Total:   660000000      Time: 22.3483sec        Rate: 10739062.9383nums/sec
[karma]   Numbers: 240000000    Total:   660000000      Time:  4.2471sec        Rate: 56509024.3035nums/sec
[strtk]   Numbers: 240000000    Total:   660000000      Time:  2.1683sec        Rate:110683636.7123nums/sec
[so   ]   Numbers: 240000000    Total:   660000000      Time:  2.7133sec        Rate: 88454602.1423nums/sec
[timo ]   Numbers: 240000000    Total:   660000000      Time:  2.8030sec        Rate: 85623453.3872nums/sec
[voigt]   Numbers: 240000000    Total:   660000000      Time:  3.4019sec        Rate: 70549286.7776nums/sec
[hopman]  Numbers: 240000000    Total:   660000000      Time:  2.7849sec        Rate: 86178023.8743nums/sec
Press any key to continue . . .

Integer To String Test (type 3)
[modp_ufast]Numbers: 240000000  Total:   505625000      Time:  1.6482sec        Rate:145610315.7819nums/sec
[sprintf] Numbers: 240000000    Total:   505625000      Time: 20.7064sec        Rate: 11590618.6109nums/sec
[karma]   Numbers: 240000000    Total:   505625000      Time:  4.3036sec        Rate: 55767734.3570nums/sec
[strtk]   Numbers: 240000000    Total:   505625000      Time:  2.9297sec        Rate: 81919227.9275nums/sec
[so   ]   Numbers: 240000000    Total:   505625000      Time:  3.0278sec        Rate: 79266003.8158nums/sec
[timo ]   Numbers: 240000000    Total:   505625000      Time:  4.0631sec        Rate: 59068204.3266nums/sec
[voigt]   Numbers: 240000000    Total:   505625000      Time:  4.5616sec        Rate: 52613393.0285nums/sec
[hopman]  Numbers: 240000000    Total:   505625000      Time:  4.1248sec        Rate: 58184194.4569nums/sec
Press any key to continue . . .

int ufast_utoa10(unsigned int value, char* str)
{
#define JOIN(N) N "0", N "1", N "2", N "3", N "4", N "5", N "6", N "7", N "8", N "9"
#define JOIN2(N) JOIN(N "0"), JOIN(N "1"), JOIN(N "2"), JOIN(N "3"), JOIN(N "4"), \
                 JOIN(N "5"), JOIN(N "6"), JOIN(N "7"), JOIN(N "8"), JOIN(N "9")
#define JOIN3(N) JOIN2(N "0"), JOIN2(N "1"), JOIN2(N "2"), JOIN2(N "3"), JOIN2(N "4"), \
                 JOIN2(N "5"), JOIN2(N "6"), JOIN2(N "7"), JOIN2(N "8"), JOIN2(N "9")
#define JOIN4    JOIN3("0"), JOIN3("1"), JOIN3("2"), JOIN3("3"), JOIN3("4"), \
                 JOIN3("5"), JOIN3("6"), JOIN3("7"), JOIN3("8"), JOIN3("9")
#define JOIN5(N) JOIN(N), JOIN(N "1"), JOIN(N "2"), JOIN(N "3"), JOIN(N "4"), \
                 JOIN(N "5"), JOIN(N "6"), JOIN(N "7"), JOIN(N "8"), JOIN(N "9")
#define JOIN6    JOIN5(), JOIN5("1"), JOIN5("2"), JOIN5("3"), JOIN5("4"), \
                 JOIN5("5"), JOIN5("6"), JOIN5("7"), JOIN5("8"), JOIN5("9")
#define F(N)     ((N) >= 100 ? 3 : (N) >= 10 ? 2 : 1)
#define F10(N)   F(N),F(N+1),F(N+2),F(N+3),F(N+4),F(N+5),F(N+6),F(N+7),F(N+8),F(N+9)
#define F100(N)  F10(N),F10(N+10),F10(N+20),F10(N+30),F10(N+40),\
                 F10(N+50),F10(N+60),F10(N+70),F10(N+80),F10(N+90)
  static const short offsets[] = { F100(0), F100(100), F100(200), F100(300), F100(400),
                                  F100(500), F100(600), F100(700), F100(800), F100(900)};
  static const char table1[][4] = { JOIN("") }; 
  static const char table2[][4] = { JOIN2("") }; 
  static const char table3[][4] = { JOIN3("") };
  static const char table4[][5] = { JOIN4 }; 
  static const char table5[][4] = { JOIN6 };
#undef JOIN
#undef JOIN2
#undef JOIN3
#undef JOIN4
  char *wstr;
  int remains[2];
  unsigned int v2;
  if (value >= 100000000) {
    v2 = value / 10000;
    remains[0] = value - v2 * 10000;
    value = v2;
    v2 = value / 10000;
    remains[1] = value - v2 * 10000;
    value = v2;
    wstr = str;
    if (value >= 1000) {
      *(__int32 *) wstr = *(__int32 *) table4[value];
      wstr += 4;
    } else {
      *(__int32 *) wstr = *(__int32 *) table5[value];
      wstr += offsets[value];
    }
    *(__int32 *) wstr = *(__int32 *) table4[remains[1]];
    wstr += 4;
    *(__int32 *) wstr = *(__int32 *) table4[remains[0]];
    wstr += 4;
    *wstr = 0;
    return (wstr - str);
  }
  else if (value >= 10000) {
    v2 = value / 10000;
    remains[0] = value - v2 * 10000;
    value = v2;
    wstr = str;
    if (value >= 1000) {
      *(__int32 *) wstr = *(__int32 *) table4[value];
      wstr += 4;
      *(__int32 *) wstr = *(__int32 *) table4[remains[0]];
      wstr += 4;
      *wstr = 0;
      return 8;
    } else {
      *(__int32 *) wstr = *(__int32 *) table5[value];
      wstr += offsets[value];
      *(__int32 *) wstr = *(__int32 *) table4[remains[0]];
      wstr += 4;
      *wstr = 0;
      return (wstr - str);
    }
  }
  else {
    if (value >= 1000) {
      *(__int32 *) str = *(__int32 *) table4[value];
      str += 4;
      *str = 0;
      return 4;
    } else if (value >= 100) {
      *(__int32 *) str = *(__int32 *) table3[value];
      return 3;
    } else if (value >= 10) {
      *(__int16 *) str = *(__int16 *) table2[value];
      str += 2;
      *str = 0;
      return 2;
    } else {
      *(__int16 *) str = *(__int16 *) table1[value];
      return 1;
    }
  }
}

int ufast_itoa10(int value, char* str) {
  if (value < 0) { *(str++) = '-'; 
    return ufast_utoa10(-value, str) + 1; 
  }
  else return ufast_utoa10(value, str);
}


    void ufast_test() {

   print_mode("[modp_ufast]");

   std::string s;
   s.reserve(32);
   std::size_t total_length = 0;
   strtk::util::timer t;
   t.start();

   char buf[128];
   int len;
   for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i)
   {
      #ifdef enable_test_type01
      s.resize(ufast_itoa10(((i & 1) ? i : -i), const_cast<char*>(s.c_str())));
      total_length += s.size();
      #endif

      #ifdef enable_test_type02
      s.resize(ufast_itoa10(max_i2s + i, const_cast<char*>(s.c_str())));
      total_length += s.size();
      #endif

      #ifdef enable_test_type03
      s.resize(ufast_itoa10(randval[(max_i2s + i) & 1023], const_cast<char*>(s.c_str())));
      total_length += s.size();
      #endif
   }
   t.stop();
   printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n",
          static_cast<unsigned long>(3 * max_i2s),
          static_cast<unsigned long>(total_length),
          t.time(),
          (3.0 * max_i2s) / t.time());
}

4
আপনি এটিকে কখনও স্ট্রিংয়ের মধ্যে রাখেন নি। এছাড়াও আমি জানি না কেন প্রত্যেকের কোডের জন্য আপনার ফলাফলগুলি এত কম, আপনার সিপিইউ ধীর নয়।
বেন ভয়েগট

মোডপ_উফাস্টের একটি ত্রুটি রয়েছে, এটি 11000000 পর্যন্ত 1000000 এর পরিবর্তে 10, 199 1090000 এর পরিবর্তে 19 এবং অন্যান্য ইত্যাদি প্রদান করে
ডেনিস জাইকিন

পরিবর্তিত ইউফ্রেস্ট অবৈধ মানগুলি দেয় (কয়েকটি ত্রুটির পরে থামিয়ে দেওয়া হয়)। Mismatch found: Generated: -99 Reference: -9099999 Mismatch found: Generated: -99 Reference: -9099998 Mismatch found: Generated: -99 Reference: -9099997
ওয়ালডেমার

বেঞ্চমার্কগুলির সাথে এখানে আরও বহনযোগ্য সংস্করণ রয়েছে: github.com/fmtlib/format-benchmark/blob/master/src/u2985907.h
ভিটআউট

2

এই মজাদার ধাঁধাটির আমার ছোট্ট চেষ্টাটি এখানে।

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

পারফরম্যান্স বেঞ্চমার্ক

গতির কথা হিসাবে, আমার এখানে আমার বেঞ্চমার্কটি আমাকে বলে যে এটি টিমোর কাজের চেয়ে 1,5 গুণ বেশি গতিযুক্ত (আমার ইনটেল হাসওলে এটি প্রায় 1 গিগাবাইট / সেকেন্ডে চলে)।

যে জিনিসগুলি আপনি প্রতারণা বিবেচনা করতে পারেন

আমি যে নন-মেকিং-এ-স্টার্ড-স্ট্রিং চিট ব্যবহার করি - অবশ্যই আমি এটি আমার তিমোর পদ্ধতির মানদণ্ডের জন্য বিবেচনা করেছি।

আমি একটি অভ্যন্তরীণ ব্যবহার করি: বিএসআর। আপনি যদি পছন্দ করেন তবে এর পরিবর্তে আপনি ডি-ব্রাইজন টেবিলগুলিও ব্যবহার করতে পারেন - যা আমার 'দ্রুততম 2 লগ' পোস্টে আমি বেশ কিছুটা লিখেছিলাম of অবশ্যই, এটির একটি পারফরম্যান্স পেনাল্টি রয়েছে (* ভাল ... আপনি যদি প্রচুর পরিমাণে ইতোয়া অপারেশন করছেন তবে আপনি আসলে একটি দ্রুত বিএসআর করতে পারেন তবে আমার ধারণা এটি ন্যায্য নয় ...)।

যেভাবে এটি কাজ করে

প্রথমে আমাদের কাজ করতে হবে যে আমাদের কত স্মৃতি দরকার figure এটি মূলত একটি 10 ​​লগ, যা বিভিন্ন স্মার্ট উপায়ে প্রয়োগ করা যেতে পারে। বিশদ জন্য ঘন ঘন উদ্ধৃত " বিট টুইডলিং হ্যাকস " দেখুন।

পরবর্তী কাজটি হ'ল সংখ্যার আউটপুট কার্যকর করা। আমি এটির জন্য টেমপ্লেট পুনরাবৃত্তি ব্যবহার করি, তাই সংকলকটি এটি বের করে ফেলবে।

আমি একে অপরের ঠিক পাশে 'মডুলো' এবং 'ডিভ' ব্যবহার করি। আপনি যদি হ্যাকারের আনন্দ উপস্থাপনাটি পড়েন তবে আপনি খেয়াল করবেন যে দু'জনের খুব ঘনিষ্ঠ সম্পর্ক রয়েছে, সুতরাং আপনার যদি একটি উত্তর থাকে তবে আপনার সম্ভবত অন্যটিও রয়েছে। আমি সংকলকটি বিশদটি বের করতে পারলাম ... :-)

কোড

(পরিবর্তিত) লগ 10 ব্যবহার করে অঙ্কের সংখ্যা পাওয়া:

struct logarithm
{
    static inline int log2(unsigned int value)
    {
        unsigned long index;
        if (!_BitScanReverse(&index, value))
        {
            return 0;
        }

        // add 1 if x is NOT a power of 2 (to do the ceil)
        return index + (value&(value - 1) ? 1 : 0);
    }

    static inline int numberDigits(unsigned int v)
    {
        static unsigned int const PowersOf10[] =
        { 0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };

        int t = (logarithm::log2(v) + 1) * 1233 >> 12; // (use a lg2 method from above)
        return 1 + t - (v < PowersOf10[t]);
    }
};

নিজেকে স্ট্রিং করা:

template <int count>
struct WriteHelper
{
    inline static void WriteChar(char* buf, unsigned int value)
    {
        unsigned int div = value / 10;
        unsigned int rem = value % 10;
        buf[count - 1] = rem + '0';

        WriteHelper<count - 1>::WriteChar(buf, div);
    }
};

template <>
struct WriteHelper<1>
{
    inline static void WriteChar(char* buf, unsigned int value) 
    {
        buf[0] = '0' + value;
    }
};

// Boring code that converts a length into a switch.
// TODO: Test if recursion with an 'if' is faster.
static inline void WriteNumber(char* data, int len, unsigned int val) 
{
    switch (len) {
    case 1:
        WriteHelper<1>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 2:
        WriteHelper<2>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 3:
        WriteHelper<3>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 4:
        WriteHelper<4>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 5:
        WriteHelper<5>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 6:
        WriteHelper<6>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 7:
        WriteHelper<7>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 8:
        WriteHelper<8>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 9:
        WriteHelper<9>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    case 10:
        WriteHelper<10>::WriteChar(data, static_cast<unsigned int>(val));
        break;
    }
}

// The main method you want to call...
static int Write(char* data, int val) 
{
    int len;
    if (val >= 0) 
    {
        len = logarithm::numberDigits(val);
        WriteNumber(data, len, unsigned int(val));
        return len;
    }
    else 
    {
        unsigned int v(-val);
        len = logarithm::numberDigits(v);
        WriteNumber(data+1, len, v);
        data[0] = '-';
        return len + 1;
    }
}

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

@ বেনভয়েগ্ট আসলে যদি আপনি ভিএস ২০১৩ এ 'বিচ্ছিন্ন' করেন তবে আপনি এইচ এর আনন্দ পড়ার পরে ঠিক এমন কোড পাবেন যা আপনি আশা করতে পারেন। আপনি যে অধ্যায়টি সন্ধান করছেন সেটি অধ্যায় 10
অ্যাটলাস্ট

হ্যাঁ, আমি সেই হার্ডওয়ারের বহুগুণটি ব্যবহার করে যা বাস্তবায়ন করছি।
বেন ভয়েগট

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

2

আমি কিছুক্ষণের জন্য এই বসে ছিল এবং অবশেষে এটি পোস্ট প্রায় কাছাকাছি পেয়েছিলাম।

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

HOPMAN_FAST - performance reference  
TM_CPP, TM_VEC - scalar and vector versions of Terje Mathisen algorithm  
WM_VEC - intrinsics implementation of Wojciech Mula's vector algorithm  
AK_BW - word-at-a-time routine with a jump table that fills a buffer in reverse  
AK_FW - forward-stepping word-at-a-time routine with a jump table in assembly  
AK_UNROLLED - generic word-at-a-time routine that uses an unrolled loop  

থ্রুপুট

কাঁচা খরচ

সংকলন-সময় স্যুইচ:

-ডিভিস্ট্রিং - পুরানো জিসিসি সেটআপগুলির জন্য এসএসও স্ট্রিংগুলিকে
সক্ষম করে - ডিবিএসআর 1 - দ্রুত
লগ 10 সক্ষম করে - ডিআরডিটিএসসি - চক্র কাউন্টারগুলিকে সক্ষম করে

#include <cstdio>
#include <iostream>
#include <climits>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <limits>
#include <ctime>
#include <stdint.h>
#include <x86intrin.h>

/* Uncomment to run */
// #define HOPMAN_FAST
// #define TM_CPP
// #define TM_VEC
// #define WM_VEC
// #define AK_UNROLLED
// #define AK_BW
// #define AK_FW

using namespace std;
#ifdef VSTRING
#include <ext/vstring.h>
typedef __gnu_cxx::__vstring string_type;
#else
typedef string string_type;
#endif

namespace detail {

#ifdef __GNUC__
#define ALIGN(N) __attribute__ ((aligned(N)))
#define PACK __attribute__ ((packed))
  inline size_t num_digits(unsigned u) {
    struct {
      uint32_t count;
      uint32_t max;
    } static digits[32] ALIGN(64) = {
    { 1, 9 }, { 1, 9 }, { 1, 9 }, { 1, 9 },
    { 2, 99 }, { 2, 99 }, { 2, 99 },
    { 3, 999 }, { 3, 999 }, { 3, 999 },
    { 4, 9999 }, { 4, 9999 }, { 4, 9999 }, { 4, 9999 },
    { 5, 99999 }, { 5, 99999 }, { 5, 99999 },
    { 6, 999999 }, { 6, 999999 }, { 6, 999999 },
    { 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 },
    { 8, 99999999 }, { 8, 99999999 }, { 8, 99999999 },
    { 9, 999999999 }, { 9, 999999999 }, { 9, 999999999 },
    { 10, UINT_MAX }, { 10, UINT_MAX }
    };
#if (defined(i386) || defined(__x86_64__)) && (defined(BSR1) || defined(BSR2))
    size_t l = u;
#if defined(BSR1)
    __asm__ __volatile__ (
      "bsrl %k0, %k0    \n\t"
      "shlq $32, %q1    \n\t" 
      "movq %c2(,%0,8), %0\n\t" 
      "cmpq %0, %q1     \n\t"
      "seta %b1         \n\t"
      "addl %1, %k0     \n\t"
      : "+r" (l), "+r"(u)
      : "i"(digits)
      : "cc"
    );
    return l;
#else
    __asm__ __volatile__ ( "bsr %0, %0;"  : "+r" (l) );
    return digits[l].count + ( u > digits[l].max );
#endif
#else
    size_t l = (u != 0) ? 31 - __builtin_clz(u) : 0;
    return digits[l].count + ( u > digits[l].max );
#endif 
  }
#else 
  inline unsigned msb_u32(unsigned x) {
    static const unsigned bval[] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
    unsigned base = 0;
    if (x & (unsigned) 0xFFFF0000) { base += 32/2; x >>= 32/2; }
    if (x & (unsigned) 0x0000FF00) { base += 32/4; x >>= 32/4; }
    if (x & (unsigned) 0x000000F0) { base += 32/8; x >>= 32/8; }
    return base + bval[x];
  }

  inline size_t num_digits(unsigned x) {
    static const unsigned powertable[] = {
  0,10,100,1000,10000,100000,1000000,10000000,100000000, 1000000000 };
    size_t lg_ten = msb_u32(x) * 1233 >> 12;
    size_t adjust = (x >= powertable[lg_ten]);
    return lg_ten + adjust;
  }
#endif /* __GNUC__ */

  struct CharBuffer {
    class reverse_iterator : public iterator<random_access_iterator_tag, char> {
        char* m_p;
      public:
        reverse_iterator(char* p) : m_p(p - 1) {}
        reverse_iterator operator++() { return --m_p; }
        reverse_iterator operator++(int) { return m_p--; }
        char operator*() const { return *m_p; }
        bool operator==( reverse_iterator it) const { return m_p == it.m_p; }
        bool operator!=( reverse_iterator it) const { return m_p != it.m_p; }
        difference_type operator-( reverse_iterator it) const { return it.m_p - m_p; }
    };
  };

  union PairTable {
    char c[2];
    unsigned short u;
  } PACK table[100] ALIGN(1024) = {
    {{'0','0'}},{{'0','1'}},{{'0','2'}},{{'0','3'}},{{'0','4'}},{{'0','5'}},{{'0','6'}},{{'0','7'}},{{'0','8'}},{{'0','9'}},
    {{'1','0'}},{{'1','1'}},{{'1','2'}},{{'1','3'}},{{'1','4'}},{{'1','5'}},{{'1','6'}},{{'1','7'}},{{'1','8'}},{{'1','9'}},
    {{'2','0'}},{{'2','1'}},{{'2','2'}},{{'2','3'}},{{'2','4'}},{{'2','5'}},{{'2','6'}},{{'2','7'}},{{'2','8'}},{{'2','9'}},
    {{'3','0'}},{{'3','1'}},{{'3','2'}},{{'3','3'}},{{'3','4'}},{{'3','5'}},{{'3','6'}},{{'3','7'}},{{'3','8'}},{{'3','9'}},
    {{'4','0'}},{{'4','1'}},{{'4','2'}},{{'4','3'}},{{'4','4'}},{{'4','5'}},{{'4','6'}},{{'4','7'}},{{'4','8'}},{{'4','9'}},
    {{'5','0'}},{{'5','1'}},{{'5','2'}},{{'5','3'}},{{'5','4'}},{{'5','5'}},{{'5','6'}},{{'5','7'}},{{'5','8'}},{{'5','9'}},
    {{'6','0'}},{{'6','1'}},{{'6','2'}},{{'6','3'}},{{'6','4'}},{{'6','5'}},{{'6','6'}},{{'6','7'}},{{'6','8'}},{{'6','9'}},
    {{'7','0'}},{{'7','1'}},{{'7','2'}},{{'7','3'}},{{'7','4'}},{{'7','5'}},{{'7','6'}},{{'7','7'}},{{'7','8'}},{{'7','9'}},
    {{'8','0'}},{{'8','1'}},{{'8','2'}},{{'8','3'}},{{'8','4'}},{{'8','5'}},{{'8','6'}},{{'8','7'}},{{'8','8'}},{{'8','9'}},
    {{'9','0'}},{{'9','1'}},{{'9','2'}},{{'9','3'}},{{'9','4'}},{{'9','5'}},{{'9','6'}},{{'9','7'}},{{'9','8'}},{{'9','9'}}
  };
} // namespace detail

struct progress_timer {
    clock_t c;
    progress_timer() : c(clock()) {}
    int elapsed() { return clock() - c; }
    ~progress_timer() {
        clock_t d = clock() - c;
        cout << d / CLOCKS_PER_SEC << "."
            << (((d * 1000) / CLOCKS_PER_SEC) % 1000 / 100)
            << (((d * 1000) / CLOCKS_PER_SEC) % 100 / 10)
            << (((d * 1000) / CLOCKS_PER_SEC) % 10)
            << " s" << endl;
    }
};

#ifdef HOPMAN_FAST
namespace hopman_fast {

    static unsigned long cpu_cycles = 0;

    struct itostr_helper {
        static ALIGN(1024) unsigned out[10000];

        itostr_helper() {
            for (int i = 0; i < 10000; i++) {
                unsigned v = i;
                char * o = (char*)(out + i);
                o[3] = v % 10 + '0';
                o[2] = (v % 100) / 10 + '0';
                o[1] = (v % 1000) / 100 + '0';
                o[0] = (v % 10000) / 1000;
                if (o[0]) o[0] |= 0x30;
                else if (o[1] != '0') o[0] |= 0x20;
                else if (o[2] != '0') o[0] |= 0x10;
                else o[0] |= 0x00;
            }
        }
    };
    unsigned itostr_helper::out[10000];

    itostr_helper hlp_init;

    template <typename T>
    string_type itostr(T o) {
        typedef itostr_helper hlp;
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        unsigned blocks[3], *b = blocks + 2;
        blocks[0] = o < 0 ? ~o + 1 : o;
        blocks[2] = blocks[0] % 10000; blocks[0] /= 10000;
        blocks[2] = hlp::out[blocks[2]];

        if (blocks[0]) {
            blocks[1] = blocks[0] % 10000; blocks[0] /= 10000;
            blocks[1] = hlp::out[blocks[1]];
            blocks[2] |= 0x30303030;
            b--;
        }

        if (blocks[0]) {
            blocks[0] = hlp::out[blocks[0] % 10000];
            blocks[1] |= 0x30303030;
            b--;
        }

        char* f = ((char*)b);
        f += 3 - (*f >> 4);

        char* str = (char*)blocks;
        if (o < 0) *--f = '-';

        str += 12;
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(f, str);
    }
      unsigned long cycles() { return cpu_cycles; }
      void reset() { cpu_cycles = 0; }
}
#endif

namespace ak {
#ifdef AK_UNROLLED
  namespace unrolled {
    static unsigned long cpu_cycles = 0;

    template <typename value_type> class Proxy {
      static const size_t MaxValueSize = 16;

      static inline char* generate(int value, char* buffer) {
        union { char* pc; unsigned short* pu; } b = { buffer + MaxValueSize };
        unsigned u, v = value < 0 ? unsigned(~value) + 1 : value;
        *--b.pu = detail::table[v % 100].u; u = v;
        if ((v /= 100)) {
          *--b.pu = detail::table[v % 100].u; u = v;
          if ((v /= 100)) {
            *--b.pu = detail::table[v % 100].u; u = v;
            if ((v /= 100)) {
              *--b.pu = detail::table[v % 100].u; u = v;
              if ((v /= 100)) {
                *--b.pu = detail::table[v % 100].u; u = v;
        } } } }
        *(b.pc -= (u >= 10)) = '-';
        return b.pc + (value >= 0);
      }
      static inline char* generate(unsigned value, char* buffer) {
        union { char* pc; unsigned short* pu; } b = { buffer + MaxValueSize };
        unsigned u, v = value;
        *--b.pu = detail::table[v % 100].u; u = v;
        if ((v /= 100)) {
          *--b.pu = detail::table[v % 100].u; u = v;
          if ((v /= 100)) {
            *--b.pu = detail::table[v % 100].u; u = v;
            if ((v /= 100)) {
              *--b.pu = detail::table[v % 100].u; u = v;
              if ((v /= 100)) {
                *--b.pu = detail::table[v % 100].u; u = v;
        } } } }
        return b.pc + (u < 10);
      }
    public:
      static inline string_type convert(value_type v) {
        char buf[MaxValueSize];
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        char* p = generate(v, buf);
        char* e = buf + MaxValueSize;
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(p, e);
      }
    };
    string_type itostr(int i) { return Proxy<int>::convert(i); }
    string_type itostr(unsigned i) { return Proxy<unsigned>::convert(i); }
    unsigned long cycles() { return cpu_cycles; }
    void reset() { cpu_cycles = 0; }
  }
#endif

#if defined(AK_BW)
  namespace bw {
    static unsigned long cpu_cycles = 0;
    typedef uint64_t u_type;

    template <typename value_type> class Proxy {

      static inline void generate(unsigned v, size_t len, char* buffer) {
        u_type u = v;
        switch(len) {
        default: u = (v * 1374389535ULL) >> 37; *(uint16_t*)(buffer + 8) = detail::table[v -= 100 * u].u; 
        case  8: v = (u * 1374389535ULL) >> 37; *(uint16_t*)(buffer + 6) = detail::table[u -= 100 * v].u; 
        case  6: u = (v * 1374389535ULL) >> 37; *(uint16_t*)(buffer + 4) = detail::table[v -= 100 * u].u;
        case  4: v = (u * 167773) >> 24; *(uint16_t*)(buffer + 2) = detail::table[u -= 100 * v].u;
        case  2: *(uint16_t*)buffer = detail::table[v].u;
        case  0: return;
        case  9: u = (v * 1374389535ULL) >> 37; *(uint16_t*)(buffer + 7) = detail::table[v -= 100 * u].u;
        case  7: v = (u * 1374389535ULL) >> 37; *(uint16_t*)(buffer + 5) = detail::table[u -= 100 * v].u;
        case  5: u = (v * 1374389535ULL) >> 37; *(uint16_t*)(buffer + 3) = detail::table[v -= 100 * u].u;
        case  3: v = (u * 167773) >> 24; *(uint16_t*)(buffer + 1) = detail::table[u -= 100 * v].u;
        case  1: *buffer = v + 0x30;
        }
      }
    public:
      static inline string_type convert(bool neg, unsigned val) {
        char buf[16];
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        size_t len = detail::num_digits(val);
        buf[0] = '-';

        char* e = buf + neg;
        generate(val, len, e);
        e += len;
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(buf, e);
      }
    };
    string_type itostr(int i) { return Proxy<int>::convert(i < 0, i < 0 ? unsigned(~i) + 1 : i); }
    string_type itostr(unsigned i) { return Proxy<unsigned>::convert(false, i); }
    unsigned long cycles() { return cpu_cycles; }
    void reset() { cpu_cycles = 0; }
  }
#endif

#if defined(AK_FW)
  namespace fw {
        static unsigned long cpu_cycles = 0;
        typedef uint32_t u_type;
        template <typename value_type> class Proxy {

        static inline void generate(unsigned v, size_t len, char* buffer) {
#if defined(__GNUC__) && defined(__x86_64__)
          uint16_t w;
          uint32_t u;
          __asm__ __volatile__ (
        "jmp %*T%=(,%3,8)       \n\t"
        "T%=: .quad L0%=        \n\t"
        "     .quad L1%=        \n\t"
        "     .quad L2%=        \n\t"
        "     .quad L3%=        \n\t"
        "     .quad L4%=        \n\t"
        "     .quad L5%=        \n\t"
        "     .quad L6%=        \n\t"
        "     .quad L7%=        \n\t"
        "     .quad L8%=        \n\t"
        "     .quad L9%=        \n\t"
        "     .quad L10%=       \n\t"
        "L10%=:         \n\t"
        " imulq $1441151881, %q0, %q1\n\t"
        " shrq $57, %q1     \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $100000000, %1, %1  \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, (%4)        \n\t"
        "L8%=:          \n\t"
        " imulq $1125899907, %q0, %q1\n\t"
        " shrq $50, %q1     \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $1000000, %1, %1    \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, -8(%4,%3)   \n\t"
        "L6%=:          \n\t"
        " imulq $429497, %q0, %q1   \n\t"
        " shrq $32, %q1     \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $10000, %1, %1  \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, -6(%4,%3)   \n\t"
        "L4%=:          \n\t"
        " imull $167773, %0, %1 \n\t"
        " shrl $24, %1      \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $100, %1, %1    \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, -4(%4,%3)   \n\t"
        "L2%=:          \n\t"
        " movw %c5(,%q0,2), %w2 \n\t"
        " movw %w2, -2(%4,%3)   \n\t"
        "L0%=: jmp 1f       \n\t"
        "L9%=:          \n\t"
        " imulq $1801439851, %q0, %q1\n\t"
        " shrq $54, %q1     \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $10000000, %1, %1   \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, (%4)        \n\t"
        "L7%=:          \n\t"
        " imulq $43980466, %q0, %q1 \n\t"
        " shrq $42, %q1     \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $100000, %1, %1 \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, -7(%4,%3)   \n\t"
        "L5%=:          \n\t"
        " imulq $268436, %q0, %q1   \n\t"
        " shrq $28, %q1     \n\t"
        " movw %c5(,%q1,2), %w2 \n\t"
        " imull $1000, %1, %1   \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, -5(%4,%3)   \n\t"
        "L3%=:          \n\t"
        " imull $6554, %0, %1   \n\t"
        " shrl $15, %1      \n\t"
        " andb $254, %b1        \n\t"
        " movw %c5(,%q1), %w2   \n\t"
        " leal (%1,%1,4), %1    \n\t"
        " subl %1, %0       \n\t"
        " movw %w2, -3(%4,%3)   \n\t"
        "L1%=:          \n\t"
        " addl $48, %0      \n\t"
        " movb %b0, -1(%4,%3)   \n\t"
        "1:             \n\t"
        : "+r"(v), "=&q"(u), "=&r"(w)
        : "r"(len), "r"(buffer), "i"(detail::table)
        : "memory", "cc"
          ); 
#else
          u_type u;
          switch(len) {
        default: u = (v * 1441151881ULL) >> 57; *(uint16_t*)(buffer) = detail::table[u].u; v -= u * 100000000;
        case  8: u = (v * 1125899907ULL) >> 50; *(uint16_t*)(buffer + len - 8) = detail::table[u].u; v -= u * 1000000;
        case  6: u = (v * 429497ULL) >> 32; *(uint16_t*)(buffer + len - 6) = detail::table[u].u; v -= u * 10000;
        case  4: u = (v * 167773) >> 24; *(uint16_t*)(buffer + len - 4) = detail::table[u].u; v -= u * 100;
        case  2: *(uint16_t*)(buffer + len - 2) = detail::table[v].u;
        case  0: return;
        case  9: u = (v * 1801439851ULL) >> 54; *(uint16_t*)(buffer) = detail::table[u].u; v -= u * 10000000; 
        case  7: u = (v * 43980466ULL) >> 42; *(uint16_t*)(buffer + len - 7) = detail::table[u].u; v -= u * 100000; 
        case  5: u = (v * 268436ULL) >> 28;  *(uint16_t*)(buffer + len - 5) = detail::table[u].u; v -= u * 1000;
        case  3: u = (v * 6554) >> 16; *(uint16_t*)(buffer + len - 3) = detail::table[u].u; v -= u * 10;
        case  1: *(buffer + len - 1) = v + 0x30;
          }
#endif
        }
      public:
        static inline string_type convert(bool neg, unsigned val) {
        char buf[16];
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        size_t len = detail::num_digits(val);
        if (neg) buf[0] = '-';
        char* e = buf + len + neg;
        generate(val, len, buf + neg);
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(buf, e);
        }
      };
      string_type itostr(int i) { return Proxy<int>::convert(i < 0, i < 0 ? unsigned(~i) + 1 : i); }
      string_type itostr(unsigned i) { return Proxy<unsigned>::convert(false, i); }
      unsigned long cycles() { return cpu_cycles; }
      void reset() { cpu_cycles = 0; }
  }
#endif
} // ak

namespace wm {
#ifdef WM_VEC
#if defined(__GNUC__) && defined(__x86_64__)
  namespace vec {
      static unsigned long cpu_cycles = 0;

      template <typename value_type> class Proxy {

      static inline unsigned generate(unsigned v, char* buf) {
        static struct {
          unsigned short mul_10[8];
          unsigned short div_const[8];
          unsigned short shl_const[8];
          unsigned char  to_ascii[16];
        } ALIGN(64) bits = 
        {
          { // mul_10
           10, 10, 10, 10, 10, 10, 10, 10
          },
          { // div_const
            8389, 5243, 13108, 0x8000, 8389, 5243, 13108, 0x8000
          },
          { // shl_const
            1 << (16 - (23 + 2 - 16)),
            1 << (16 - (19 + 2 - 16)),
            1 << (16 - 1 - 2),
            1 << (15),
            1 << (16 - (23 + 2 - 16)),
            1 << (16 - (19 + 2 - 16)),
            1 << (16 - 1 - 2),
            1 << (15)
          },
          { // to_ascii 
            '0', '0', '0', '0', '0', '0', '0', '0',
            '0', '0', '0', '0', '0', '0', '0', '0'
          }
        };
        unsigned x, y, l;
        x = (v * 1374389535ULL) >> 37;
        y = v;
        l = 0;
        if (x) {
          unsigned div = 0xd1b71759;
          unsigned mul = 55536;
          __m128i z, m, a, o;
          y -= 100 * x;
          z = _mm_cvtsi32_si128(x);
          m = _mm_load_si128((__m128i*)bits.mul_10);
          o = _mm_mul_epu32( z, _mm_cvtsi32_si128(div));
          z = _mm_add_epi32( z, _mm_mul_epu32( _mm_cvtsi32_si128(mul), _mm_srli_epi64( o, 45) ) );
          z = _mm_slli_epi64( _mm_shuffle_epi32( _mm_unpacklo_epi16(z, z), 5 ), 2 );
          a = _mm_load_si128((__m128i*)bits.to_ascii);
          z = _mm_mulhi_epu16( _mm_mulhi_epu16( z, *(__m128i*)bits.div_const ), *(__m128i*)bits.shl_const );
          z = _mm_sub_epi16( z, _mm_slli_epi64( _mm_mullo_epi16( m, z ), 16 ) );
          z = _mm_add_epi8( _mm_packus_epi16( z, _mm_xor_si128(o, o) ), a );
          x = __builtin_ctz( ~_mm_movemask_epi8( _mm_cmpeq_epi8( a, z ) ) );
          l = 8 - x;
          uint64_t q = _mm_cvtsi128_si64(z) >> (x * 8);
          *(uint64_t*)buf = q;
          buf += l;
          x = 1;
        }
        v = (y * 6554) >> 16;
        l += 1 + (x | (v != 0));
            *(unsigned short*)buf = 0x30 + ((l > 1) ? ((0x30 + y - v * 10) << 8) + v : y);
            return l;
        }
      public:
        static inline string_type convert(bool neg, unsigned val) {
        char buf[16];
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        buf[0] = '-';
        unsigned len = generate(val, buf + neg);
        char* e = buf + len + neg;
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(buf, e);
        }
      };
      inline string_type itostr(int i) { return Proxy<int>::convert(i < 0, i < 0 ? unsigned(~i) + 1 : i); }
      inline string_type itostr(unsigned i) { return Proxy<unsigned>::convert(false, i); }
      unsigned long cycles() { return cpu_cycles; }
      void reset() { cpu_cycles = 0; }
  }
#endif
#endif
} // wm

namespace tmn {

#ifdef TM_CPP
  namespace cpp {
      static unsigned long cpu_cycles = 0;

      template <typename value_type> class Proxy {

        static inline void generate(unsigned v, char* buffer) {
          unsigned const f1_10000 = (1 << 28) / 10000;
          unsigned tmplo, tmphi;

          unsigned lo = v % 100000;
          unsigned hi = v / 100000;

          tmplo = lo * (f1_10000 + 1) - (lo >> 2);
          tmphi = hi * (f1_10000 + 1) - (hi >> 2);

          unsigned mask = 0x0fffffff;
          unsigned shift = 28;

          for(size_t i = 0; i < 5; i++)
          {
            buffer[i + 0] = '0' + (char)(tmphi >> shift);
            buffer[i + 5] = '0' + (char)(tmplo >> shift);
            tmphi = (tmphi & mask) * 5;
            tmplo = (tmplo & mask) * 5;
            mask >>= 1;
            shift--;
          }
        }
      public:
        static inline string_type convert(bool neg, unsigned val) {
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        char buf[16];
        size_t len = detail::num_digits(val);
        char* e = buf + 11;
        generate(val, buf + 1);
        buf[10 - len] = '-';
        len += neg;
        char* b = e - len;
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(b, e);
        }
      };
      string_type itostr(int i) { return Proxy<int>::convert(i < 0, i < 0 ? unsigned(~i) + 1 : i); }
      string_type itostr(unsigned i) { return Proxy<unsigned>::convert(false, i); }
      unsigned long cycles() { return cpu_cycles; }
      void reset() { cpu_cycles = 0; }
  }
#endif

#ifdef TM_VEC
  namespace vec {
      static unsigned long cpu_cycles = 0;

      template <typename value_type> class Proxy {

        static inline unsigned generate(unsigned val, char* buffer) {
        static struct {
            unsigned char mul_10[16];
            unsigned char to_ascii[16];
            unsigned char gather[16];
            unsigned char shift[16];
        } ALIGN(64) bits = {
            { 10,0,0,0,10,0,0,0,10,0,0,0,10,0,0,0 },
            { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' },
            { 3,5,6,7,9,10,11,13,14,15,0,0,0,0,0,0 },
            { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }
        };

        unsigned u = val / 1000000;
        unsigned l = val - u * 1000000;

        __m128i x, h, f, m, n;

        n = _mm_load_si128((__m128i*)bits.mul_10);
        x = _mm_set_epi64x( l, u );
        h = _mm_mul_epu32( x, _mm_set1_epi32(4294968) );
        x = _mm_sub_epi64( x, _mm_srli_epi64( _mm_mullo_epi32( h, _mm_set1_epi32(1000) ), 32 ) );
        f = _mm_set1_epi32((1 << 28) / 1000 + 1);
        m = _mm_srli_epi32( _mm_cmpeq_epi32(m, m), 4 );
        x = _mm_shuffle_epi32( _mm_blend_epi16( x, h, 204 ), 177 );
        f = _mm_sub_epi32( _mm_mullo_epi32(f, x), _mm_srli_epi32(x, 2) );

        h = _mm_load_si128((__m128i*)bits.to_ascii);

        x = _mm_srli_epi32(f, 28);
        f = _mm_mullo_epi32( _mm_and_si128( f, m ), n );

        x = _mm_or_si128( x, _mm_slli_epi32(_mm_srli_epi32(f, 28), 8) );
        f = _mm_mullo_epi32( _mm_and_si128( f, m ), n );

        x = _mm_or_si128( x, _mm_slli_epi32(_mm_srli_epi32(f, 28), 16) );
        f = _mm_mullo_epi32( _mm_and_si128( f, m ), n );

        x = _mm_or_si128( x, _mm_slli_epi32(_mm_srli_epi32(f, 28), 24) );

        x = _mm_add_epi8( _mm_shuffle_epi8(x, *(__m128i*)bits.gather), h );
        l = __builtin_ctz( ~_mm_movemask_epi8( _mm_cmpeq_epi8( h, x ) ) | (1 << 9) );

        x = _mm_shuffle_epi8( x, _mm_add_epi8(*(__m128i*)bits.shift, _mm_set1_epi8(l) ) );

        _mm_store_si128( (__m128i*)buffer, x );
        return 10 - l;
        }

      public:
        static inline string_type convert(bool neg, unsigned val) {
#ifdef RDTSC
        long first_clock = __rdtsc();
#endif
        char arena[32];
        char* buf = (char*)((uintptr_t)(arena + 16) & ~(uintptr_t)0xf);
        *(buf - 1)= '-';
        unsigned len = generate(val, buf) + neg;
        buf -= neg;
        char* end = buf + len;
#ifdef RDTSC
        cpu_cycles += __rdtsc() - first_clock;
#endif
        return string_type(buf, end);
        }
      };
      string_type itostr(int i) { return Proxy<int>::convert(i < 0, i < 0 ? unsigned(~i) + 1 : i); }
      string_type itostr(unsigned i) { return Proxy<unsigned>::convert(false, i); }
      unsigned long cycles() { return cpu_cycles; }
      void reset() { cpu_cycles = 0; }
  }
#endif
}

bool fail(string in, string_type out) {
    cout << "failure: " << in << " => " << out << endl;
    return false;
}

#define TEST(x, n) \
    stringstream ss; \
    string_type s = n::itostr(x); \
    ss << (long long)x; \
    if (::strcmp(ss.str().c_str(), s.c_str())) { \
        passed = fail(ss.str(), s); \
        break; \
    }

#define test(x) { \
    passed = true; \
    if (0 && passed) { \
        char c = CHAR_MIN; \
        do { \
            TEST(c, x); \
        } while (c++ != CHAR_MAX); \
        if (!passed) cout << #x << " failed char!!!" << endl; \
    } \
    if (0 && passed) { \
        short c = numeric_limits<short>::min(); \
        do { \
            TEST(c, x); \
        } while (c++ != numeric_limits<short>::max()); \
        if (!passed) cout << #x << " failed short!!!" << endl; \
    } \
    if (passed) { \
        int c = numeric_limits<int>::min(); \
        do { \
            TEST(c, x); \
        } while ((c += 100000) < numeric_limits<int>::max() - 100000); \
        if (!passed) cout << #x << " failed int!!!" << endl; \
    } \
    if (passed) { \
        unsigned c = numeric_limits<unsigned>::max(); \
        do { \
            TEST(c, x); \
        } while ((c -= 100000) > 100000); \
        if (!passed) cout << #x << " failed unsigned int!!!" << endl; \
    } \
}

#define time(x, N) \
if (passed) { \
    static const int64_t limits[] = \
        {0, 10, 100, 1000, 10000, 100000, \
         1000000, 10000000, 100000000, 1000000000, 10000000000ULL }; \
    long passes = 0; \
    cout << #x << ": "; \
    progress_timer t; \
    uint64_t s = 0; \
    if (do_time) { \
        for (int n = 0; n < N1; n++) { \
            int i = 0; \
            while (i < N2) { \
                int v = ((NM - i) % limits[N]) | (limits[N] / 10); \
                int w = x::itostr(v).size() + \
                    x::itostr(-v).size(); \
                i += w * mult; \
                                passes++; \
            } \
            s += i / mult; \
        } \
    } \
    k += s; \
    cout << N << " digits: " \
          << s / double(t.elapsed()) * CLOCKS_PER_SEC/1000000 << " MB/sec, " << (x::cycles() / passes >> 1) << " clocks per pass "; \
    x::reset(); \
}

#define series(n) \
    { if (do_test) test(n);    if (do_time) time(n, 1); if (do_time) time(n, 2); \
      if (do_time) time(n, 3); if (do_time) time(n, 4); if (do_time) time(n, 5); \
      if (do_time) time(n, 6); if (do_time) time(n, 7); if (do_time) time(n, 8); \
      if (do_time) time(n, 9); if (do_time) time(n, 10); }

int N1 = 1, N2 = 500000000, NM = INT_MAX;
int mult = 1; //  used to stay under timelimit on ideone
unsigned long long k = 0;

int main(int argc, char** argv) {
    bool do_time = 1, do_test = 1;
    bool passed = true;
#ifdef HOPMAN_FAST
    series(hopman_fast)
#endif
#ifdef WM_VEC
    series(wm::vec)
#endif
#ifdef TM_CPP
    series(tmn::cpp)
#endif
#ifdef TM_VEC
    series(tmn::vec)
#endif
#ifdef AK_UNROLLED
    series(ak::unrolled)
#endif
#if defined(AK_BW)
    series(ak::bw)
#endif
#if defined(AK_FW)
    series(ak::fw)
#endif
    return k;
}

1

আমি বিশ্বাস করি যে আমি দ্রুততম পূর্ণসংখ্যার থেকে স্ট্রিং অ্যালগরিদম তৈরি করেছি। এটি প্রায় 33% দ্রুত গতিযুক্ত মডুলো 100 অ্যালগরিদমের একটি প্রকরণ এবং সবচেয়ে গুরুত্বপূর্ণ এটি ছোট এবং বৃহত উভয় সংখ্যক ক্ষেত্রেই দ্রুত। একে স্ক্রিপ্ট ItoS অ্যালগরিদম বলা হয়। আমি কীভাবে অ্যালগরিদমকে @see https://github.com/kabuki-starship/kabuki-toolkit/wiki/Engineering-a-Faster-Integer-to- String-Algorithm এ অ্যালগরিদমটি ইঞ্জিনিয়ার করেছি সেই কাগজটি পড়ার জন্য । আপনি অ্যালগরিদম ব্যবহার করতে পারেন তবে অনুগ্রহ করে কাবুকি ভিএম- তে ফিরে অবদান এবং স্ক্রিপ্টটি পরীক্ষা করে দেখুন ; বিশেষত যদি আপনি AMIL-NLP এবং / অথবা সফ্টওয়্যার-সংজ্ঞায়িত নেটওয়ার্কিং প্রোটোকলগুলিতে আগ্রহী হন।

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

/** Kabuki Toolkit
    @version 0.x
    @file    ~/source/crabs/print_itos.cc
    @author  Cale McCollough <cale.mccollough@gmail.com>
    @license Copyright (C) 2017-2018 Cale McCollough <calemccollough@gmail.com>;
             All right reserved (R). Licensed under the Apache License, Version 
             2.0 (the "License"); you may not use this file except in 
             compliance with the License. You may obtain a copy of the License 
             [here](http://www.apache.org/licenses/LICENSE-2.0). Unless 
             required by applicable law or agreed to in writing, software 
             distributed under the License is distributed on an "AS IS" BASIS, 
             WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
             implied. See the License for the specific language governing 
             permissions and limitations under the License.
*/

#include <stdafx.h>
#include "print_itos.h"

#if MAJOR_SEAM >= 1 && MINOR_SEAM >= 1

#if MAJOR_SEAM == 1 && MINOR_SEAM == 1
#define DEBUG 1

#define PRINTF(format, ...) printf(format, __VA_ARGS__);
#define PUTCHAR(c) putchar(c);
#define PRINT_PRINTED\
    sprintf_s (buffer, 24, "%u", value); *text_end = 0;\
    printf ("\n    Printed \"%s\" leaving value:\"%s\":%u",\
            begin, buffer, (uint)strlen (buffer));
#define PRINT_BINARY PrintBinary (value);
#define PRINT_BINARY_TABLE PrintBinaryTable (value);
#else
#define PRINTF(x, ...)
#define PUTCHAR(c)
#define PRINT_PRINTED
#define PRINT_BINARY
#define PRINT_BINARY_TABLE
#endif

namespace _ {

void PrintLine (char c) {
    std::cout << '\n';
    for (int i = 80; i > 0; --i) 
        std::cout << c;
}

char* Print (uint32_t value, char* text, char* text_end) {

    // Lookup table for powers of 10.
    static const uint32_t k10ToThe[]{
        1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
        1000000000, ~(uint32_t)0 };

    /** Lookup table of ASCII char pairs for 00, 01, ..., 99.
        To convert this algorithm to big-endian, flip the digit pair bytes. */
    static const uint16_t kDigits00To99[100] = {
        0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830,
        0x3930, 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731,
        0x3831, 0x3931, 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632,
        0x3732, 0x3832, 0x3932, 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533,
        0x3633, 0x3733, 0x3833, 0x3933, 0x3034, 0x3134, 0x3234, 0x3334, 0x3434,
        0x3534, 0x3634, 0x3734, 0x3834, 0x3934, 0x3035, 0x3135, 0x3235, 0x3335,
        0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, 0x3036, 0x3136, 0x3236,
        0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, 0x3037, 0x3137,
        0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, 0x3038,
        0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
        0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839,
        0x3939, };

    static const char kMsbShift[] = { 4, 7, 11, 14, 17, 21, 24, 27, 30, };

    if (!text) {
        return nullptr;
    }
    if (text >= text_end) {
        return nullptr;
    }

    uint16_t* text16;
    char      digit;
    uint32_t  scalar;
    uint16_t  digits1and2,
              digits3and4,
              digits5and6,
              digits7and8;
    uint32_t  comparator;

    #if MAJOR_SEAM == 1 && MINOR_SEAM == 1
    // Write a bunches of xxxxxx to the buffer for debug purposes.
    for (int i = 0; i <= 21; ++i) {
        *(text + i) = 'x';
    }
    *(text + 21) = 0;
    char* begin = text;
    char buffer[256];
    #endif

    if (value < 10) {
        PRINTF ("\n    Range:[0, 9] length:1 ")
        if (text + 1 >= text_end) {
            return nullptr;
        }
        *text++ = '0' + (char)value;
        PRINT_PRINTED
        return text;
    }
    if (value < 100) {
        PRINTF ("\n    Range:[10, 99] length:2 ")
        if (text + 2 >= text_end) {
            return nullptr;
        }
        *reinterpret_cast<uint16_t*> (text) = kDigits00To99[value];
        PRINT_PRINTED
        return text + 2;
    }
    if (value >> 14) {
        if (value >> 27) {
            if (value >> 30) {
                PRINTF ("\n    Range:[1073741824, 4294967295] length:10")
                Print10:
                if (text + 10 >= text_end) {
                    return nullptr;
                }
                comparator = 100000000;
                digits1and2 = (uint16_t)(value / comparator);
                PRINTF ("\n    digits1and2:%u", digits1and2)
                value -= digits1and2 * comparator;
                *reinterpret_cast<uint16_t*> (text) = kDigits00To99[digits1and2];
                PRINT_PRINTED
                text += 2;
                goto Print8;
            }
            else {
                comparator = 1000000000;
                if (value >= comparator) {
                    PRINTF ("\n    Range:[100000000, 1073741823] length:10")
                    goto Print10;
                }
                PRINTF ("\n    Range:[134217727, 999999999] length:9")
                if (text + 9 >= text_end) {
                    return nullptr;
                }
                comparator = 100000000;
                digit = (char)(value / comparator);
                *text++ = digit + '0';
                PRINT_PRINTED
                value -= comparator * digit;
                goto Print8;
            }
        }
        else if (value >> 24) {
            comparator = k10ToThe[8];
            if (value >= comparator) {
                PRINTF ("\n    Range:[100000000, 134217728] length:9")
                if (text + 9 >= text_end) {
                    return nullptr;
                }
                *text++ = '1';
                PRINT_PRINTED
                value -= comparator;
            }
            PRINTF ("\n    Range:[16777216, 9999999] length:8")
            if (text + 8 >= text_end) {
                return nullptr;
            }
            Print8:
            PRINTF ("\n    Print8:")
            scalar = 10000;
            digits5and6 = (uint16_t)(value / scalar);
            digits1and2 = value - scalar * digits5and6;
            digits7and8 = digits5and6 / 100;
            digits3and4 = digits1and2 / 100;
            digits5and6 -= 100 * digits7and8;
            digits1and2 -= 100 * digits3and4;
            *reinterpret_cast<uint16_t*> (text + 6) = 
                kDigits00To99[digits1and2];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text + 4) = 
                kDigits00To99[digits3and4];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text + 2) = 
                kDigits00To99[digits5and6];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text) = 
                kDigits00To99[digits7and8];
            PRINT_PRINTED
            return text + 8;
        }
        else if (value >> 20) {
            comparator = 10000000;
            if (value >= comparator) {
                PRINTF ("\n    Range:[10000000, 16777215] length:8")
                if (text + 8 >= text_end) {
                    return nullptr;
                }
                *text++ = '1';
                PRINT_PRINTED
                value -= comparator;
            }
            else {
                PRINTF ("\n    Range:[1048576, 9999999] length:7")
                if (text + 7 >= text_end) {
                    return nullptr;
                }
            }
            scalar = 10000;
            digits5and6 = (uint16_t)(value / scalar);
            digits1and2 = value - scalar * digits5and6;
            digits7and8 = digits5and6 / 100;
            digits3and4 = digits1and2 / 100;
            digits5and6 -= 100 * digits7and8;
            digits1and2 -= 100 * digits3and4;;
            *reinterpret_cast<uint16_t*> (text + 5) = 
                kDigits00To99[digits1and2];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text + 3) = 
                kDigits00To99[digits3and4];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text + 1) = 
                kDigits00To99[digits5and6];
            PRINT_PRINTED
            *text = (char)digits7and8 + '0';
            return text + 7;
        }
        else if (value >> 17) {
            comparator = 1000000;
            if (value >= comparator) {
                PRINTF ("\n    Range:[100000, 1048575] length:7")
                if (text + 7 >= text_end) {
                    return nullptr;
                }
                *text++ = '1';
                PRINT_PRINTED
                value -= comparator;
            }
            else {
                PRINTF ("\n    Range:[131072, 999999] length:6")
                if (text + 6 >= text_end) {
                    return nullptr;
                }
            }
            Print6:
            scalar = 10000;
            digits5and6 = (uint16_t)(value / scalar);
            digits1and2 = value - scalar * digits5and6;
            digits7and8 = digits5and6 / 100;
            digits3and4 = digits1and2 / 100;
            digits5and6 -= 100 * digits7and8;
            digits1and2 -= 100 * digits3and4;
            text16 = reinterpret_cast<uint16_t*> (text + 6);
            *reinterpret_cast<uint16_t*> (text + 4) = kDigits00To99[digits1and2];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text + 2) = kDigits00To99[digits3and4];
            PRINT_PRINTED
            *reinterpret_cast<uint16_t*> (text    ) = kDigits00To99[digits5and6];
            PRINT_PRINTED
            return text + 6;
        }
        else { // (value >> 14)
            if (value >= 100000) {
                PRINTF ("\n    Range:[65536, 131071] length:6")
                goto Print6;
            }
            PRINTF ("\n    Range:[10000, 65535] length:5")
            if (text + 5 >= text_end) {
                return nullptr;
            }
            digits5and6 = 10000;
            digit = (uint8_t)(value / digits5and6);
            value -= digits5and6 * digit;
            *text = digit + '0';
            PRINT_PRINTED
            digits1and2 = (uint16_t)value;
            digits5and6 = 100;
            digits3and4 = digits1and2 / digits5and6;
            digits1and2 -= digits3and4 * digits5and6;
            *reinterpret_cast<uint16_t*> (text + 1) = 
                kDigits00To99[digits3and4];
            PRINT_PRINTED
                PRINTF ("\n    digits1and2:%u", digits1and2)
            *reinterpret_cast<uint16_t*> (text + 3) = 
                kDigits00To99[digits1and2];
            PRINT_PRINTED
            return text + 5;
        }
    }
    digits1and2 = (uint16_t)value;
    if (value >> 10) {
        digits5and6 = 10000;
        if (digits1and2 >= digits5and6) {
            if (text + 5 >= text_end) {
                return nullptr;
            }
            PRINTF ("\n    Range:[10000, 16383] length:5")
            *text++ = '1';
            PRINT_PRINTED
            digits1and2 -= digits5and6;

        }
        else {
            PRINTF ("\n    Range:[1024, 9999] length:4")
            if (text + 4 >= text_end) {
                return nullptr;
            }
        }
        digits5and6 = 100;
        digits3and4 = digits1and2 / digits5and6;
        digits1and2 -= digits3and4 * digits5and6;
        *reinterpret_cast<uint16_t*> (text    ) = kDigits00To99[digits3and4];
        PRINT_PRINTED
        *reinterpret_cast<uint16_t*> (text + 2) = kDigits00To99[digits1and2];
        PRINT_PRINTED
        return text + 4;
    }
    else {
        if (text + 4 >= text_end) {
            return nullptr;
        }
        digits3and4 = 1000;
        if (digits1and2 >= digits3and4) {
            PRINTF ("\n    Range:[1000, 1023] length:4")
            digits1and2 -= digits3and4;
            text16 = reinterpret_cast<uint16_t*> (text + 2);
            *text16-- = kDigits00To99[digits1and2];
            PRINT_PRINTED
            *text16 = (((uint16_t)'1') | (((uint16_t)'0') << 8));
            PRINT_PRINTED
            return text + 4;
        }
        PRINTF ("\n    Range:[100, 999] length:3")
        digits1and2 = (uint16_t)value;
        digits3and4 = 100;
        digit = (char)(digits1and2 / digits3and4);
        digits1and2 -= digit * digits3and4;
        *text = digit + '0';
        PRINT_PRINTED
        *reinterpret_cast<uint16_t*> (text + 1) = kDigits00To99[digits1and2];
        PRINT_PRINTED
        return text + 3;
    }
}

}       //< namespace _
#undef  PRINTF
#undef  PRINT_PRINTED
#endif  //< MAJOR_SEAM >= 1 && MINOR_SEAM >= 1

লেখক


3
এফওয়াইআই: স্ট্যাক ওভারফ্লোতে এটি পোস্ট করার মাধ্যমে আপনি এটি অনিবার্যভাবে সিসি বাই-এসএ 3.0 এর অধীনে প্রকাশ করেছেন (স্ট্যাক এক্সচেঞ্জের ব্যবহারের শর্তাবলীতে)। এটি আপনার জিপিএল 3 এর অধীনে প্রকাশিত বিবৃতিটি একটি অতিরিক্ত লাইসেন্স গঠন করে যা কোনও ব্যবহারকারী সিসি বাই-এসএ 3.0 এর বিকল্প হিসাবে বিকল্পভাবে ব্যবহার করতে পারে । কোডটি অনুলিপি করা ব্যবহারকারীর বিবেচনার ভিত্তিতে কোন লাইসেন্স ব্যবহার করা উচিত। যদি এটি আপনার পক্ষে সমস্যা হয় তবে আমি আপনাকে উপযুক্ত আইনী পরামর্শ নেওয়ার পরামর্শ দিই। (IANAL) নোট করুন যে এর সাথে অন্তর্নিহিত কোনও ভুল নেই, তবে আমি অনুভব করেছি যে এটি আপনার নজরে আনা উচিত।
মাকিন

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

আমি এটা করতে ভুলে গেছি। এটি কেবল অন্য একটি র‍্যাপার ফাংশন। আমার সমস্ত জিনিস অ্যাপাচি লাইসেন্সযুক্ত তবে আমি ভেবেছিলাম আমি জিএনইউ চেষ্টা করব তবে হ্যাঁ ... এটির কোনও মানে হয় না।

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

আমি সবেমাত্র অ্যালগরিদম আপডেট করেছি এবং বৃহত সংখ্যার উল্লেখযোগ্য উন্নতি করেছি।

0

ব্যবহারকারী 434507 এর সমাধানে পরিবর্তন। সি ++ স্ট্রিংয়ের পরিবর্তে অক্ষর অ্যারে ব্যবহার করতে পরিবর্তিত। কিছুটা দ্রুত চালায়। কোডে 0 টির জন্য চেকও সরানো হয়েছে ... কারণ এটি আমার বিশেষ ক্ষেত্রে কখনও হয় না। যদি এটি আপনার ক্ষেত্রে আরও সাধারণ হয় তবে এটিকে আবার সরিয়ে দিন।

// Int2Str.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <iostream>
#include "StopWatch.h"

using namespace std;

const char digit_pairs[201] = {
  "00010203040506070809"
  "10111213141516171819"
  "20212223242526272829"
  "30313233343536373839"
  "40414243444546474849"
  "50515253545556575859"
  "60616263646566676869"
  "70717273747576777879"
  "80818283848586878889"
  "90919293949596979899"
};

void itostr(int n, char* c) {
    int sign = -(n<0);
    unsigned int val = (n^sign)-sign;

    int size;
    if(val>=10000) {
        if(val>=10000000) {
            if(val>=1000000000) {
                size=10;
            }
            else if(val>=100000000) {
                size=9;
            }
            else size=8;
        }
        else {
            if(val>=1000000) {
                size=7;
            }
            else if(val>=100000) {
                size=6;
            }
            else size=5;
        }
    }
    else {
        if(val>=100) {
            if(val>=1000) {
                size=4;
            }
            else size=3;
        }
        else {
            if(val>=10) {
                size=2;
            }
            else if(n==0) {
                c[0]='0';
                c[1] = '\0';
                return;
            }
            else size=1;
        }
    }
    size -= sign;
    if(sign)
    *c='-';

    c += size-1;
    while(val>=100) {
        int pos = val % 100;
        val /= 100;
        *(short*)(c-1)=*(short*)(digit_pairs+2*pos); 
        c-=2;
    }
    while(val>0) {
        *c--='0' + (val % 10);
        val /= 10;
    }
    c[size+1] = '\0';
}

void itostr(unsigned val, char* c)
{
    int size;
    if(val>=10000)
    {
        if(val>=10000000)
        {
            if(val>=1000000000)
                size=10;
            else if(val>=100000000)
                size=9;
            else 
                size=8;
        }
        else
        {
            if(val>=1000000)
                size=7;
            else if(val>=100000)
                size=6;
            else
                size=5;
        }
    }
    else 
    {
        if(val>=100)
        {
            if(val>=1000)
                size=4;
            else
                size=3;
        }
        else
        {
            if(val>=10)
                size=2;
            else if (val==0) {
                c[0]='0';
                c[1] = '\0';
                return;
            }
            else
                size=1;
        }
    }

    c += size-1;
    while(val>=100)
    {
       int pos = val % 100;
       val /= 100;
       *(short*)(c-1)=*(short*)(digit_pairs+2*pos); 
       c-=2;
    }
    while(val>0)
    {
        *c--='0' + (val % 10);
        val /= 10;
    }
    c[size+1] = '\0';
}

void test() {
    bool foundmismatch = false;
    char str[16];
    char compare[16];
    for(int i = -1000000; i < 1000000; i++) {
        int random = rand();
        itostr(random, str);
        itoa(random, compare, 10);
        if(strcmp(str, compare) != 0) {
            cout << "Mismatch found: " << endl;
            cout << "Generated: " << str << endl;
            cout << "Reference: " << compare << endl;
            foundmismatch = true;
        }
    }
    if(!foundmismatch) {
        cout << "No mismatch found!" << endl;
    }
    cin.get();
}

void benchmark() {
    StopWatch stopwatch;
    stopwatch.setup("Timer");
    stopwatch.reset();
    stopwatch.start();
    char str[16];
    for(unsigned int i = 0; i < 2000000; i++) {
        itostr(i, str);
    }
    stopwatch.stop();
    cin.get();
}

int main( int argc, const char* argv[]) {
    benchmark();
}

2
আমি এটি 0x80000000 থেকে 0x7FFFFFFF পর্যন্ত পরীক্ষা করেছি এবং ইতিমধ্যে -999999999 এ আপনি অবৈধ মান পেয়েছেন (কয়েকটি অমিলের পরে আমি থামিয়েছি)। Mismatch found: Generated: -9999999990 Reference: -999999999 Mismatch found: Generated: -9999999980 Reference: -999999998 Mismatch found: Generated: -9999999970 Reference: -999999997
ওয়াল্ডেমার

0

আমরা নিম্নলিখিত কোডটি ব্যবহার করি (এমএসভিসির জন্য):

টেম্পলেটেড টিবিটস্ক্যানরাইভার্স:

#include <intrin.h>

namespace intrin {

#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanReverse64)

template<typename TIntegerValue>
__forceinline auto tBitScanReverse(DWORD * out_index, TIntegerValue mask)
    -> std::enable_if_t<(std::is_integral<TIntegerValue>::value && sizeof(TIntegerValue) == 4), unsigned char>
{
    return _BitScanReverse(out_index, mask);
}
template<typename TIntegerValue>
__forceinline auto tBitScanReverse(DWORD * out_index, TIntegerValue mask)
    -> std::enable_if_t<(std::is_integral<TIntegerValue>::value && sizeof(TIntegerValue) == 8), unsigned char>
{
#if !(_M_IA64 || _M_AMD64)
    auto res = _BitScanReverse(out_index, (unsigned long)(mask >> 32));
    if (res) {
        out_index += 32;
        return res;
    }
    return _BitScanReverse(out_index, (unsigned long)mask);
#else
    return _BitScanReverse64(out_index, mask);
#endif
}

}

চর / wchar_t সহায়ক:

template<typename TChar> inline constexpr TChar   ascii_0();
template<>               inline constexpr char    ascii_0() { return  '0'; }
template<>               inline constexpr wchar_t ascii_0() { return L'0'; }

template<typename TChar, typename TInt> inline constexpr TChar ascii_DEC(TInt d) { return (TChar)(ascii_0<TChar>() + d); }

10 টেবিলের শক্তি:

static uint32 uint32_powers10[] = {
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000
//   123456789
};
static uint64 uint64_powers10[] = {
    1ULL,
    10ULL,
    100ULL,
    1000ULL,
    10000ULL,
    100000ULL,
    1000000ULL,
    10000000ULL,
    100000000ULL,
    1000000000ULL,
    10000000000ULL,
    100000000000ULL,
    1000000000000ULL,
    10000000000000ULL,
    100000000000000ULL,
    1000000000000000ULL,
    10000000000000000ULL,
    100000000000000000ULL,
    1000000000000000000ULL,
    10000000000000000000ULL
//   1234567890123456789
};

template<typename TUint> inline constexpr const TUint  * powers10();
template<>               inline constexpr const uint32 * powers10() { return uint32_powers10; }
template<>               inline constexpr const uint64 * powers10() { return uint64_powers10; }

আসল মুদ্রণ:

template<typename TChar, typename TUInt>
__forceinline auto
print_dec(
    TUInt u,
    TChar * & buffer) -> typename std::enable_if_t<std::is_unsigned<TUInt>::value>
{
    if (u < 10) {                                                   // 1-digit, including 0  
        *buffer++ = ascii_DEC<TChar>(u);
    }
    else {
        DWORD log2u;
        intrin::tBitScanReverse(&log2u, u);                         //  log2u [3,31]  (u >= 10)
        DWORD log10u = ((log2u + 1) * 77) >> 8;                     //  log10u [1,9]   77/256 = ln(2) / ln(10)
        DWORD digits = log10u + (u >= powers10<TUInt>()[log10u]);   //  digits [2,10]

        buffer += digits;
        auto p = buffer;

        for (--digits; digits; --digits) {
            auto x = u / 10, d = u - x * 10;
            *--p = ascii_DEC<TChar>(d);
            u = x;
        }
        *--p = ascii_DEC<TChar>(u);
    }
}

শেষ লুপটি নিবন্ধভুক্ত করা যেতে পারে:

switch (digits) {
case 10: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  9: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  8: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  7: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  6: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  5: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  4: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  3: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; }
case  2: { auto x = u / 10, d = u - x * 10; *--p = ascii_DEC<TChar>(d); u = x; *--p = ascii_DEC<TChar>(u); break; }
default: __assume(0);
}

মূল ধারণাটি @atlaste এর আগে প্রস্তাবিত হিসাবে একই: https://stackoverflow.com/a/29039967/2204001


0

সবেমাত্র সাম্প্রতিক ক্রিয়াকলাপের কারণে এটি জুড়ে এসেছে; আমার কাছে বেঞ্চমার্ক যুক্ত করার সত্যিই সময় নেই, তবে আমি যখন স্ট্রিং রূপান্তরটিতে দ্রুত পূর্ণসংখ্যার প্রয়োজন তখন অতীতে যা লিখেছিলাম তা যুক্ত করতে চেয়েছিলাম ...

https://github.com/CarloWood/ai-utils/blob/master/itoa.h
https://github.com/CarloWood/ai-utils/blob/master/itoa.cxx

এখানে ব্যবহৃত কৌশলটি হ'ল ব্যবহারকারীকে অবশ্যই একটি স্টাড :: অ্যারের সরবরাহ করতে হবে যা যথেষ্ট পরিমাণে বড় (তাদের স্ট্যাকের উপরে) এবং এই কোডটি স্ট্রিংটি সেই পেছনের দিকে লিখে ইউনিটগুলি শুরু করে এবং তারপরে একটি পয়েন্টারটি অফসেট দিয়ে অ্যারেতে ফিরে আসে যেখানে ফলাফল আসলে শুরু হয়।

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


-1

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

if(val >= 0)
{
    div_t   d2 = div(val,100);
    while(d2.quot)
    {
        COPYPAIR(it,2 * d2.rem);
        it-=2;
        d2 = div(d2.quot,100);
    }
    COPYPAIR(it,2*d2.rem);
    if(d2.quot<10)
        it++;
}
else
{
    div_t   d2 = div(val,100);
    while(d2.quot)
    {
        COPYPAIR(it,-2 * d2.rem);
        it-=2;
        d2 = div(d2.quot,100);
    }
    COPYPAIR(it,-2*d2.rem);
    if(d2.quot<=-10)
        it--;
    *it = '-';
}

ঠিক আছে, স্বাক্ষরযুক্ত স্বাক্ষরের জন্য, ডিভ ফাংশনটি ব্যবহার করা যাবে না তবে স্বাক্ষরযুক্ত স্বতন্ত্রভাবে পৃথকভাবে পরিচালনা করা যায়।
ডিজিট পেয়ার থেকে কীভাবে 2 টি অক্ষর অনুলিপি করতে হয় তার বিভিন্নতা পরীক্ষা করার জন্য আমি কপিপায়ার ম্যাক্রোকে সংজ্ঞায়িত করেছি (এই পদ্ধতির কোনওরূপে কোনও সুস্পষ্ট সুবিধা পাওয়া যায় নি):

#define COPYPAIR0(_p,_i) { memcpy((_p), &digit_pairs[(_i)], 2); }
#define COPYPAIR1(_p,_i) { (_p)[0] = digit_pairs[(_i)]; (_p)[1] = digit_pairs[(_i)+1]; }
#define COPYPAIR2(_p,_i) { unsigned short * d = (unsigned short *)(_p); unsigned short * s = (unsigned short *)&digit_pairs[(_i)]; *d = *s; }

#define COPYPAIR COPYPAIR2

1
কারণ এই চ্যালেঞ্জটি কোডের কয়েকটি লাইন নয়, গতি সম্পর্কে।
বেন ভয়েগট

1
পিএস: এবং যে লোকেরা আমার সমাধানটিতে এটি ব্যবহার করতে চান তাদের জন্য: (1) এটি অনেক ধীর এবং (2) কারণ ডিভ স্বাক্ষরিত পূর্ণসংখ্যার উপর কাজ করে - যা অ্যাবস ভাঙে (INT32_MIN)।
এটলস্টে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.