কম্পিউটার প্রোগ্রামিং ফুল ডিটেল .. বাই : এম.এইচ.বিশাল
মোট লেকচার : ১৬ টি
( প্রতি ক্লাসে ২টি করে লেকচার শেখানো হবে )
পর্ব -০৩,, আজকের লেকচার:
অধ্যায় পাঁচ] একটুখানি গণিত।
অধ্যায় চার] লুপ (Loop)।
এবারে বিস্তারিত
অধ্যায় চার] লুপ (Loop)।
তোমরা এরই মধ্যে প্রোগ্রামের মধ্যে বিভিন্ন ধরনের শর্ত (condition) ব্যবহার করতে শিখে গেছ। এইসব শর্ত দিয়ে বিভিন্ন প্রোগ্রাম তৈরি করাও হয়তো শুরু করে দিয়েছ। খুব ভালো কথা। কিন্তু এখন আমরা আরেকটি সমস্যা ও তার সমাধানের পথ খুঁজব। একটি প্রোগ্রাম লিখতে হবে, যেটি 1 থেকে 10 পর্যন্ত সব পূর্ণসংখ্যা মনিটরে দেখাবে (প্রতি লাইনে একটি সংখ্যা থাকবে)। খুবই সহজ সমস্যা এবং সমাধানও অত্যন্ত সহজ। আমি জানি, তোমরা এক মিনিটের মধ্যেই নিচের প্রোগ্রামটি লিখে ফেলবে:
#include <stdio.h>
int main()
{
printf(“1\n”);
printf(“2\n”);
printf(“3\n”);
printf(“4\n”);
printf(“5\n”);
printf(“6\n”);
printf(“7\n”);
printf(“8\n”);
printf(“9\n”);
printf(“10\n”);
return 0;
}
প্রোগ্রাম: ৪.১
এখানে আমরা 1 থেকে 10 পর্যন্ত সবগুলো সংখ্যা প্রিন্ট করে দিয়েছি। অবশ্য একটি printf() ব্যবহার করেও কাজটি করা যেত: printf(“1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n”);
আবার প্রোগ্রামটি এভাবেও লেখা যেত। n একটি ইন্টিজার ভেরিয়েবল, যার মান আমরা প্রথমে 1 বসাব। তারপর n-এর মান প্রিন্ট করব। তারপর n-এর মান এক বাড়াব (n = n + 1 অথবা সংক্ষেপে, n++ লিখে)।
int n = 1;
printf(“%d\n”, n);
n = n + 1;
printf(“%d\n”, n);
n = n + 1;
printf(“%d\n”, n);
n = n + 1;
/* এভাবে মোট দশ বার */
আবার nএর মান 1 বাড়ানোর কাজটি কিন্তু এক লাইনেই সেরে ফেলা যায়।
printf(“%d\n”, n);
n = n + 1;
এর পরিবর্তে আমরা লিখতে পারি:
printf(“%d\n”, n++);
যা-ই হোক, এ তো গেল 1 থেকে 10 পর্যন্ত প্রিন্ট করা। কিন্তু আমাদের যদি 1 থেকে 100, বা 1000, বা 10000 পর্যন্ত প্রিন্ট করতে বলা হতো তাহলে আমরা কী করতাম? ওপরে যে পদ্ধতি অবলম্বন করা হয়েছে সেটি তো অবশ্যই করা যেত। কিন্তু আমি জানি, তোমরা কেউই এত কষ্ট করতে রাজি না।
এ সমস্যা সমাধানের জন্য সব প্রোগ্রামিং ল্যাঙ্গুয়েজেই লুপ (loop) বলে একটি পদ্ধতি রয়েছে। এটি দিয়ে একই কাজ বারবার করা যায়। লুপের মধ্যে একটি শর্ত বসিয়ে দিতে হয়, যেটি পূরণ না হওয়া পর্যন্ত প্রোগ্রামটি লুপের ভেতরের কাজ বারবার করতে থাকবে। সি ল্যাঙ্গুয়েজে দুটি জনপ্রিয় লুপ হচ্ছে while এবং for। আমরা এখন while ব্যবহার করে ওই প্রোগ্রামটি লিখব।
#include <stdio.h>
int main()
{
int n = 1;
while(n <= 10) {
printf(“%d\n”, n);
n++;
}
return 0;
}
প্রোগ্রাম: ৪.২
কী চমৎকার! এখন আমরা চাইলে 10-এর বদলে যত খুশি বসাতে পারি, যত বসাব 1 থেকে তত পর্যন্ত প্রিন্ট হবে। while লুপে প্রথম বন্ধনীর ভেতর শর্ত লিখে দিতে হয়। প্রোগ্রাম সেই শর্ত পরীক্ষা করে। যতক্ষণ পর্যন্ত শর্তটি সত্য হয় ততক্ষণ পর্যন্ত লুপের ভেতরের কাজগুলো চলতে থাকে। লুপের ভেতরের কাজগুলো থাকবে দ্বিতীয় বন্ধনীর ভেতর। যেমন এখানে লুপের ভেতরে আমরা দুটি কাজ করেছি। n-এর মান প্রিন্ট করেছি আর তারপর n-এর মান 1 বাড়িয়েছি। n-এর মান 1 করে বাড়তে থাকলে একসময় এটি 11 হবে আর তখন n <= 10 এই শর্তটি মিথ্যা হয়ে যাবে (কারণ 11 > 10)। আর প্রোগ্রামটিও লুপ থেকে বের হয়ে আসবে। অর্থাৎ, শর্তটি যখনই মিথ্যা হবে তখনই লুপ থেকে বের হয়ে যাবে।
ইন্ডেন্টেশনের ব্যাপারটিও খেয়াল করো। লুপের ভেতরের অংশের কোড চার ঘর ডানদিক থেকে শুরু হয়েছে।
এবারে তোমাদের জন্য একটি প্রশ্ন। বলো তো নিচের প্রোগ্রামটির আউটপুট কী হবে?
#include <stdio.h>
int main()
{
int n = 1;
while(n <= 10) {
printf(“%d\n”, n);
}
n++;
return 0;
}
প্রোগ্রাম: ৪.৩
এটাও কি 1 থেকে 10 পর্যন্ত সব সংখ্যা প্রিন্ট করবে? দেখা যাক। প্রোগ্রামটি রান করাও। আউটপুট কী?
মনিটরে প্রতি লাইনে 1 প্রিন্ট হচ্ছে এবং প্রোগ্রামটি বন্ধ হচ্ছে না। খুবই দুঃখের বিষয়। দেখা যাক দুঃখের পেছনে কারণটা কী।
int n = 1; প্রথমে প্রোগ্রামটি n-এর মান 1 বসাবে।
তারপর while লুপে গিয়ে শর্ত পরীক্ষা করবে। আমরা শর্ত দিয়েছি n <= 10 মানে n-এর মান 10-এর ছোট বা সমান। এই শর্ত তো সত্য কারণ n-এর মান 1। তারপর প্রোগ্রামটি n-এর মান প্রিন্ট করবে printf(“%d\n”, n);। তারপর কি n-এর মান 1 বাড়বে? বাড়বে না, কারণ আমরা দ্বিতীয় বন্ধনী শেষ করে দিয়েছি ‘}’ চিহ্ন দিয়ে (মানে লুপ শেষ)। তার মানে প্রোগ্রামটি আবার শর্ত পরীক্ষা করবে, আবার n-এর মান প্রিন্ট করবে…এভাবে চলতেই থাকবে কারণ n-এর মান যেহেতু বাড়ছে না, n <= 10 শর্তটি সব সময় সত্যই রয়ে যাচ্ছে – কখনো মিথ্যা হচ্ছে না। এখন তোমরা while লুপ নিয়ে বিভিন্ন ধরনের গবেষণা চালিয়ে যেতে পারো। সব সময় সত্য হয় এমন শর্ত ব্যবহার করে তোমার কম্পিউটারকে ব্যস্ত রাখতে পারো। while(1){…} এখানে শর্ত হিসেবে 1 ব্যবহার করা হয়েছে। কম্পিউটার 1 বলতে বোঝে সত্য। সুতরাং লুপের ভেতরের কাজগুলো সব সময় চলতে থাকবে, বন্ধ হবে না। while(1 == 1){…} ও একই আচরণ করবে। তবে এখন আমি তোমাদের একটি দরকারি জিনিস বলে রাখি, যেটি দিয়ে তোমরা জোর করে লুপ থেকে বের হয়ে যেতে পারবে। সেটি হচ্ছে break স্টেটমেন্ট। কথা না বাড়িয়ে একটি প্রোগ্রাম লিখলেই ব্যাপারটি পরিষ্কার হয়ে যাবে।
#include <stdio.h>
int main()
{
int n = 1;
while(n <= 100) {
printf(“%d\n”, n);
n++;
if(n > 10) {
break;
}
}
return 0;
}
প্রোগ্রাম: ৪.৪
এই প্রোগ্রামটি কী করবে? 1 থেকে 10 পর্যন্ত প্রিন্ট করবে। যদিও while-এর ভেতর আমরা বলেছি যে শর্ত হচ্ছে n <= 100, কিন্তু লুপের ভেতরে আবার বলে দিয়েছি যে যদি n > 10 হয়, তবে break; মানে বের হয়ে যাও, বা লুপটি ভেঙে দাও। break সব সময় যেই লুপের ভেতর থাকে সেটির বাইরে প্রোগ্রামটিকে নিয়ে আসে। সুতরাং n-এর মান 10 প্রিন্ট হওয়ার পরে এর মান এক বাড়বে (n++;) অর্থাৎ n-এর মান হবে 11। আর তখন n > 10 সত্য হবে, ফলে প্রোগ্রামটি if কন্ডিশনের ভেতরে ঢুকে যাবে। সেখানে গিয়ে সে দেখবে তাকে break করতে বলা হয়েছে তাই সে লুপের বাইরে চলে যাবে। break-এর উল্টা কাজ করে, এমন একটি স্টেটমেন্ট হচ্ছে continue;। কোনো জায়গায় continue ব্যবহার করলে লুপের ভেতরে continue-এর পরের অংশের কাজ আর হয় না। নিচের প্রোগ্রামটি কোড করে কম্পাইল ও রান করো:
#include <stdio.h>
int main()
{
int n = 0;
while (n < 10) {
n = n + 1;
if (n % 2 == 0) {
continue;
}
printf(“%d\n”, n);
}
return 0;
}
প্রোগ্রাম: ৪.৫
এই প্রোগ্রামটি 1 থেকে 10-এর মধ্যে কেবল বেজোড় সংখ্যাগুলো প্রিন্ট করবে। জোড় সংখ্যার বেলায় continue ব্যবহার করার কারণে প্রোগ্রামটি printf(“%d\n”, n); স্টেটমেন্ট এক্সিকিউট না করে লুপের পরবর্তী ধাপের কাজ শুরু করবে।
এবারে আমরা আরেকটি প্রোগ্রাম লিখব। ছোটবেলায় যে নামতাগুলো তোমরা শিখেছ সেগুলো এখন আমরা প্রোগ্রাম লিখে কম্পিউটারের মনিটরে দেখব। চলো 5-এর নামতা দিয়ে শুরু করা যাক। আমাদের প্রোগ্রামের আউটপুট হবে এরকম:
5 X 1 = 5
5 X 2 = 10
5 X 3 = 15
5 X 4 = 20
5 X 5 = 25
5 X 6 = 30
5 X 7 = 35
5 X 8 = 40
5 X 9 = 45
5 X 10 = 50
তোমরা নিশ্চয়ই এখন অনেকগুলো printf ফাংশন লেখা শুরু করবে না। লুপের সাহায্যে প্রোগ্রামটি লিখে ফেলবে:
#include <stdio.h>
int main()
{
int n = 5;
int i = 1;
while (i <= 10) {
printf(“%d X %d = %d\n”, n, i, n*i);
i = i + 1;
}
return 0;
}
প্রোগ্রাম: ৪.৬
এতক্ষণ আমরা while লুপ ব্যবহার করলাম। এবার চলো for লুপ ব্যবহার করতে শিখি। 5-এর নামতার প্রোগ্রামটি যদি আমরা for লুপ ব্যবহার করে লিখি তাহলে সেটির চেহারা দাঁড়াবে:
#include <stdio.h>
int main()
{
int n = 5;
int i;
for(i = 1; i <= 10; i = i + 1) {
printf(“%d X %d = %d\n”, n, i, n*i);
}
return 0;
}
প্রোগ্রাম: ৪.৭
for লুপের প্রথম বন্ধনীর ভেতর তিনটি অংশ লক্ষ করো। প্রতিটি অংশ সেমিকোলন (;) দিয়ে আলাদা করা হয়েছে। প্রোগ্রামটি যখন লুপের ভেতর ঢুকে তখন প্রথম সেমিকোলনের আগে আমরা যে কাজগুলো করতে বলব, সেগুলো একবার করবে। যেমন এখানে i-এর মান 1 বসাবে। তারপর দ্বিতীয় অংশের কাজ করবে। দ্বিতীয় অংশে সাধারণত শর্ত ব্যবহার করা হয় (while লুপে প্রথম বন্ধনীর ভেতর আমরা যে কাজটি করি আরকি)। ওপরের প্রোগ্রামে আমরা দ্বিতীয় অংশে i <= 10 শর্তটি ব্যবহার করেছি। এই শর্ত যদি মিথ্যা হয় তবে প্রোগ্রামটি লুপ থেকে বেরিয়ে আসবে। আর যদি সত্য হয় তবে লুপের ভেতরের কাজগুলো করবে এবং তার পর for লুপের সেই প্রথম বন্ধনীর ভেতর তৃতীয় অংশে যে কাজগুলো করতে বলা হয়েছে সেগুলো করবে। তারপর আবার দ্বিতীয় অংশে এসে শর্ত পরীক্ষা করবে। প্রথম অংশের কাজ কিন্তু আর হবে না। তো আমাদের প্রোগ্রামটি আবার লক্ষ করো। i <= 10 সত্য, কারণ i-এর মান 1। তারপর printf() ফাংশনের কাজ হবে। তারপর i = i + 1 স্টেটমেন্ট এক্সিকিউট হবে (i-এর মান এক বেড়ে যাবে)। তারপর আবার i <= 10 সত্য না মিথ্যা সেটি পরীক্ষা করা হবে (i-এর মান এখন 2)। তারপর আবার লুপের ভেতরের কাজ হবে (printf())। এভাবে যতক্ষণ না i <= 10 শর্তটি মিথ্যা হচ্ছে ততক্ষণ লুপের ভেতরের কাজ চলতে থাকবে। i-এর মান এক এক করে বেড়ে বেড়ে যখন 11 হবে তখন শর্তটি মিথ্যা হবে আর প্রোগ্রামটি লুপ থেকে বের হয়ে আসবে। for লুপের প্রথম বন্ধনীর ভেতরের তিনটি অংশই যে ব্যবহার করতে হবে এমন কোন কথা নেই। কোন অংশ ব্যবহার করতে না চাইলে আমরা সেটি ফাঁকা রেখে দিতে পারি, তবে সেমিকোলন কিন্তু অবশ্যই দিতে হবে। যেমন আমরা যদি i-এর মান আগেই নির্ধারণ করে দেই তবে সেটি লুপের ভেতর না করলেও চলে।
int i = 1;
for(; i<= 10; i = i + 1) {
printf(“%d X %d = %d\n”, n, i, n*i);
}
যদি তিনটি অংশের কোনোটিই লিখতে না চাই, তবে পুরো প্রোগ্রামটি এভাবে লেখা যায়:
#include <stdio.h>
int main()
{
int n = 5;
int i = 1;
for( ; ; ) {
printf(“%d X %d = %d\n”, n, i, n*i);
i = i + 1;
if (i > 10) {
break;
}
}
return 0;
}
প্রোগ্রাম: ৪.৮
এখন আমরা আরেকটি কাজ করব। for লুপ ব্যবহার করে 5-এর নামতায় যে গুণ করেছি (n*i) সেটি না করে কেবল যোগ করে প্রোগ্রামটি লিখব। তোমরা কি অবাক হচ্ছ যে নামতার প্রোগ্রাম আবার গুণ ছাড়া কীভাবে হবে? আমরা কিন্তু 5 x 3-কে লিখতে পারি 5 + 5 + 5। আমি কী করতে যাচ্ছি তা বুঝতে পারছ নিশ্চয়ই। প্রোগ্রামটি লিখে ফেলি:
#include <stdio.h>
int main()
{
int m, n = 5;
int i;
m = 0;
for(i = 1; i <= 10; i = i + 1) {
m = m + n;
printf(“%d X %d = %d\n”, n, i, m);
}
return 0;
}
প্রোগ্রাম: ৪.৯
প্রোগ্রামটিতে আমরা গুণ না করে যোগ করলাম। কম্পাইল ও রান করে দেখো। কাজ করবে ঠিকঠাক। কোনো সংখ্যার গুণিতকগুলো যেমন গুণ করে বের করা যায়, তেমনই যোগ করেও করা যায়। আমরা যদি কোনো প্রোগ্রামে দেখি যে গুণ না করে যোগ করলেই কাজ হচ্ছে, তাহলে যোগ করাই ভালো কারণ কম্পিউটারের প্রসেসর একটি যোগ করতে যে সময় নেয়, একটি গুণ করতে তার চেয়ে অনেক বেশি সময় নেয়। যদিও তুমি হয়তো প্রোগ্রাম রান করার সময় তা বুঝতে পারো না। কম্পিউটারের প্রসেসর সম্পর্কে বিস্তারিত লেখাপড়া করলে বিষয়টা জানতে পারবে। আপাতত এটি জানলেই চলবে যে একটি গুণ করার চেয়ে একটি যোগ করা ভালো, কারণ যোগ করতে কম্পিউটার অপেক্ষাকৃত কম সময় নেয়।
তো আমরা for লুপ শিখে ফেললাম। এখন আমরা চেষ্টা করব শুধু নির্দিষ্ট একটি সংখ্যার নামতা না লিখে 1 থেকে 20 পর্যন্ত সবগুলো সংখ্যার নামতা একবারে লিখে ফেলতে। অর্থাৎ n-এর মান 5 নির্দিষ্ট না করে 1 থেকে 20 পর্যন্ত হবে। এটি করার একটি বোকা পদ্ধতি (নাকি চোরা পদ্ধতি?) হচ্ছে নামতা লিখার অংশটি বারবার কপি-পেস্ট করা। কিন্তু আমরা এটি করব লুপের ভেতর লুপ ব্যবহার করে। একটি লুপের সাহায্যে n-এর মান 1 থেকে 20 পর্যন্ত এক করে বাড়াব। আর তার ভেতর n-এর একটি নির্দিষ্ট মানের জন্য নামতাটা লিখব।
#include <stdio.h>
int main()
{
int n, i;
for(n = 1; n <= 20; n = n + 1) {
for(i = 1; i <= 10; i = i + 1) {
printf(“%d X %d = %d\n”, n, i, n*i);
}
}
return 0;
}
প্রোগ্রাম: ৪.১০
এখন তোমরা প্রোগ্রামটি চালাও। তারপর তোমাদের কাজ হবে গুণ না করে কেবল যোগ ব্যবহার করে প্রোগ্রামটি লেখা।
আমরা এখানে একটি for লুপের ভেতর আরেকটি for লুপ, যাকে নেস্টেড লুপও (nested loop) বলে, সেটি ব্যবহার করলাম। তো আমরা চাইলে for লুপের ভেতর for বা while অথবা while লুপের ভেতর for বা while লুপ একাধিকবার ব্যবহার করতে পারি। অবশ্য সেটি কখনোই চার বা পাঁচবারের বেশি দরকার হওয়ার কথা না। নেস্টেড লুপ দিয়ে আমরা এখন আরেকটি প্রোগ্রাম লিখব। 1, 2, 3 – এই তিনটি সংখ্যার সব বিন্যাস (permutation) বের করার প্রোগ্রাম। বিন্যাসগুলো ছোট থেকে বড় ক্রমে দেখাতে হবে অর্থাৎ প্রোগ্রামটির আউটপুট হবে এই রকম:
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
এই প্রোগ্রামটি অনেকভাবে লেখা যেতে পারে, কিন্তু আমরা এখন পর্যন্ত যতটুকু প্রোগ্রামিং শিখেছি, তাতে নেস্টেড লুপের ব্যবহারই সবচেয়ে ভালো সমাধান।
এখানে আমরা প্রথম সংখ্যাটির জন্য একটি লুপ, দ্বিতীয় সংখ্যাটির জন্য প্রথম লুপের ভেতরে একটি লুপ এবং তৃতীয় সংখ্যাটির জন্য দ্বিতীয় লুপের ভেতর আরেকটি লুপ ব্যবহার করব।
#include <stdio.h>
int main()
{
int a, b, c;
for (a = 1; a <= 3; a++) {
for (b = 1; b <= 3; b++) {
for (c = 1; c <= 3; c++) {
printf (“%d, %d, %d\n”, a, b, c);
}
}
}
return 0;
}
প্রোগ্রাম: ৪.১১
এখন প্রোগ্রামটি রান করলে আমরা এই রকম আউটপুট পাব:
1, 1, 1
1, 1, 2
1, 1, 3
1, 2, 1
1, 2, 2
1, 2, 3
1, 3, 1
1, 3, 2
1, 3, 3
2, 1, 1
2, 1, 2
2, 1, 3
2, 2, 1
2, 2, 2
2, 2, 3
2, 3, 1
2, 3, 2
2, 3, 3
3, 1, 1
3, 1, 2
3, 1, 3
3, 2, 1
3, 2, 2
3, 2, 3
3, 3, 1
3, 3, 2
3, 3, 3
কিন্তু আমরা তো আসলে এই রকম জিনিস চাচ্ছি না। a-এর মান যখন 1 তখন b ও c-এর মান 1 হবে না, আবার b এবং c-এর মানও সমান হবে না। মানে a, b ও c আলাদা হবে। তাহলে আমরা লুপের ভেতর শর্তগুলো একটু পরিবর্তন করব। দ্বিতীয় লুপের শর্ত b <= 3-এর সঙ্গে আরেকটি শর্ত জুড়ে দেব, b != a। b <= 3 && b != a মানে b-এর মান 3-এর চেয়ে ছোট বা সমান হবে এবং b-এর মান a-এর মানের সমান হবে না। তৃতীয় লুপে আমরা এখন শর্ত দেব, c <= 3 && c != a && c != b, মানে c-এর মান 3-এর ছোট বা সমান হতে হবে এবং c-এর মান a-এর মানের সমান হওয়া চলবে না এবং c-এর মান b-এর মানের সমান হলেও চলবে না। তাহলে আমাদের প্রোগ্রামটির চেহারা দাঁড়াবে এই রকম:
#include <stdio.h>
int main()
{
int a, b, c;
for (a = 1; a <= 3; a++) {
for (b = 1; b <= 3 && b != a; b++) {
for (c = 1; c <= 3 && c != a && c != b; c++) {
printf (“%d, %d, %d\n”, a, b, c);
}
}
}
return 0;
}
প্রোগ্রাম: ৪.১২
রান করলে আমরা আউটপুট কী দেখব?
3, 2, 1
মাত্র একটি লাইন! আমরা প্রোগ্রামটি ঠিক করতে গিয়ে ঝামেলা পাকিয়ে ফেলেছি মনে হচ্ছে। তোমরা কি একটু চিন্তা করে ঝামেলার কারণ বের করতে পারবে?
প্রথমে a-এর মান 1তাই a <= 3 সত্য। প্রোগ্রামটি প্রথম লুপের ভেতর ঢুকে গেল। তারপর দ্বিতীয় লুপের শুরুতে b-এর মান 1। b <= 3 সত্য। কিন্তু b != a মিথ্যা। কারণ aও b-এর মান তো সমান, দুটোর মানই 1। তাই প্রোগ্রামটি আর দ্বিতীয় লুপের ভেতর ঢুকবে না। এরপর a-এর মান 1 বাড়ল (a++)। a <= 3 সত্য (a-এর মান 2)। এখন দ্বিতীয় লুপ শুরু হবে। b-এর মান 1। এবারে b <= 3 এবং b != a দুটি শর্তই সত্য। প্রোগ্রামটি দ্বিতীয় লুপের ভেতর ঢুকে যাবে। তৃতীয় লুপের শুরুতে c-এর মান 1। c <=3 সত্য, c !=a সত্য কিন্তু c !=b মিথ্যা (দুটোর মানই 1)। তাই প্রোগ্রামটি তৃতীয় লুপ থেকে বের হয়ে যাবে– কেবল তিনটি শর্ত সত্য হলেই প্রোগ্রামটি তৃতীয় লুপের ভেতর ঢুকবে এবং a, b ও c-এর মান প্রিন্ট করবে। এভাবে কিছুক্ষণ গবেষণা করলে তোমরা দেখবে যে যখন a-এর মান 3, b-এর মান 2 এবং c-এর মান 1, তখনই কেবল সব শর্ত সত্য হয় আর আমরা আউটপুট পাই: 3, 2, 1। আসলে দ্বিতীয় লুপে আমরা b-এর মান a-এর মানের সমান হলে লুপ থেকে বের হয়ে যাচ্ছি। সেই কাজটি করা ঠিক হচ্ছে না। আমাদের উচিত দুটো মান সমান হলে পরবর্তী মানের জন্য চেষ্টা করা। আর মান দুটো সমান না হলেই কেবল পরবর্তী কাজ করা। তাহলে আমরা লিখতে পারি: for (b = 1; b <= 3; b++) { if (b != a) { /* b-এর মান a-এর মানের সমান না হলেই ভেতরের অংশে প্রোগ্রামটি ঢুকবে। */ for (c = 1; c <= 3; c++) { if (c != a && c != b) { /*c-এর মান a-এর মানের সমান না হলে এবং c-এর মান b-এর মানের সমান না হলেই কেবল ভেতরের অংশে প্রোগ্রামটি ঢুকবে। */ printf (“%d, %d, %d\n”, a, b, c); } } } } তাহলে আমাদের পুরো প্রোগ্রামটি দাঁড়াচ্ছে এই রকম:
#include <stdio.h>
int main()
{
int a, b, c;
for (a = 1; a <= 3; a++) {
for (b = 1; b <= 3; b++) {
if (b != a) {
for (c = 1; c <= 3; c++) {
if (c != b && c != a){
printf (“%d, %d, %d\n”, a, b, c);
}
}
}
}
}
return 0;
}
প্রোগ্রাম: ৪.১৩
প্রোগ্রামটি চালালে আমরা নিচের আউটপুট দেখব, যেটি আমরা চাচ্ছিলাম।
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
যাক, অবশেষে আমাদের সমস্যার সমাধান হলো। তবে আমরা কিন্তু আরও সহজেই সমাধান করতে পারতাম এভাবে–
#include <stdio.h>
int main()
{
int a, b, c;
for (a = 1; a <= 3; a++) {
for (b = 1; b <= 3; b++) {
for (c = 1; c <= 3; c++) {
if(b != a && c != a && c != b) {
printf (“%d, %d, %d\n”, a, b, c);
}
}
}
}
return 0;
}
প্রোগ্রাম: ৪.১৪
এখানে আমাদের বেশি চিন্তা করতে হলো না। কেবল প্রিন্ট করার সময় a, b, c তিনটির মান পরস্পরের সমান নয়, সেটি নিশ্চিত করে নিলেই হলো! বুদ্ধিটা ভালোই, তবে এটির চেয়ে আমাদের আগের প্রোগ্রামটি কম্পিউটারকে দিয়ে কম কাজ করায়, তাই চলতেও কম সময় লাগে, বা কম্পিউটারের ভাষায় বললে রান টাইম (run time) কম। আসলে একটি প্রোগ্রাম চলতে কেমন সময় লাগবে সেটি নির্ভর করে মূলত প্রোগ্রামটি মোট কয়টি অ্যাসাইনমেন্ট অপারেশন (assignment operation) আর কয়টি কম্পারিজন অপারেশন (comparison operation) করল তার ওপর।
অধ্যায় পাঁচ] একটুখানি গণিত।
এই অধ্যায়ে আমরা প্রোগ্রামিংয়ের নতুন কিছু শিখব না। এখন পর্যন্ত আমরা যতটুকু প্রোগ্রামিং শিখেছি, তা দিয়েই কিছু সহজ-সরল গাণিতিক সমস্যার সমাধান করব।
১) x + y = 15, x – y = 5 হলে x ও y-এর মান কত?
সমীকরণদুটি যোগ করলে পাই 2x = 20, বা x = 10। আবার বিয়োগ করলে পাই, 2y = 10, বা y = 5। এখন একটি প্রোগ্রাম লিখতে হবে যেখানে x + y ও x – y-এর মান দেওয়া থাকবে, x ও y-এর মান বের করতে হবে। আমি প্রোগ্রামটি একটু পরে লিখে দেব। এর মধ্যে তুমি নিজে লিখার চেষ্টা করো। সহজ প্রোগ্রাম।
২) 4x + 5y = 14, 5x + 6y = 17 হলে x ও y-এর মান কত?
সমীকরণদুটিকে আমরা এভাবে লিখতে পারি:
a1x + b1y = c1, a2x + b2y = c2। তোমরা বিভিন্নভাবে এর সমাধান করতে পার। এর মধ্যে দুটি জনপ্রিয় উপায় হচ্ছে প্রতিস্থাপন (substitution) ও নির্ণায়কের (determinant) সাহায্যে সমাধান। পদ্ধতিগুলো জানা না থাকলে ক্লাস এইট বা নাইনের গণিত বই দেখো। সমাধান করলে দেখবে,
x = (b2c1 – b1c2) / (a1b2 – a2b1) এবং y = (a1c2 – a2c1) / (a1b2 – a2b1)। এখন a1, a2, b1, b2, c1, c2-এর জায়গায় নির্দিষ্ট মান বসিয়ে দিলেই x ও y-এর মান পেয়ে যাবে।
এই ধরনের সমীকরণ সমাধানের জন্যও আমরা একটি প্রোগ্রাম লিখব, যার ইনপুট হবে a1, a2, b1, b2, c1, c2 এবং আউটপুট হবে x ও y-এর মান। এটিও সহজ প্রোগ্রাম। নিজে চেষ্টা করো।
আশা করি, তোমরা দুটি সমস্যারই সমাধান নিজে করে ফেলতে পারবে। এখন আমি প্রথম সমস্যার কোড দিচ্ছি:
#include <stdio.h>
int main()
{
double x, y, x_plus_y, x_minus_y;
printf(“Enter the value of x + y: “);
scanf(“%lf”, &x_plus_y);
printf(“Enter the value of x – y: “);
scanf(“%lf”, &x_minus_y);
x = (x_plus_y + x_minus_y) / 2;
y = (x_plus_y – x_minus_y) / 2;
printf(“x = %0.2lf, y = %0.2lf\n”, x, y);
return 0;
}
প্রোগ্রাম: ৫.১
সমাধান খুবই সহজ। তবে লক্ষ করো যে আমি ভেরিয়েবলের ডাটা টাইপ int ব্যবহার না করে double ব্যবহার করেছি।
এবারে দ্বিতীয় সমস্যার কোড:
#include <stdio.h>
int main()
{
double a1, a2, b1, b2, c1, c2, x, y;
printf(“a1 = “);
scanf(“%lf”, &a1);
printf(“a2 = “);
scanf(“%lf”, &a2);
printf(“b1 = “);
scanf(“%lf”, &b1);
printf(“b2 = “);
scanf(“%lf”, &b2);
printf(“c1 = “);
scanf(“%lf”, &c1);
printf(“c2 = “);
scanf(“%lf”, &c2);
x = (b2 * c1 – b1 * c2) / (a1 * b2 – a2 * b1);
y = (a1 * c2 – a2 * c1) / (a1 * b2 – a2 * b1);
printf(“x = %0.2lf, y = %0.2lf\n”, x, y);
return 0;
}
প্রোগ্রাম: ৫.২
এটিও সহজ প্রোগ্রাম! তবে তোমরা দেখো (a1 * b2 – a2 * b1)-এর মান আমি দুবার বের করেছি (x-এর মান বের করার সময়, আবার y-এর মান বের করার সময়)। কাজটি একবারেই করা যেত এবং একবারে করলেই ভালো, তাহলে আমাদের প্রোগ্রাম দুটি গুণ ও একটি বিয়োগের কাজ কম করবে। আবার (a1 * b2 – a2 * b1)-এর মান যদি শূন্য হয়, তাহলে একটি ঝামেলা হয়ে যাচ্ছে, কারণ কোনো কিছুকে তো শূন্য দিয়ে ভাগ করা যায় না। তাই ওই মানটি শূন্য হলে আসলে সমীকরণের কোনো সমাধান নেই। এবার প্রোগ্রামটি আরও ভালোভাবে লিখে ফেলি।
#include <stdio.h>
int main()
{
double a1, a2, b1, b2, c1, c2, d, x, y;
printf(“a1 = “);
scanf(“%lf”, &a1);
printf(“a2 = “);
scanf(“%lf”, &a2);
printf(“b1 = “);
scanf(“%lf”, &b1);
printf(“b2 = “);
scanf(“%lf”, &b2);
printf(“c1 = “);
scanf(“%lf”, &c1);
printf(“c2 = “);
scanf(“%lf”, &c2);
d = a1 * b2 – a2 * b1;
if ((int) d == 0) {
printf(“Value of x and y can not be determined.\n”);
}
else {
x = (b2 * c1 – b1 * c2) / d;
y = (a1 * c2 – a2 * c1) / d;
printf(“x = %0.2lf, y = %0.2lf\n”, x, y);
}
return 0;
}
প্রোগ্রাম: ৫.৩
এখানে একটি ব্যাপার খেয়াল করো। আমি if-এর ভেতর লিখেছি (int) d == 0। এখানে আমি প্রথমে d (যা একটি double টাইপের ভেরিয়েবল)-কে ইন্টিজারে টাইপ কাস্ট করে তারপর তার মানটি 0-এর সমান কি না তা পরীক্ষা করেছি। পরীক্ষাটা এভাবেও করা যেত: if (d == 0.0) তবে এতে মাঝে মাঝে ঝামেলা হয়, ফ্লোটিং পয়েন্ট-সংক্রান্ত হিসাব-নিকাশের জন্য। তোমরা কম্পিউটার আর্কিটেকচার নিয়ে লেখাপড়া করলে বিষয়টা বুঝতে পারবে।
তোমাদের মনে একটি প্রশ্ন আসতে পারে যে এই সহজ সমস্যাগুলো প্রোগ্রামিং করে সমাধান করে কী লাভ? আসলে একবার প্রোগ্রাম লিখে ফেলার পরে কিন্তু আর সমাধান করতে হয় না। তারপর শুধু ইনপুট দেবে, প্রোগ্রামটি নিজেই সমস্যার সমাধান করে তোমাকে আউটপুট দেবে।
৩) আমি যদি তোমাকে দশ হাজার টাকা ঋণ দিই 35% সুদে এবং টাকাটা পাঁচ বছর সময়ের মধ্যে তোমাকে সুদে-আসলে পরিশোধ করতে বলি, তাহলে পাঁচ বছরে মোট কত টাকা তোমার দিতে হবে এবং প্রতি মাসে কত টাকা দিতে হবে? ঋণটা যদি জটিল কিছু না হয়, তাহলে তোমার মোট পরিশোধ করতে হবে 10000 + 10000 * 35 / 100 টাকা। এই সহজ-সরল ঋণের জন্য একটি প্রোগ্রাম লিখে ফেলা যাক:
#include <stdio.h>
int main()
{
double loan_amount, interest_rate, number_of_years, total_amount, monthly_amount;
printf(“Enter the loan amount: “);
scanf(“%lf”, &loan_amount);
printf(“Enter the interest rate: “);
scanf(“%lf”, &interest_rate);
printf(“Number of years: “);
scanf(“%lf”, &number_of_years);
total_amount = loan_amount + loan_amount * interest_rate / 100.00;
monthly_amount = total_amount / (number_of_years * 12);
printf(“Total amount: %0.2lf\n”, total_amount);
printf(“Monthly amount: %0.2lf\n”, monthly_amount);
return 0;
}
প্রোগ্রাম: ৫.৪
আমাদের ফর্মুলাতে একটু সমস্যা আছে। আসলে 35% সুদ দিতে হলে সেটা বাৎসরিক সুদ হবে। অর্থাৎ প্রতি বছর মোট ঋণের উপর 35% সুদ দেওয়া লাগবে। তাহলে দেখা যাচ্ছে পাঁচ বছরে তোমার মোট পরিশোধ করতে হবে 10000 + 10000 * 35 * 5 / 100 টাকা। এখন এই ফর্মুলা অনুযায়ী প্রোগ্রাম লিখে ফেলো।
তবে বাস্তবে ঋণের হিসাব-নিকাশ কিন্তু এত সরল নয়। তুমি ব্যাংক থেকে ঋণ নিতে গেলেই সেটি টের পাবে।
৪) পদার্থবিজ্ঞানের একটি সমস্যার সমাধান করা যাক।
কোনো বস্তু u আদিবেগে (initial velocity) এবং a ত্বরণে (acceleration) যাত্রা শুরু করল (ত্বরণের মান সব সময় a থাকবে, বাড়বে বা কমবে না)। t সময় পরে এর বেগ যদি v হয় তাহলে 2t সময়ে বস্তুটি কত দূরত্ব অতিক্রম করবে? (সমস্যাটি দিয়েছেন শাহরিয়ার মঞ্জুর, এটি ভ্যালাডলিড অনলাইন জাজের 10071 নম্বর সমস্যা)।
2t সময়ে অতিক্রান্ত দূরত্ব হবে v x 2t। এটি প্রমাণ করে ফেলো। তারপর আবার পড়া শুরু করো। নবম-দশম শ্রেণীর পদার্থবিজ্ঞান বইতে তোমরা দুটি সূত্র পাবে:
v = u + at
s = ut + 0.5 at^2 (এখানে s হচ্ছে t সময়ে অতিক্রান্ত দূরত্ব)।
তাহলে 2t সময় পরে অতিক্রান্ত দূরত্ব হবে
u x 2t + 0.5 x a x (2t)^2 = u x 2t + 0.5 x a x 4t^2 = u x 2t + a x 2t^2 = 2t (u + at) = 2tv
এখন, তোমাদেরকে একটি প্রোগ্রাম লিখতে হবে, যেখানে v ও t-এর মান ইনপুট হিসেবে দেওয়া হবে, 2t সময়ে অতিক্রান্ত দূরত্ব নির্ণয় করতে হবে। প্রোগ্রামটি নিজে নিজে লিখে ফেলো।
৫) 1 + 2 + 3 + … + 998 + 999 + 1000 এই ধারার সমষ্টি কত?
তোমরা যারা ধারার যোগফলের সূত্র জানো, তারা চট করে বলে দিতে পারবে, এই ধারাটির যোগফল হচ্ছে 1000 x 1001 / 2। তাহলে এর জন্য একটি প্রোগ্রাম লিখে ফেলা যাক, যেখানে শেষ পদের মান হবে ইনপুট আর আউটপুট হবে যোগফল।
#include <stdio.h>
int main()
{
int n, sum;
scanf(“%d”, &n);
sum = (n * (n + 1)) / 2;
printf(“Summation is %d\n”, sum);
return 0;
}
প্রোগ্রাম: ৫.৫
ধারার যোগফল নির্ণয়ের সূত্র জানা না থাকলে আমরা লুপ ব্যবহার করে প্রোগ্রামটি লিখতে পারি।
#include <stdio.h>
int main()
{
int i, n, sum;
scanf(“%d”, &n);
for(i = 1, sum = 0; i <= n; i++) {
sum = sum + i;
}
printf(“Summation is %d\n”, sum);
return 0;
}
প্রোগ্রাম: ৫.৬
সুতরাং ধারার সমস্যা নিয়ে আর চিন্তা নেই। তুমি যদি একটি পদের মান তার আগের পদের চেয়ে কত করে বাড়ছে, সেটি বের করতে পারো, তাহলেই লুপ ব্যবহার করে যোগফল বের করে ফেলতে পারবে। তবে সূত্র বের করতে পারলে লুপ ব্যবহার না করাই ভালো। কারণ প্রথম প্রোগ্রামটি দেখো (যেখানে সূত্র ব্যবহার করেছি)। সেখানে একটি যোগ, একটি গুণ আর একটি ভাগ করতে হয়েছে, n-এর মান যত বড়ই হোক না কেন। আর দ্বিতীয় প্রোগ্রামে (যেখানে লুপ ব্যবহার করেছি) n-এর মান যত, ততবার যোগ করতে হয়েছে, আবার সেই যোগফলটি sum ভেরিয়েবলে রাখতে হয়েছে (ভেরিয়েবলে কোনো মান রাখতেও কিন্তু একটু সময় লাগে)।
এখন তোমাদের একটি সহজ প্রোগ্রাম লিখতে হবে। প্রথম n সংখ্যক ধনাত্মক বেজোড় সংখ্যার যোগফল নির্ণয়ের প্রোগ্রাম। n-এর মান হবে ইনপুট, আর যোগফল হবে আউটপুট।
৬) আমাদের এবারকার প্রোগ্রামটি হবে তাপমাত্রাকে সেলসিয়াস (Celsius) থেকে ফারেনহাইটে (Farenheit) রূপান্তর করার প্রোগ্রাম।
সেলসিয়াসকে ফারেনহাইটে রূপান্তরের সূত্র হচ্ছে: °F = (°C × 1.8) + 32।
#include <stdio.h>
int main()
{
double celsius, farenheit;
printf(“Enter the temperature in celsius: “);
scanf(“%lf”, &celsius);
farenheit = 1.8 * celsius + 32;
printf(“Temperature in farenheit is: %lf\n”, farenheit);
return 0;
}
প্রোগ্রাম: ৫.৭
এখন তোমাদের কাজ হচ্ছে ফারেনহাইট থেকে সেলসিয়াসে রূপান্তরের প্রোগ্রাম লেখা।
৭) এখন আমরা দুটি সংখ্যার গসাগু (GCD → Greatest Common Divisor বা HCF → Highest Common Factor) ও লসাগু (LCM → Least Common Multiple) নির্ণয় করার জন্য প্রোগ্রাম লিখব।
দুটি সংখ্যার গসাগু হচ্ছে যেসব সংখ্যা দিয়ে ওই দুটি সংখ্যা নিঃশেষে বিভাজ্য হয়, তাদের মধ্যে সবচেয়ে বড় সংখ্যা। তাহলে আমরা যেটি করব, দুটি সংখ্যা a ও b নেব। তারপর এদের মধ্যে যেটি ছোট, সেই মানটি আবার x ভেরিয়েবলে রাখব। গসাগু এর মান x-এর চেয়ে বড় হওয়া সম্ভব নয় (5 ও 10-এর গসাগু-এর মান নিশ্চয়ই 5-এর চেয়ে বড় হবে না)। এখন a ও b, x দিয়ে নিঃশেষে বিভাজ্য হয় কি না (a % x == 0 এবং b % x == 0) সেটি পরীক্ষা করব। যদি হয় তবে আমরা গসাগু পেয়ে গেছি। যদি a ও b উভয়েই নিঃশেষে বিভাজ্য না হয়, তখন x-এর মান এক কমিয়ে পরীক্ষা করব। যতক্ষণ না আমরা গসাগু পাচ্ছি x-এর মান কমাতেই থাকব। একসময় আমরা গসাগু পাবই, কারণ x-এর মান যখন 1 হবে, তখন তো x দিয়ে a ও b দুটি সংখ্যাই নিঃশেষে বিভাজ্য। তোমরা কি প্রোগ্রামটি নিজে লিখার চেষ্টা করবে? না পারলে আমার কোড দেখো:
#include <stdio.h>
int main()
{
int a, b, x, gcd;
scanf(“%d %d”, &a, &b);
if (a < b) {
x = a;
}
else {
x = b;
}
for(; x >= 1; x–) {
if (a % x == 0 && b % x == 0) {
gcd = x;
break;
}
}
printf(“GCD is %d\n”, gcd);
return 0;
}
প্রোগ্রাম: ৫.৮
প্রোগ্রামে দেখো gcd পাওয়ার সঙ্গে সঙ্গে লুপ থেকে বের হয়ে যেতে হবে (আমি break ব্যবহার করেছি এই জন্য)। break ব্যবহার না করলে কী হবে সেটি পরীক্ষা করে দেখো।
তবে গসাগু বের করার জন্য আমি যেই পদ্ধতি ব্যবহার করেছি সেটি খুব সহজ পদ্ধতি হলেও ইফিশিয়েন্ট (efficient) নয়। যেমন, সংখ্যা দুটি খুব বড় হলে এবং সহমৌলিক (co-prime) হলে লুপটি কিন্তু অনেকবার ঘুরবে। কারণ সহমৌলিক হলে গসাগু হবে 1। তোমরা নিশ্চয়ই জানো যে, দুটি সংখ্যার মধ্যে 1 ছাড়া আর কোনো সাধারণ উৎপাদক না থাকলে সংখ্যা দুটি সহমৌলিক।
গসাগু বের করার জন্য ইউক্লিডের একটি চমৎকার পদ্ধতি আছে। ইউক্লিড ভাগশেষ উপপাদ্যের (division algorithm) সাহায্যে গসাগু বের করার উপায় দেখিয়েছেন। এই পদ্ধতিতে খুব সহজে গসাগু বের করা যায় এবং প্রোগ্রামটিও বেশ ইফিশিয়েন্ট হয়। এর জন্য দুটি জিনিস জানা লাগবে:
a ও 0-এর গসাগু-এর মান a।
a ও b-এর গসাগু = b ও a % b-এর গসাগু।
তাহলে প্রোগ্রামে যেটি করতে হবে, একটি লুপের সাহায্যে a-এর মান b আর b-এর মান a%b বসিয়ে যেতে হবে, যতক্ষণ না b-এর মান শূন্য হয়। b-এর মান শূন্য হলেই বুঝে যাব যে গসাগু হচ্ছে a (এটা কিন্তু প্রোগ্রাম শুরুর সময় a-এর মান না, b-এর মান যখন শূন্য হবে সেই সময় a-এর মান)।
#include <stdio.h>
int main()
{
int a, b, t, x, gcd;
scanf(“%d %d”, &a, &b);
if (a == 0) gcd = b;
else if (b == 0) gcd = a;
else {
while (b != 0) {
t = b;
b = a % b;
a = t;
}
gcd = a;
}
printf(“GCD is %d\n”, gcd);
return 0;
}
প্রোগ্রাম: ৫.৯
এই প্রোগ্রামটি আরও ইফিশিয়েন্ট করার চেষ্টা করো।
এবার লসাগু বের করার প্রোগ্রাম। তোমরা নিশ্চয়ই স্কুলে শিখেছ, কীভাবে লসাগু বের করতে হয়। সেই পদ্ধতি অবলম্বন করে প্রোগ্রাম লিখে ফেলো। আর যারা সেই পদ্ধতি জানো না, তাদের জন্য একটি সূত্র বলে দিচ্ছি। আশা করি, লসাগু বের করার প্রোগ্রাম লিখতে আর সমস্যা হবে না।
দুটি সংখ্যার লসাগু x দুটি সংখ্যার গসাগু = সংখ্যা দুটির গুণফল।
Leave a Reply