Learn C Programming

lesson ৬ / ৭ · Variable আর data type

Module ২ · Variable আর data type

Problem: variable আর type

FreeProblem

এই lesson-এ যা শিখবে

  • প্রথম লাইন লেখার আগেই একটা সমস্যার জন্য দরকারি type বেছে নিতে পারবে।
  • Judge যে চেহারায় সংখ্যা চায়, দশমিক সহ ঠিক সেই চেহারায় ছাপতে পারবে।
  • Constraints-র দুই প্রান্তে program পরীক্ষা করতে পারবে, যেখানে type ছেড়ে দেয়।

দশটা সমস্যা, লুকানো test-র বিরুদ্ধে judge করা। এর আটটার সঙ্গে পাঁচটা lesson-এ তোমার দেখা হয়েছে। দুইটা নতুন।

আগের set ছিল ছাপা নিয়ে। এটা বাছা নিয়ে। নিচের প্রায় প্রতিটা সমস্যায় এমন একটা type আছে যেটা কাজ করে আর একটা যেটা চুপচাপ করে না, আর তুমি কোনটা বেছেছ সেটা কেবল judge-ই বলবে।

আগের problem set-র পরে নতুন কী

Module 1-এ প্রতিটা সমস্যা তুমি যা দিয়েছ সেটাই ছেপেছে। এখানে উত্তরটাকে আগে একটা হিসাব পেরিয়ে টিকে থাকতে হবে।

এতে ভুল উত্তরের চেহারা বদলে যায়। ওটা আর একটা বাদ পড়া space হবে না। ওটা হবে এমন একটা সংখ্যা, যেটা ছোট input-এ ঠিক আর বড় input-এ ভুল।

নিচের তিনটা সমস্যায় একটা input সীমার একদম মাথায়, আর ওগুলোই সেই test যেগুলো int বাছলে ব্যর্থ হয়। একটায় এমন একটা input আছে যেটা double বাছলে ব্যর্থ হয়।

তাই গল্পের আগে Constraints পড়ো, আর type-টা ওখানেই ঠিক করো।

লাইন লেখার আগে type বাছা

চারটা প্রশ্ন প্রতিবারই এর উত্তর দেয়।

  1. মানটা কি ঋণাত্মক হতে পারে? না হলে unsigned খোলা আছে, আর তাও কেন নাও নিতে পারো সেটা lesson 2 বলেছে।
  2. হিসাবের মাঝপথ সহ ওটা কত বড় হতে পারে? দুইশো কোটির বেশি মানে long long। দুইটা অনুমোদিত input-র যোগফলও মাঝপথের মধ্যে পড়ে।
  3. এটা কি গুনছে না মাপছে? গোনা মানে integer। মাপা হলে double হতে পারে।
  4. এটা কি টাকা? তাহলে এটা গোনা, পয়সায়, একটা long long-এ।

দ্বিতীয় প্রশ্নেই বেশির ভাগ ব্যর্থতা লুকিয়ে। safe-sum-এ প্রতিটা input একটা int-এ আরামসে ধরে, আর ওদের যোগফল ধরে না।

তাই নিয়মটা হলো: তোমার program যে সবচেয়ে বড় মান পড়বে সেটা না, বরং যে সবচেয়ে বড় মান ধরে রাখবে সেটা দেখো।

Judge যে চেহারায় সংখ্যা চায়

Judge লেখা মেলায়। ঠিক মান আর ভুল চেহারা মানে শূন্য, ঠিক যেমনটা Module 1-এ ছিল।

এই দশটা সমস্যায় যে specifier লাগে

printf("%d\n",   n)        একটা int
printf("%lld\n", n)        একটা long long
printf("%u\n",   n)        একটা unsigned int
printf("%.2f\n", x)        একটা double, ঠিক দুই দশমিক ঘর
printf("%.1f\n", x)        একটা double, ঠিক এক দশমিক ঘর
printf("%lld.%02lld\n", taka, paisa)    পূর্ণ টাকা, তারপর দুই অঙ্কের পয়সা

scanf("%d",   &n)          একটা int
scanf("%lld", &n)          একটা long long
scanf("%lf",  &x)          একটা double, l-টা খেয়াল করো
  • scanf-এ %f একটা float পড়ে আর একটা double নষ্ট করে। এখানে এটাই সবচেয়ে সাধারণ নীরব ব্যর্থতা।
  • %.2f রাখা মানটাকে round করে, আর সেটা সবসময় তোমার লেখা মান না।
  • %02lld দুই অঙ্কে শূন্য দিয়ে ভরে দেয়, আর ওভাবেই 5 পয়সা 05 হয়ে ছাপে।
  • নিচের প্রতিটা starter-এ ঠিক scanf লাইনটা আগে থেকেই আছে। ওটা ছুঁয়ো না।

