স্ট্যান্ড :: ক্রোনো :: বছরের স্টোরেজটি কি আসলে কমপক্ষে 17 বিট?


14

Cppreferences থেকে

std::chrono::years (since C++20) duration</*signed integer type of at least 17 bits*/, std::ratio<31556952>>

ব্যবহার libc++তা নিম্নরেখাঙ্কিত স্টোরেজ বলে মনে হয় std::chrono::yearsহয় shortযা সাইন করা হয়েছে 16 বিট

std::chrono::years( 30797 )        // yields  32767/01/01
std::chrono::years( 30797 ) + 365d // yields -32768/01/01 apparently UB

সিপ্রিফারেন্স বা অন্য কিছু নিয়ে টাইপো আছে ?

উদাহরণ:

#include <fmt/format.h>
#include <chrono>

template <>
struct fmt::formatter<std::chrono::year_month_day> {
  char presentation = 'F';

  constexpr auto parse(format_parse_context& ctx) {
    auto it = ctx.begin(), end = ctx.end();
    if (it != end && *it == 'F') presentation = *it++;

#   ifdef __exception
    if (it != end && *it != '}') {
      throw format_error("invalid format");
    }
#   endif

    return it;
  }

  template <typename FormatContext>
  auto format(const std::chrono::year_month_day& ymd, FormatContext& ctx) {
    int year(ymd.year() );
    unsigned month(ymd.month() );
    unsigned day(ymd.day() );
    return format_to(
        ctx.out(),
        "{:#6}/{:#02}/{:#02}",
        year, month, day);
  }
};

using days = std::chrono::duration<int32_t, std::ratio<86400> >;
using sys_day = std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int32_t, std::ratio<86400> >>;

template<typename D>
using sys_time = std::chrono::time_point<std::chrono::system_clock, D>;
using sys_day2 = sys_time<days>;

int main()
{
  auto a = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::hours( (1<<23) - 1 ) 
      )
    )
  );

  auto b = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::minutes( (1l<<29) - 1 ) 
      )
    )
  );

  auto c = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::seconds( (1l<<35) - 1 ) 
      )
    )
  );

  auto e = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::days( (1<<25) - 1 ) 
      )
    )
  );

  auto f = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::weeks( (1<<22) - 1 ) 
      )
    )
  );

  auto g = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::months( (1<<20) - 1 ) 
      )
    )
  );

  auto h = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::years( 30797 ) // 0x7FFF - 1970
      )
    )
  );

  auto i = std::chrono::year_month_day( 
    sys_day( 
      std::chrono::floor<days>(
        std::chrono::years( 30797 ) // 0x7FFF - 1970
      ) + std::chrono::days(365)
    )
  );

  fmt::print("Calendar limit by duration's underlining storage:\n"
             "23 bit hour       : {:F}\n"
             "29 bit minute     : {:F}\n"
             "35 bit second     : {:F}\n"
             "25 bit days       : {:F}\n"
             "22 bit week       : {:F}\n"
             "20 bit month      : {:F}\n"
             "16? bit year      : {:F}\n"
             "16? bit year+365d : {:F}\n"
             , a, b, c, e, f, g, h, i);
}

[ গডবোল্ট লিঙ্ক ]


2
yearব্যাপ্তি: eel.is/c++draft/time.cal.year# মেম্বার 19-19 years রেঞ্জ: eel.is/c++draft/time.synyearএটি নাগরিক বছরের "নাম" এবং 16 বিটগুলির প্রয়োজন requires yearsএকটি ক্রোনো সময়কাল, একটি হিসাবে একই জিনিস নয় year। একজন দুটি বিয়োগ করতে পারে yearএবং ফলাফলের ধরন রয়েছে yearsyearsএর ফলাফলটি ধারণ করতে সক্ষম হতে হবে year::max() - year::min()
হাওয়ার্ড হিনান্ট

1
std::chrono::years( 30797 ) + 365dসংকলন করে না
হাওয়ার্ড হিনান্ট

1
ফলে years{30797} + days{365}216s এর ইউনিট 204528013 হয়।
হাওয়ার্ড হিনান্ট

1
এটি মাত্র দুটি সময়সীমা যুক্ত করা হচ্ছে। নিষিদ্ধ করার অর্থ এটি নিষিদ্ধ করা hours{2} + seconds{5}
হাওয়ার্ড হিন্যান্ট