এখনো কোনো loop নেই, কোনো শর্তও নেই

এখানে কিছুতেই if বা for লাগে না, আর Module 5 আর 6 এখনো আসেনি।

তিনটা সমস্যা হ্যাঁ বা না প্রশ্ন করে, আর উত্তরটা একটা তুলনা। একটা তুলনা এমন একটা expression যার মান 1 বা 0, যেটা lesson 4 দেখিয়েছে, তাই ওটা তুমি %d দিয়ে ছাপো।

দুইটা সমস্যায় ভাগশেষ লাগে, যেটা Module 4-র % operator। Lesson 2-র অনুশীলন ৪ /, * আর - দিয়ে একটা ভাগশেষ বানিয়েছে, আর সেটাই এখানে চাওয়া পথ।

তাই যদি এমন কিছুর দিকে হাত বাড়াতে থাকো যেটা এখনো শেখোনি, সমস্যাটা তোমাকে বলছে সামনে না তাকিয়ে একটা lesson আবার পড়তে।

জমা দেওয়ার আগে কীভাবে পরীক্ষা করবে

চারটা পরীক্ষা, আর দ্বিতীয়টা Module 1-রটার থেকে আলাদা।

  1. Sample-টা চালাও। Sample ব্যর্থ হলে আর কিছুরই মানে নেই।
  2. Constraints-র দুই প্রান্ত চালাও। Statement থেকে সবচেয়ে বড় অনুমোদিত input copy করে বসিয়ে দাও। ভুল type এই পরীক্ষাটাই ধরে।
  3. নিজের output-র অক্ষর গোনো sample-র সঙ্গে মিলিয়ে। দশমিক ঘর, space, কমা।
  4. উত্তরটা কী হওয়া উচিত জিজ্ঞেস করো সবচেয়ে বড় input-র জন্য, কাগজে। নিজের বের করা সংখ্যার সঙ্গে program একমত হলে কাজ শেষ।

তাই পরীক্ষা মানে program আবার পড়া না। মানে statement-এ আগেই বলে দেওয়া input-গুলোতে ওটা চালানো।

Hint-র সিঁড়ি

নিচের প্রতিটা সমস্যায় তিনটা ধাপ আছে, যেগুলো তুমি ক্রমে খোলো। Hint 1 বলে কী খেয়াল করতে হবে, Hint 2 পথটা কথায় বোঝায়, আর Solution পুরো পদ্ধতিটা দুই অনুচ্ছেদে ব্যাখ্যা করে।

Hint খোলা লেখা থাকে আর তাতে কিছু খরচ হয় না। এরপর program-টা নিজে টাইপ করো, কারণ পড়াটা দক্ষতা না।

Example 1: একটা পুরো সমস্যা, সমাধান করা, type বুঝে বেছে

এমন দুইটা মান পড়ো যাদের প্রতিটা একটা int-এ ধরে, আর এমন একটা যোগফল ছাপো যেটা ধরে না।

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 0;
    scanf("%d %d", &a, &b);

    long long sum = (long long)a + b;

    printf("%lld\n", sum);
    return 0;
}
4000000000

ওই output 2000000000 2000000000 input-র জন্য। Cast-টা +-র বাঁ পাশে, তাই যোগটা নিজেই চওড়া type-এ হয়। ওটাকে বাইরে সরালে চওড়া করার আগেই উত্তরটা নষ্ট হয়ে যায়।

Run in Compiler
Example 2: ঠিক দুই দশমিক ঘর

এই চারটা সমস্যার দরকারি চেহারা: একটা দশমিক পড়ো, হিসাব করো, নির্দিষ্ট সংখ্যক ঘর পর্যন্ত ছাপো।

#include <stdio.h>

int main(void)
{
    double side = 0.0;
    scanf("%lf", &side);

    double area = side * side;

    printf("%.2f\n", area);
    return 0;
}
6.25

ওই output 2.5 input-র জন্য। %lf-কে %f করে দাও, আর program প্রতিটা input-র জন্য 0.00 ছাপবে, compiler-র কাছ থেকে একটাও message ছাড়াই।

Run in Compiler
Example 3: টাকা, পূর্ণ পয়সা থেকে ছাপা

কোথাও কোনো দশমিক type নেই। দশমিক বিন্দুটা শেষ মুহূর্তে বসায় printf।

#include <stdio.h>

int main(void)
{
    long long total_paisa = 120050;

    long long taka = total_paisa / 100;
    long long paisa = total_paisa - taka * 100;

    printf("%lld.%02lld\n", taka, paisa);
    return 0;
}
1200.50

02-টা বাদ দাও, আর 1200 টাকা 5 পয়সার একটা জের 1200.5 হয়ে ছাপবে, যেটা judge-এ ভুল উত্তর আর দোকানে একজন রাগী ক্রেতা।

Run in Compiler

এটা কোথায় কাজে লাগছে

  • প্রতিটা programming contest। ICPC, Codeforces আর Progsity-র contest platform সবাই এভাবেই judge করে, আর "test 7-এ ভুল উত্তর" প্রায় সবসময়ই মানে বড্ড সরু একটা type।
  • আর্থিক হিসাব মেলানো। একটা ব্যাংকের দিনশেষের কাজ লক্ষ লক্ষ পরিমাণ সবচেয়ে ছোট এককে যোগ করে আর এক integer-র সঙ্গে আরেক integer মেলায়। ওই শিকলের কোথাও একটা দশমিক type থাকলেই তুলনাটা শেষ।
  • স্বয়ংক্রিয় মূল্যায়ন। এই track-র পরের প্রতিটা module-র judge করা অনুশীলন আর Skill Test-র build অংশ, সবাই এই দশটা সমস্যার judge-ই ব্যবহার করে।
  • Golden-file test। Compiler আর command line tool পরীক্ষা করা হয় চালিয়ে, আর output-টা রাখা একটা file-র সঙ্গে অক্ষর ধরে ধরে মিলিয়ে। GCC-র নিজের test suite ঠিক এভাবেই চলে।

যে ভুলগুলো সবাই করে

১. ক্ষতি হয়ে যাওয়ার পরে চওড়া করা।

long long sum = (long long)(a + b);

দুইটা command line-র কোনোটাতেই message নেই, আর কেবল সবচেয়ে বড় test-গুলোতেই ব্যর্থ হয়। Bracket-র ভেতরের a + b এখনো int-র অঙ্ক, তাই ওটা overflow করে আর ভাঙা জিনিসটাকে পরে চওড়া করা হয়। Cast-টা একটা operand-র উপর বসাও।

২. double-কে %f দিয়ে পড়া।

double r = 0.0;
scanf("%f", &r);

Playground-এ নীরব, আর আমাদের দৌড়ে প্রতিটা input-র জন্য 0.000000 ছেপেছে। scanf-কে বলা হয়েছিল 8 byte-র বাক্সে 4 byte লিখতে। scanf-এ এটা %lf, সবসময়।

৩. টাকা double হিসেবে ছাপা।

double balance = 120050 / 100.0;
printf("%.2f\n", balance);

কোনো message নেই, আর এখানে ওটা 1200.50-ই ছাপে। তবু অভ্যাসটা ভুল: lesson 3-র till ছেপেছিল 2.67 যেখানে দোকান আশা করেছিল 2.68, আর সেজন্যই paisa-ledger double নিষিদ্ধ করে।

৪. দুইটা দশমিক মান == দিয়ে মেলানো।

printf("%d\n", a + b == c);

কোনো message নেই, আর সহজ test-গুলো পাশ করে। ব্যর্থ হয় 0.1 0.2 0.3-এ, যেটা close-enough-র একটা লুকানো test আর statement-এ ওটার নাম বলাই আছে, যাতে কেউ ফাঁদে না পড়ে।

মাথা খাটাও

bytes-for-doubles-এ Bob-র উত্তর ছয়টা test পাশ করে আর সবচেয়ে বড়টায় ব্যর্থ হয়, যেখানে ও ছাপে -589934592।

#include <stdio.h>

int main(void)
{
    int n = 0;
    scanf("%d", &n);

    int total = n * sizeof(double);

    printf("%d\n", total);
    return 0;
}

এটা নিয়ে কোনো command line কিছুই বলে না, নিজের মেশিনের gcc -Wall -Wextra-ও না। ঠিক কোন ধাপে উত্তরটা হারাল, আর হারানোর মুহূর্তে সঠিক মানটা কত ছিল, বলো।

তারপর কঠিন অংশ। কেবল total-র type long long আর specifier %lld করে দিলেই program ঠিক হয়ে যায়, যদিও n এখনো একটা int। গুণটা কেন আগে থেকেই একটা চওড়া type-এ হচ্ছিল, বলো।