4
আমার অনুমান যে আপনার সময়কাল ধরনের সঙ্গে calendrical উপাদান বিভ্রান্ত করছেন, কারণ তারা হয় না যেমন একই নামের আছে। এখানে একটি সাধারণ নিয়ম আছে: durationনাম বহুবচন হল: years, months, days। Calendrical উপাদান নাম একবচন আছেন: year, month, dayyear{30797} + day{365}একটি সংকলন-সময় ত্রুটি। year{2020}এই বছর হয়। years{2020}2020 বছর দীর্ঘ সময়কাল।
হাওয়ার্ড হিনান্ট

উত্তর:


8

Cppreferences নিবন্ধটি সঠিক । যদি libc ++ একটি ছোট প্রকার ব্যবহার করে তবে এটি libc ++ এ ত্রুটি বলে মনে হচ্ছে।


তবে wordসম্ভবত এমন একটি অন্য যুক্ত করা যা year_month_dayভেক্টরকে অদম্যভাবে বাল্কিং করবে না ? যে গেল at least 17 bitsnorminal পাঠ্য হিসেবে গণনা করা যাবে?
স্যান্ডথর্ন

3
@ স্যান্ডথর্নে year_month_dayরয়েছে year, নেই years। প্রতিনিধিত্ব year16-বিট করা প্রয়োজন হয় না, যদিও প্রকারটি shortপ্রদর্শন হিসাবে ব্যবহৃত হয়। ওটিও, yearsসংজ্ঞাটির 17 বিট অংশটি আদর্শিক কারণ এটি কেবলমাত্র প্রকাশের হিসাবে চিহ্নিত করা হয়নি। এবং খোলামেলাভাবে বলছি যে এটি কমপক্ষে 17 বিট টিএস করে এবং তারপরে এটির প্রয়োজন হয় না তা অর্থহীন।
আন্দ্রে সেমাশেভ

1
আহ yearমধ্যে year_month_dayমনে করা হয় intপ্রকৃতপক্ষে। => অপারেটর ইন্ট আমি মনে করি এটি at least 17 bits yearsবাস্তবায়ন সমর্থন করে ।
স্যান্ডথর্ন

আপনার উত্তর সম্পাদনা করতে আপনি কি আপত্তি করবেন? এটি স্ট্যান্ড :: ক্রোনো :: বছরগুলি আসলে ইনটি এবং স্টাডেন্ট :: ক্রোনো :: সাল নির্ধারিতভাবে সর্বোচ্চ 32767 এ ..
স্যান্ডথর্ন

@ স্যান্ডথর্ন উত্তরটি সঠিক, আমি কেন এটি সম্পাদনা করতে হবে তা দেখছি না।
আন্দ্রে সেমাসেভ

4

আমি https://godbolt.org/z/SNivyp টুকরো টুকরো টুকরো করে উদাহরণটি ভেঙে দিচ্ছি :

  auto a = std::chrono::year_month_day( 
    sys_days( 
      std::chrono::floor<days>(
        std::chrono::years(0) 
        + std::chrono::days( 365 )
      )
    )
  );

সরলকরণ এবং অনুমান using namespace std::chronoকরার সুযোগ রয়েছে:

year_month_day a = sys_days{floor<days>(years{0} + days{365})};

উপ-অভিব্যক্তি years{0}একটি হল durationএকটি সঙ্গে periodসমান ratio<31'556'952>এবং একটি মান সমান 0। নোট করুন যে years{1}, ভাসমান-পয়েন্ট হিসাবে প্রকাশিত daysহুবহু 365.2425। এটি নাগরিক বছরের গড় দৈর্ঘ্য।

উপ-অভিব্যক্তি days{365}একটি হল durationএকটি সঙ্গে periodসমান ratio<86'400>এবং একটি মান সমান 365