Assignment হওয়ার আগেই n * sizeof(double)-র type বের করো, sizeof কী ফেরত দেয় তার lesson 5-র উত্তরটা ধরে। তারপর জিজ্ঞেস করো, ওই type-র একটা মান 4 byte-র বাক্সে রাখলে কী হয়।

Problem 1: echo-numberসহজ

Kenji একটা নতুন tool-র input box পরীক্ষা করছে। ও চায় সবচেয়ে ছোট program-টা, যেটা দেখাবে সংখ্যাটা ভিতরে গিয়ে আবার বেরিয়ে এসেছে।

Input. এক লাইনে একটা পূর্ণসংখ্যা n।

Output. এক লাইনে: সংখ্যাটা, একটা space, তারপর stored শব্দটা।

Constraints. -1000000 <= n <= 1000000।

Sample. Input 42 দিলে 42 stored।

#include <stdio.h>

int main(void)
{
    int n = 0;
    scanf("%d", &n);

    /* One printf. Nothing else. */

    return 0;
}
Run in Compiler

Hint 1

তোমার প্রথম লাইন চলার সময় মানটা আগে থেকেই n-এ আছে। হিসাব করার কিছু নেই।

Hint 2

একটা printf, যার format string-এ আছে %d, একটা space, stored শব্দটা আর একটা newline।

Solution

n-কে %d দিয়ে ছাপো, তারপর একটা space, তারপর শব্দটা, তারপর \n। এখানে int-ই ঠিক type, কারণ constraints দশ লাখে থেমে যায়, ওর সীমার অনেক ভিতরে।

সীমার ঋণাত্মক প্রান্তটা সত্যিকারের একটা লুকানো test। %d minus চিহ্নটা নিজেই ছাপে, তাই বাড়তি কিছু লাগে না, তবু একবার চালিয়ে নিজের চোখে দেখে নাও।

Problem 2: swap-with-thirdমাঝারি

Bob দুই বাক্স বই গোছাচ্ছে আর label দুটো উল্টো বাক্সে লেগে আছে। একটা তৃতীয় variable-এ প্রথম মানটা রেখে দুটো বদলে ফেলো।

Input. এক লাইনে দুইটা পূর্ণসংখ্যা a b।

Output. এক লাইনে সংখ্যা দুটো উল্টো ক্রমে, মাঝে ঠিক একটা space।

Constraints. -1000000 <= a, b <= 1000000।

Sample. Input 10 20 দিলে 20 10।

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 0;
    int spare = 0;
    scanf("%d %d", &a, &b);

    /* Three assignments, then one printf. */

    return 0;
}
Run in Compiler

Hint 1

Assignment একটা মান বাক্সে copy করে আর আগে যা ছিল তা শেষ করে দেয়। a-র উপরে একবার লেখা হয়ে গেলে পুরনো a আর নেই।

Hint 2

আগে পুরনো a-কে spare-এ রেখে দাও। তারপর a নিতে পারে b, আর b নিতে পারে তুমি যেটা রেখেছিলে।

Solution

এই ক্রমে তিনটা assignment: spare পায় a, তারপর a পায় b, তারপর b পায় spare। দুইটা মান এক printf-এ ছাপো, specifier দুটোর মাঝে একটাই space দিয়ে।

এক লাইনে b তারপর a ছাপলেও প্রতিটা test পাশ করে, আর কিছুই শেখায় না। আগে তিনটা assignment করো, তারপর ছোট পথটা চেষ্টা করো, আর খেয়াল করো একটা memory নিয়ে শেখা আর অন্যটা টাইপ করা নিয়ে শেখা।

Problem 3: safe-sumসহজ

Amara একটা sensor-র দুইটা reading যোগ করছে। প্রতিটা reading একটা int-এ ধরে, আর ওদের যোগফল ধরে না।

Input. এক লাইনে দুইটা পূর্ণসংখ্যা a b।

Output. এক লাইনে ওদের যোগফল।

Constraints. 0 <= a, b <= 2000000000।

Sample. Input 2000000000 2000000000 দিলে 4000000000।

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 0;
    scanf("%d %d", &a, &b);

    /* The inputs fit in an int. The answer does not. */

    return 0;
}
Run in Compiler

Hint 1

দুইশো কোটি একটা int-এ ধরে। চারশো কোটি ধরে না, আর সবচেয়ে বড় test ঠিক ওটাই চায়।

Hint 2

যোগফলের একটা long long লাগে, আর যোগটা নিজেরও লাগে। +-র আগেই এক পাশকে (long long) দিয়ে চওড়া করো।

Solution

উত্তরের জন্য একটা long long declare করো আর লেখো (long long)a + b। এক operand চওড়া হলেই পুরো যোগটা চওড়ায় হয়, আর দ্বিতীয় মানটা নিজে থেকেই মিলিয়ে চওড়া হয়ে যায়।

ছাপো %lld দিয়ে। ওখানে %d দিলে Playground নীরবে compile করে আর এমন একটা সংখ্যা ছাপে যার যোগফলের সঙ্গে কোনো সম্পর্ক নেই, মানে lesson 2-র দ্বিতীয় ভুলটা যা বলেছে সেটাই।

Problem 4: circle-areaসহজ

Zara গোল টেবিল-mat কাটছে আর প্রতিটার ক্ষেত্রফল দরকার, দুই দশমিক ঘর পর্যন্ত।

Input. এক লাইনে একটা দশমিক সংখ্যা r, সেন্টিমিটারে ব্যাসার্ধ।

Output. এক লাইনে ক্ষেত্রফল, ঠিক দুই দশমিক ঘর পর্যন্ত।

Constraints. 0.01 <= r <= 1000.00। পাই-র জন্য 3.14159265358979 ব্যবহার করো।

Sample. Input 2.5 দিলে 19.63।

#include <stdio.h>

int main(void)
{
    double r = 0.0;
    scanf("%lf", &r);

    /* One printf, with %.2f. */

    return 0;
}
Run in Compiler

Hint 1

ক্ষেত্রফল মানে পাই গুণ ব্যাসার্ধ গুণ ব্যাসার্ধ। Statement-র পাই-টা লেখো, পুরো পনেরো অঙ্কই।

Hint 2

এখানে সবই double, তাই কিছুই পূর্ণসংখ্যার কাজ হিসেবে হয় না। একমাত্র ফাঁদ দুই দিকের format specifier।

Solution

পাই-র ধ্রুবকটাকে r দিয়ে দুইবার গুণ করো আর ফলটা %.2f দিয়ে ছাপো। সবচেয়ে ছোট অনুমোদিত ব্যাসার্ধে ক্ষেত্রফল প্রায় 0.0003, যেটা 0.00 হয়ে ছাপে, আর সেটা bug না, সঠিক উত্তর।

scanf-র লাইনটা যেমন দেওয়া আছে তেমনই রাখো। ওখানে একটা %f আট byte-র বাক্সে চার byte লেখে, তাই r শূন্যেই থেকে যায়, একসঙ্গে প্রতিটা test ব্যর্থ হয়, আর compiler এটা নিয়ে একটা কথাও বলে না।

Problem 5: seconds-to-daysমাঝারি

একটা server অনেক বিপুল সংখ্যক second ধরে চলছে। Zara চায় সেটা দিন, ঘণ্টা, মিনিট আর second হিসেবে লেখা হোক।

Input. এক লাইনে একটা পূর্ণসংখ্যা s, second-র সংখ্যা।

Output. এক লাইনে: d days, h hours, m minutes, s seconds, চারটা সংখ্যা বসানো অবস্থায়।

Constraints. 0 <= s <= 1000000000000। শব্দগুলো 1-র জন্য বদলাতে হবে না; যেমন দেখানো হয়েছে ঠিক তেমনই ছাপো।

Sample. Input 90061 দিলে 1 days, 1 hours, 1 minutes, 1 seconds।

#include <stdio.h>

int main(void)
{
    long long s = 0;
    scanf("%lld", &s);

    /* 86400 seconds in a day, 3600 in an hour, 60 in a minute. */

    return 0;
}
Run in Compiler

Hint 1

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

Hint 2

days = s / 86400-র পরে বাকিটা s - days * 86400। একই কাজ আরও দুইবার করো, 3600 আর তারপর 60 দিয়ে।

Solution

চারটা মান, সবচেয়ে বড় একক থেকে নিচের দিকে ক্রমে নেওয়া। দিনের জন্য 86400 দিয়ে ভাগ করো, ওই কয় দিনের second বিয়োগ করো, বাকিটা 3600 দিয়ে ভাগ করে ঘণ্টা নাও, আবার বিয়োগ করো, 60 দিয়ে ভাগ করে মিনিট নাও, আর যা পড়ে থাকে সেটাই second।

প্রতিটা variable একটা long long, কারণ কেবল input-ই এক লক্ষ কোটি ছাড়ায়। চারটা মান এক printf-এ চারটা %lld দিয়ে ছাপো, আর কমা আর শব্দগুলো মুখস্থ থেকে না লিখে statement থেকে copy করো।