উপ-অভিব্যক্তি years{0} + days{365}একটি হল durationএকটি সঙ্গে periodসমান ratio<216>এবং একটি মান সমান 146'000। এই প্রথম গবেষনার দ্বারা গঠিত common_type_tএর ratio<31'556'952>এবং ratio<86'400>যা GCD (31'556'952, 86'400), অথবা 216. গ্রন্থাগার প্রথম ধর্মান্তরিত এই সাধারণ ইউনিট উভয় operands হয়, এবং তারপর সাধারণ ইউনিটে উপরন্তু আছে।

years{0}216s সময়কালে ইউনিটগুলিতে রূপান্তর করতে একটিকে অবশ্যই 146'097 দ্বারা 0 দিয়ে গুণ করতে হবে। এটি একটি খুব গুরুত্বপূর্ণ বিষয় হতে পারে। এই রূপান্তরটি কেবল 32 বিট দিয়ে সম্পন্ন হলে সহজেই ওভারফ্লো হতে পারে।

<সরাইয়া>

যদি এই মুহুর্তে আপনি বিভ্রান্ত বোধ করেন তবে কোডটি সম্ভবত একটি ক্যালেন্ড্রিকাল গণনা করতে চায় তবে এটি আসলে কালানুক্রমিক গণনা করছে। ক্যালেন্ডারিকাল গণনাগুলি ক্যালেন্ডারগুলির সাথে গণনা।

ক্যালেন্ডারে সমস্ত ধরণের অনিয়ম রয়েছে যেমন কয়েক মাস এবং বছর বিভিন্ন দৈহিক দৈর্ঘ্যের হিসাবে থাকে। একটি ক্যালেন্ডারিক্যাল গণনা এই অনিয়মগুলিকে আমলে নেয়।

একটি কালানুক্রমিক গণনা স্থির ইউনিটগুলির সাথে কাজ করে এবং ক্যালেন্ডার বিবেচনা না করে কেবল সংখ্যাগুলি ক্র্যাঙ্ক করে। আপনি গ্রেগরিয়ান ক্যালেন্ডার, জুলিয়ান ক্যালেন্ডার, হিন্দু ক্যালেন্ডার, চাইনিজ ক্যালেন্ডার ইত্যাদি ব্যবহার করেন তবে কালানুক্রমিক গণনা পাত্তা দেয় না

</ সরাইয়া>

এরপরে আমরা আমাদের 146000[216]sসময়কাল নিয়ে থাকি এবং এটির সাথে একটি (যা টাইপ-ওরফে নামকরণ করে ) periodএর সাথে একটি স্থানে রূপান্তর করি । ফাংশনটি এই রূপান্তরটি করে এবং ফলাফলটি আরও বেশি সহজভাবে, খালি ।ratio<86'400>daysfloor<days>()365[86400]s365d

পরবর্তী পদক্ষেপটি নেয় durationএবং এটিকে রূপান্তর করে time_point। ধরণ time_pointহয় time_point<system_clock, days>যা একটি টাইপ-ওরফে নাম দিয়েছে sys_days। এটি লিপ সেকেন্ড বাদে 1970-০1-01 00:00:00 ইউটিসি- dayssystem_clockযুগের পর থেকে কেবল একটি গণনা ।

অবশেষে মানটি sys_daysএকটিতে রূপান্তরিত year_month_dayহয় 1971-01-01

এই গণনাটি করার একটি সহজ উপায় হ'ল:

year_month_day a = sys_days{} + days{365};

এই অনুরূপ গণনা বিবেচনা করুন:

year_month_day j = sys_days{floor<days>(years{14699} + days{0})};

তারিখে এই ফলাফল 16668-12-31। যা সম্ভবত আপনি প্রত্যাশার চেয়ে এক দিন আগে ((14699 + 1970) -01-01)। Subexpression years{14699} + days{0}এখন হচ্ছে: 2'147'479'803[216]s। দ্রষ্টব্য যে রান-টাইম মানটি INT_MAX( 2'147'483'647) কাছাকাছি চলে এসেছে এবং এটি repউভয়ের অন্তর্নিহিত yearsএবং daysএটি int

প্রকৃতপক্ষে যদি আপনি রূপান্তর years{14700}ইউনিট করা [216]sআপনি ওভারফ্লো পাবেন: -2'147'341'396[216]s

এটি ঠিক করতে, একটি ক্যালেন্ডারিক্যাল গণনায় স্যুইচ করুন:

year_month_day j = (1970y + years{14700})/1/1;

এ সব ফলাফল https://godbolt.org/z/SNivyp যে যোগ করা হয় yearsএবং daysএবং জন্য একটি মান ব্যবহার yearsকরে 14699 চেয়ে অনেক বেশী সম্মুখীন হয় intওভারফ্লো।

এক সত্যিই সঙ্গে কালানুক্রমিক কম্পিউটেশন করতে চায় তাহলে yearsএবং daysএই ভাবে, তাহলে এটি জ্ঞানী 64 বিট গাণিতিক ব্যবহার করতে হবে। গণনা শুরুর দিকে 32 টিরও বেশি বিট ব্যবহার করে yearsইউনিটগুলিতে রূপান্তর করে এটি সম্পাদন করা যায় rep। উদাহরণ স্বরূপ:

years{14700} + 0s + days{0}

যোগ 0sকরে years, ( secondsকমপক্ষে 35 বিট থাকতে হবে), তারপরে common_type repপ্রথম সংযোজনের জন্য 64 টি বিট করতে বাধ্য করা হবে ( years{14700} + 0s) এবং যোগ করার সময় b৪ বিটে চালিয়ে যেতে হবে days{0}:

463'887'194'400s == 14700 * 365.2425 * 86400

মধ্যবর্তী ওভারফ্লো এড়ানোর আরেকটি উপায় (এই সীমাতে) আরও যুক্ত করার আগে নির্ভুলতায় কেটে yearsযাওয়া :daysdays

year_month_day j = sys_days{floor<days>(years{14700})} + days{0};

jমান আছে 16669-12-31। এটি সমস্যা এড়ায় কারণ এখন [216]sইউনিটটি কখনই প্রথম স্থানে তৈরি হয় না। আর আমরা কখনো এমনকি সীমার কাছাকাছি পেতে years, daysবা year

যদিও আপনি যদি প্রত্যাশা করে থাকেন 16700-01-01তবে আপনার এখনও সমস্যা রয়েছে এবং এটি সংশোধন করার উপায় হ'ল পরিবর্তে একটি ক্যালেন্ডারিক্যাল গণনা করা:

year_month_day j = (1970y + years{14700})/1/1;

1
দুর্দান্ত ব্যাখ্যা। কালানুক্রমিক গণনা সম্পর্কে আমি উদ্বিগ্ন। আমি years{14700} + 0s + days{0}যদি কোনও কোডবেসে দেখতে পাই তবে 0sসেখানে কী করছে এবং এটি কতটা গুরুত্বপূর্ণ তা আমার কোনও ধারণা নেই । কোনও বিকল্প, সম্ভবত আরও সুস্পষ্ট উপায় আছে? duration_cast<seconds>(years{14700}) + days{0}ভালো কিছু হবে?
বলভ

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

1
কেউ একটি কাস্টম সময়কাল তৈরি করতে পারে: use llyears = duration<long long, years::period>;এবং তারপরে এটি ব্যবহার করুন। তবে সম্ভবত সবচেয়ে ভাল বিষয়টি হল আপনি কী অর্জন করতে চাইছেন সে সম্পর্কে চিন্তাভাবনা করা এবং আপনি এটি সঠিক পথে চালাচ্ছেন কিনা তা নিয়ে প্রশ্ন করা। উদাহরণস্বরূপ, আপনার কি 10 হাজার বছর বয়সী টাইম স্কেলে ডে-স্পষ্টতা দরকার? নাগরিক ক্যালেন্ডারটি 4 হাজার বছরে প্রায় 1 দিনের জন্য সঠিক। সম্ভবত একটি ভাসমান পয়েন্ট সহস্রাব্দ একটি ভাল ইউনিট হবে?
হাওয়ার্ড হিনান্ট

স্পেসিফিকেশন: সিভিল ক্যালেন্ডারের ক্রোনোর ​​মডেলিং -32767/1/1 থেকে 32767/12/31 এর মধ্যে রয়েছে। সৌরজগতের মডেলিংয়ের ক্ষেত্রে সিভিল ক্যালেন্ডারের যথার্থতা 4 হাজার বছরে প্রায় 1 দিন।
হাওয়ার্ড হিনান্ট

1
এটা সত্যিই ব্যবহারের ক্ষেত্রে উপর নির্ভর করবে এবং আমি বর্তমানে যোগ করার জন্য একটি প্রেরণার ব্যবহারের ক্ষেত্রে কষ্ট চিন্তা হচ্ছে yearsএবং days। এটি আক্ষরিকভাবে কয়েকটি অবিচ্ছেদ্য সংখ্যায় 365.2425 দিনের একাধিক সংযোজন করছে। সাধারণত আপনি যদি মাস বা বছরের ক্রম অনুসারে কালানুক্রমিক গণনা করতে চান তবে এটি কিছু পদার্থবিজ্ঞান বা জীববিজ্ঞানের মডেল করা। সম্ভবত যুক্ত monthsকরার বিভিন্ন উপায়ে এই পোস্টটি system_clock::time_pointদুই ধরণের গণনার মধ্যে পার্থক্যটি পরিষ্কার করতে সহায়তা করবে: স্ট্যাকওভারফ্লো.com
হাওয়ার্ড হিন্যান্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.