Problem 6: lamp-toggleকঠিন

Kenji-র টেবিল-বাতিটা শুরুতে বন্ধ। কেউ switch-টা n বার টিপল। শেষে বাতিটা জ্বলছে কি না বলো।

Input. এক লাইনে একটা পূর্ণসংখ্যা n, কতবার টেপা হলো।

Output. এক লাইনে: বাতি জ্বললে 1, নাহলে 0।

Constraints. 0 <= n <= 1000000000। Loop লাগবে না, আর চাইও না।

Sample. Input 7 দিলে 1। Input 0 দিলে 0।

#include <stdio.h>

int main(void)
{
    int n = 0;
    scanf("%d", &n);

    /* No loop. What is left over when n is divided by 2? */

    return 0;
}
Run in Compiler

Hint 1

দুইবার টিপলে বাতি আগের অবস্থায় ফিরে যায়। তাই n জোড় না বিজোড়, কেবল সেটাই গুরুত্বপূর্ণ হতে পারে।

Hint 2

n-কে 2 দিয়ে ভাগ করলে ভাগশেষ কত, সেটা দরকার, আর % হলো Module 4। Lesson 2-র অনুশীলন ৪ /, * আর - দিয়ে একটা ভাগশেষ বানিয়েছে।

Solution

পূর্ণসংখ্যার ভাগ ভগ্নাংশ ফেলে দেয়, তাই n / 2 পুরো জোড়া টেপাগুলো গোনে। ওটাকে আবার 2 দিয়ে গুণ করে n থেকে বিয়োগ করো, আর যা পড়ে থাকে সেটা বিজোড়বার টেপায় 1 আর জোড়বার টেপায় 0। ওটাই উত্তর, তাই %d দিয়ে ছেপে দাও।

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

Problem 7: bytes-for-doublesমাঝারি

Amara হিসাব করছে reading-র একটা table-র জন্য কত memory লাগবে, চাওয়ার আগেই।

Input. এক লাইনে একটা পূর্ণসংখ্যা n, reading-র সংখ্যা।

Output. এক লাইনে কত byte লাগবে, যদি double ধরনের n-টা মান রাখতে হয়।

Constraints. 0 <= n <= 1000000000। মাপটা sizeof থেকে নাও, নিজের লেখা কোনো সংখ্যা থেকে না।

Sample. Input 10 দিলে 80।

#include <stdio.h>

int main(void)
{
    long long n = 0;
    scanf("%lld", &n);

    /* Multiply by sizeof(double), print with %lld. */

    return 0;
}
Run in Compiler

Hint 1

সবচেয়ে বড় input-র উত্তর আটশো কোটি, তাই গুণটা এমন একটা বাক্সে হতে হবে যেটা আটশো কোটি ধরে।

Hint 2

sizeof একটা size_t ফেরত দেয়, যেটা unsigned। ওটাকে long long-এ cast করো, যাতে গুণের দুই পাশই তোমার বাছা type হয়।

Solution

Starter যেভাবে করছে সেভাবেই n-কে একটা long long হিসেবে পড়ো, আর সেটাকে (long long)sizeof(double) দিয়ে গুণ করো। গুণফলটা %lld দিয়ে ছাপো। উপরের মাথা খাটানোর program-টা এই program-রই প্রায়-ঠিক রূপ।

8-টা নিজে লিখে দিলে প্রতিটা test পাশ করে আর তবু অনুশীলনের ভুল উত্তরই থাকে। এই module-র কথাই হলো মাপটা মেশিনের কাছে করা একটা প্রশ্ন, আর যে program জিজ্ঞেস করে সে মেশিন বদলালেও চলতে থাকে।

Problem 8: paisa-ledgerমাঝারি

Maria-র দোকানের খাতা পয়সায় রাখা হয়, টাকায় নয়, কারণ পূর্ণসংখ্যা কখনো সরে যায় না। একদিনের সারিতে থাকে শুরুর জের, একটা জমা আর একটা তোলা।

Input. এক লাইনে তিনটা পূর্ণসংখ্যা: শুরুর জের, জমা আর তোলা, সবই পয়সায়।

Output. এক লাইনে শেষের জের টাকায় লেখা: পূর্ণ টাকা, একটা দাঁড়ি-চিহ্ন, তারপর ঠিক দুই অঙ্কের পয়সা।

Constraints. 0 <= শুরুর জের, জমা <= 1000000000000000, আর তোলা কখনো জেরকে শূন্যের নিচে নামায় না। কোথাও double না।

Sample. Input 100000 25050 5000 দিলে 1200.50।

#include <stdio.h>

int main(void)
{
    long long opening = 0;
    long long deposit = 0;
    long long withdrawal = 0;
    scanf("%lld %lld %lld", &opening, &deposit, &withdrawal);

    /* Do every sum in paisa. Put the decimal point back only when you print. */

    return 0;
}
Run in Compiler

Hint 1

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

Hint 2

পূর্ণ টাকা মানে জেরকে 100 দিয়ে ভাগ। পয়সাটা হলো ভাগ যা ফেলে দিয়েছে, আর ওটা 5 হলেও দুই অঙ্কে ছাপতে হবে।

Solution

জমা যোগ করো আর তোলা বিয়োগ করো, সবই long long পয়সায়। তারপর ভাগ করো: টাকা হলো জের ভাগ 100, আর পয়সা হলো জের বিয়োগ একশো গুণ টাকা। জোড়াটা %lld.%02lld দিয়ে ছাপো, যেখানে 02 সামনে একটা শূন্য দিয়ে দুই অঙ্কে ভরে দেয়।

Statement-এ double নিষিদ্ধ, আর কারণটা তুমি যাচাই করতে পারো। দুইটা লুকানো test-র জের প্রায় এক কোয়াড্রিলিয়ন পয়সা, যেটা একটা double-র ঠিক রাখা পনেরো অঙ্কের অনেক বাইরে, তাই দশমিক রূপটা শেষ পয়সাটা হারিয়ে ব্যর্থ হতো।

Problem 9: close-enoughকঠিন

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

Input. এক লাইনে তিনটা দশমিক সংখ্যা a b c।

Output. এক লাইনে: a + b যদি c-র 0.000000001-র মধ্যে থাকে তবে 1, নাহলে 0।

Constraints. -1000000 <= a, b, c <= 1000000। একটা লুকানো test হলো 0.1 0.2 0.3, আর সেখানে উত্তরটা 1।

Sample. Input 0.1 0.2 0.3 দিলে 1। Input 1.0 1.0 3.0 দিলে 0।

#include <stdio.h>
#include <math.h>

int main(void)
{
    double a = 0.0;
    double b = 0.0;
    double c = 0.0;
    scanf("%lf %lf %lf", &a, &b, &c);

    /* One printf with %d. A comparison is already a 1 or a 0. */

    return 0;
}
Run in Compiler

Hint 1

পার্থক্যটা ধনাত্মক বা ঋণাত্মক হতে পারে, আর তোমার দরকার কেবল ওর মাপ। <math.h>-র fabs চিহ্নটা বাদ দেয়।

Hint 2

একটা তুলনা এমন expression যার মান 1 বা 0, তাই পুরো উত্তরটা এক printf-এ %d দিয়েই এঁটে যায়। কোনো if লাগে না।

Solution

a + b - c বের করো, fabs দিয়ে তার মাপ নাও, আর সেটাকে 0.000000001-র সঙ্গে মেলাও, যেটা লেখা হয় 1e-9। তুলনাটাই উত্তর, তাই ওটা সরাসরি printf-কে %d দিয়ে দিয়ে দাও।

fabs ছাড়া দুইটা তুলনা লাগত, দুই দিকে একটা করে, গুণ করে, যেমনটা lesson 4 দেখিয়েছে। দুইটাই পাশ করে। Playground-এ math library আগে থেকেই জোড়া লাগানো, তাই fabs-র জন্য include ছাড়া আর কিছু লাগে না।

Problem 10: type-fitsকঠিন

Zara একটা file format-র কলাম নকশা করছে। কলামটা যত মান ধরতে পারে, তার সবটা ধরে এমন সবচেয়ে সরু signed fixed-width type ওর দরকার।

Input. এক লাইনে দুইটা পূর্ণসংখ্যা lo hi, কলামের সবচেয়ে ছোট আর সবচেয়ে বড় মান।

Output. এক লাইনে bit-এ একটা প্রস্থ: 8, 16, 32 বা 64।

Constraints. -9000000000000000000 <= lo <= hi <= 9000000000000000000। কোনো শর্ত লাগবে না, loop-ও না।

Sample. Input -200 300 দিলে 16। Input 0 5000000000 দিলে 64।

#include <stdio.h>

int main(void)
{
    long long lo = 0;
    long long hi = 0;
    scanf("%lld %lld", &lo, &hi);

    /* Lesson 4: a comparison is a 1 or a 0, and two of them multiplied is "both". */

    return 0;
}
Run in Compiler

Hint 1

int8_t ধরে -128 থেকে 127, int16_t ধরে -32768 থেকে 32767, int32_t ধরে প্রায় দুইশো কোটির এদিক-ওদিক। আগে ওই ছয়টা সংখ্যা লিখে ফেলো।

Hint 2

প্রতিটা type-র জন্য "সীমাটা ধরে" মানে দুইটা তুলনা গুণ করা। তিনটা সীমা একটার ভেতরে আরেকটা, তাই তিনটা উত্তর কেবল 1 1 1, 0 1 1, 0 0 1 বা 0 0 0 হতে পারে।

Solution

তিনটা flag বানাও। প্রতিটা হলো (lo >= ওই type-র সবচেয়ে নিচু) * (hi <= ওই type-র সবচেয়ে উঁচু), তাই প্রতিটা 1 বা 0। সীমাগুলো একটার ভেতরে আরেকটা বলে flag-গুলো কেবল ক্রমেই জ্বলতে পারে, আর কয়টা জ্বলল সেটাই বলে দেয় সিঁড়ির কত নিচে নামা যাবে।

গোনাটাকে শর্ত ছাড়াই প্রস্থে বদলাও: 8 byte থেকে শুরু করো আর প্রতিটা 1-র জন্য একবার অর্ধেক করো, মানে তিনবার 1 + flag দিয়ে ভাগ করো। Byte-কে 8 দিয়ে গুণ করে %lld দিয়ে ছাপো। Type-র সীমাগুলো LL suffix দিয়ে লেখো, যাতে তুলনাগুলো একটা int-এ না হয়ে চওড়া type-এ হয়।

যে প্রশ্নগুলো সবার মনে আসে

  • এখানকার প্রতিটা সমস্যায় long long দিয়ে চিন্তা বন্ধ করে দিতে পারি?

    Integer সমস্যাগুলোর জন্য পারো, আর পাশও করবে। এই module-র কথা হলো, তিনটায় ওটা কেন লাগল আর বাকিগুলোয় কেন লাগল না, সেটা তুমি বলতে পারবে।

  • শেষে newline না দিলেও judge মেনে নেয় কেন?

    কারণ তুলনাটা একদম শেষের newline আর লাইনের শেষের space বাদ দেয়। তবু newline-টা দিয়ো; অন্য জায়গার বেশির ভাগ judge ওটা আশা করে।

  • আমার দশমিক উত্তর শেষ ঘরে sample-র থেকে আলাদা। এটা কি ভুল উত্তর?

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

  • Lesson-গুলো না শেখালেও কি % বা if ব্যবহার করতে পারি?

    কেউ আটকাবে না, আর তোমার উত্তর পাশও করবে। তুমি কেবল অনুশীলনটা বাদ দিয়ে যাবে, যেটা ছিল হাতে যা আছে তাই দিয়ে সমাধান করা।

  • কোন লুকানো test ব্যর্থ হলো বুঝব কীভাবে?

    ফলাফল test-র নম্বর বলে দেয়। ওটা constraints-র সঙ্গে মেলাও: শেষের test-গুলো সাধারণত দুই প্রান্তের, আর প্রান্তের test ব্যর্থ মানে প্রায় সবসময়ই বড্ড সরু একটা type।

মূল কথা

  • আগে Constraints পড়ো আর type-টা ওখানেই বাছো, প্রথম লাইন লেখার আগে।
  • তোমার program যা ধরে রাখে সেটাই গুরুত্বপূর্ণ, যা পড়ে সেটা না।
  • অঙ্কের আগে চওড়া করো, পরে কখনো না, নাহলে উত্তরটা আগেই নষ্ট।
  • %lf একটা double পড়ে আর %f একটাকে নষ্ট করে, নীরবে, Playground-এ।
  • টাকা মানে long long-এ পূর্ণ পয়সা, ছাপা হয় %lld.%02lld দিয়ে।
  • একটা তুলনার মান 1 বা 0, তাই এই তিনটা সমস্যায় কোনো if লাগেই না।

পরেরটা module test: পাঁচটা lesson-র উপরে দশটা প্রশ্ন, আর সঙ্গে এই সমস্যাগুলোর দুইটা আবার।

Module test

এই module এর উপর দশটা প্রশ্ন। 70% পেলে pass, আর যতবার খুশি দেওয়া যায়।

Module test দিন

lesson ৬ শেষ

সব problem accepted হলেই lesson শেষ।

১০ টা problem-এর মধ্যে ০ টা accepted

পরেরটা: Module test: variable আর data type