প্রোগ্রামিং ল্যাঙ্গুয়েজ

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

আমি যখন কলেজে পড়তাম, তখন কিউ-বেসিক (Q Basic) নামে একটা প্রোগ্রামিং ল্যাঙ্গুয়েজ শেখার ব্যর্থ চেষ্টা করেছিলাম। কিউ-বেসিক ল্যাঙ্গুয়েজটা আমাদের সিলেবাসে ছিল আর কী। এইচএসসি পরীক্ষার পরে কম্পিউটার কিনি, তখন এইচটিএমএল (HTML) শিখলাম কিছুটা, যদিও এটা ঠিক প্রোগ্রামিং ল্যাঙ্গুয়েজ না। তারপরে ২০০১ সালের শুরু থেকে সি (C) শেখা শুরু করি। আমাদের ভার্সিটির ক্লাস শুরু হয় ২০০১ সালের মে মাসে, আর ততদিনে সি এর বেসিক কিছুটা শেখা হয়েছে। আমি আমার বাকী ভার্সিটি-জীবন এর সুবিধা ভোগ করি। আমার যদি ভার্সিটির সি কোর্সের ক্লাশ থেকে সি শেখা লাগতো, তাহলে একটু অসুবিধাই হতো হয়ত, যেটা আমার অনেক ক্লাসমেটকে দেখে বুঝতে পেরেছি। সি শেখার সময় প্রথম বছরে ৩-৪টা বই কিনেছিলাম, যদিও সবগুলো বই শুরু থেকে শেষ পর্যন্ত পড়ি নাই। এক বছর সি শেখার পরে আমি হার্বার্ট শিল্ডের টিচ ইয়োরসেল্ফ সি প্লাস প্লাস বইটা পড়ি। কিন্তু এরপরে আর আমার সি প্লাস প্লাস (C++) চর্চা করা হয় নাই।

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

ভার্সিটির সেকেন্ড ইয়ারে অবজেক্ট ওরিয়েন্টেড কোর্স ছিল। সেই কোর্সে জাভা (Java) শিখি। আর তারপরের সেমিস্টারে একটা প্রজেক্টও করি জাভা ব্যবহার করে। তারপরে ২০০৬-২০০৭ সালে কিছু টুকটাক কাজ করতে জাভা ব্যবহার করেছিলাম।

সম্ভবত ফোর্থ ইয়ারে আমাদের মাইক্রোপ্রসেস কোর্স ছিল, সেই কোর্সের ল্যাবের জন্য এসেম্বলি ল্যাঙ্গুয়েজ (Assembly Language) শিখতে হয়েছিল।

আমার প্রথম প্রফেশনাল চাকরি ছিল টাইগার আইটি-তে, ২০০৭ সালের মাঝামাঝি। সেখানে আমি যেই প্রজেক্টে জয়েন করলাম, সেই প্রজেক্টে পার্ল (Perl) প্রোগ্রামিং ল্যাঙ্গুয়েজ ব্যবহার করতে হয়। কিন্তু আমি আগে কখনও এই ল্যাঙ্গুয়েজের নাম শুনি নাই। তাই বলে আমার কিন্তু চাকরি পেতে সমস্যা হয় নাই। কারণ ভালো কোম্পানীগুলো বেশি গুরুত্ব দেয় প্রবলেম সলভিং স্কিলের ওপর, প্রোগ্রামিং ল্যাঙ্গুয়েজ শেখার ওপর নয়।

আমার দ্বিতীয় সফটওয়্যার ইঞ্জিনিয়ারিং চাকরি ছিল ট্রিপার্ট ল্যাবসে (যেটা পরে প্লেডম কিনে নেয়, আবার প্লেডমকে ডিজনী কিনে নেয়)। সেখানে ব্যাকএন্ডের কাজ হতো পিএইচপি (PHP) প্রোগ্রামিং ল্যাঙ্গুয়েজে। আর মাঝেমধ্যে অল্পস্বল্প জাভাস্ক্রিপ্ট। তো সেই চাকরির ইন্টারভিউতে আমাকে জিজ্ঞাসা করল যে পিএইচপি পারি কী না। আমি সোজা বলে দিলাম যে পারি না, কারণ এর আগে ২-৩ দিন পিএইচপি নিয়ে গুতাগুতি করলেও সেটা বলার মতো কিছু না। কিন্তু সেজন্য আমার চাকরি পাওয়া আটকায় নাই। সেখানে এক বছর কাজ করার পরে একটা নতুন প্রজেক্টে কাজ করতে হয়, আর সেই প্রজেক্ট হচ্ছে অ্যাকশন স্ক্রিপ্ট (Actionscript)-এ। তো সেটাও দুই-তিন দিন শিখে কাজ শুরু করে দেই।

তারপরে তিন বছর আমার নিজের কোম্পানী মুক্তসফট নিয়ে ব্যস্ত ছিলাম। সেখানে পিএইচপি, পার্ল, পাইথন (Python) – এসব ল্যাঙ্গুয়েজ ব্যবহার করেছি, যখন প্রোগ্রামিং করতে হয়েছে। জেকুয়েরি ব্যবহার করেও একটা প্রজেক্ট করেছিলাম। আসলে ক্লায়েন্ট যেই ল্যাঙ্গুয়েজ চাইতো, সেটাই ব্যবহার করতাম। আর ক্লায়েন্ট কিছু না বললে পাইথন। তারপরে দুই বছর একটা আমেরিকান কোম্পানীর কাজ করি, সেখানে আমি পাইথন ব্যবহার করার সিদ্ধান্ত নেই, কারণ পাইথনে কোড করতে ভালো লাগে এবং সময় কম লাগে।

২০১৫ সালের মাঝামাঝি আমি সিঙ্গাপুরের গ্র্যাব নামক কোম্পানীতে ইন্টারভিউ দেই। বেশ কয়েকটা ইন্টারভিউ হয় এবং সেখানে আমি সি ব্যবহার করি, প্রবলেম সলভ করার জন্য। ইন্টারভিউ শেষে অফার পেয়ে জয়েন করি। জয়েন করার পরে জানতে পারলাম যে এখানে গো (Go বা Golang) ব্যবহার করা হয়, তাই প্রথম কিছুদিন গো শিখি। লক্ষ্য করার বিষয় হচ্ছে এত বড় কোম্পানী এত বেতন দিয়ে অন্য দেশ থেকে ইঞ্জিনিয়ার হায়ার করছে, ওরা কিন্তু এই বিষয় নিয়ে মাথা ঘামায় নাই যে আমি গো পারি কী না। সুতরাং বোঝাই যাচ্ছে যে কয়টা প্রোগ্রামিং ল্যাঙ্গুয়েজ পারি, এটা আসলে বিবেচ্য বিষয় নয়। কম্পিউটার সায়েন্সের বেসিক জ্ঞান (ডাটা স্ট্রাকচার, অ্যালগরিদম, অপারেটিং সিস্টেম, ডাটাবেজ, অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং, নেটওয়ার্কিং ইত্যাদি) এবং প্রবলেম সলভিং স্কিল-ই একজন ভালো সফটওয়্যার ইঞ্জিনিয়ার হওয়ার পূর্বশর্ত। আর কাজ করতে করতে সফটওয়্যার ইঞ্জিনিয়ারিংটাও শেখা হয়ে যায়, তবে তার জন্য ভালো কোম্পানীতে কাজ করাটা জরুরী।

বিগ ইন্টিজার ২

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

যোগ / বিয়োগ / গুণ / ভাগ করা
দুটি বিগ-ইন্টিজার যোগ করার জন্য আমাদেরকে add() মেথডটি ব্যবহার করতে হবে। ধরা যাক, আমরা a এবং b দুটি সংখ্যা যোগ করে ans নামের একটি ভেরিয়েবলে রাখতে চাই। তাহলে আমাদের লিখতে হবে –
BigInteger ans = a.add(b);

একই ভাবে বিয়োগ করার জন্য subtract(), গুণ করার জন্য multiply(), এবং ভাগ করার জন্য আমাদেরকে divide() মেথড ব্যবহার করতে হবে।

ভাগশেষ বের করা
একটি সংখ্যা কে অপর একটি সংখ্যা দিয়ে ভাগ করার পর অবশিষ্ট ভাগশেষ বা mod ভ্যালু বের করতে চাইলে আমাদেরকে mod() মেথড টি ব্যবহার করতে হবে। যেমন, আমরা যদি একটি সংখ্যা a কে অপর একটি সংখ্যা m দিয়ে mod করতে চাই তাহলে আমাদের লিখতে হবে-
BigInteger ans = a.mod(m);

এছাড়াও remainder() মেথড দিয়েও একই কাজ করা যায়।

তুলনা করা
অন্য সব ডাটা টাইপের মত বিগ ইন্টিজারে আমরা দুটি সংখ্যা তুলনা করার জন্য ==, > বা < ব্যবহার করতে পারি না। দুটি বিগ-ইন্টিজার সমান কিনা তা দেখার জন্য আমাদের equals() মেথড টি ব্যবহার করতে হয়। সংখ্যা দুটি সমান হলে মেথডটি true রিটার্ন করে, তা নাহলে false রিটার্ন করে। দুটি বিগ-ইন্টিজার কম্পেয়ার করার জন্য জাভার BigInteger ক্লাসে compareTo() মেথড আছে। এই মেথডটি একটি ইন্টিজার সংখ্যা রিটার্ন করে। আমরা যখন দুটি সংখ্যা কম্পেয়ার করবো তখন প্রথম সংখ্যাটি যদি দ্বিতীয় সংখ্যার চেয়ে ছোটো হয় তাহলে মেথডটি -1 রিটার্ন করবে, সংখ্যা দুটি যদি সমান হয় তাহলে 0 রিটার্ন করবে এবং প্রথম সংখ্যাটি যদি বড় হয় তাহলে 1 রিটার্ন করবে। নিচের কোডটি রান করে দেখলে বিষয়টি আরো ভালভাবে বুঝা যাবে –

import java.util.*;
import java.math.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner (System.in); 
        BigInteger a, b;
        a = sc.nextBigInteger();
        b = sc.nextBigInteger();
        int cmp = a.compareTo(b);
        if(cmp == -1) 
            System.out.println("a is less than b");
        else if(cmp == 0) 
            System.out.println("a is equal to b");
        else if(cmp == 1) 
            System.out.println("a is greater than b");
    }
}

পাওয়ার বের করা
আমরা চাইলে বিগ-ইন্টিজারের পাওয়ারও বের করতে পারি। এজন্য আমাদেরকে pow() মেথডটি ব্যবহার করতে হবে। তবে এই মেথডটি প্যারামিটার হিসেবে একটি ইন্টিজার গ্রহন করে, তাই পাওয়ার এর মানটি অবশ্যই int ডাটা টাইপের রেঞ্জের মধ্যে হতে হবে। কোনো একটি সংখ্যা n এর পাওয়ার p বের করতে চাইলে আমাদের লিখতে হবে –
BigInteger ans = n.pow(p);

বিগ-মড ভ্যালু বের করা
বিগ-মড বা (n^p)%m এক্সপ্রেশনের মান বের করার জন্য বিগ-ইন্টিজারের modpow() মেথড আছে। মেথডটি প্যারামিটার হিসেবে দুটি BigInteger নিয়ে থাকে। এখন আমরা যদি কোন একটি সংখ্যা n-এর পাওয়ার p-কে অপর একটি সংখ্যা m দিয়ে mod করতে চাই, তাহলে আমাদের লিখতে হবে –

BigInteger ans = n.modPow(p,m);

মডুলার-ইনভার্স ভ্যালু বের করা
মডুলার-ইনভার্স বের করার জন্য বিগ-ইন্টিজারে modInverse() মেথড আছে। তবে এজন্য আমরা যে সংখ্যার মডুলার-ইনভার্স বের করতে চাই এবং যে সংখ্যাটি দিয়ে mod করতে চাই, তাদেরকে অবশ্যই রিলেটিভলি-প্রাইম হতে হবে। এখন আমরা যদি কোনো একটি সংখ্যা n-এর মডুলার-ইনভার্স বের করতে চাই এবং যে সংখ্যাটি দিয়ে mod করবো তা যদি m হয়, তাহলে আমাদের লিখতে হবে –
BigInteger ans = n.modInverse(m);

GCD বের করা
দুটি সংখ্যার Greatest Common Divisor (GCD) অর্থাৎ গসাগু বের করার জন্য বিগ-ইন্টিজারে gcd() মেথডটি আছে। দুটি সংখ্যা a এবং b-এর GCD বের করতে চাইলে আমাদের লিখতে হবে –
BigInteger ans = a.gcd(b);

ম্যাক্সিমাম/ মিনিমাম বের করা
জাভার বিগ-ইন্টিজারে দুটি সংখ্যার মধ্যে বৃহত্তর সংখ্যা বের করার জন্য max() এবং ক্ষুদ্রতর সংখ্যা বের করার জন্য min() মেথড রয়েছে। দুটি সংখ্যার মধ্যে ম্যাক্সিমাম বা মিনিমাম বের করার জন্য আমাদের লিখতে হবে –
BigInteger largest = a.max(b);
BigInteger smallest = a.min(b);

Absolute মান বের করা
কোনো সংখ্যার পরম মান বা Absolute value বের করার জন্য বিগ-ইন্টিজারে abs() মেথড আছে। কোনো একটি সংখ্যা n এর Absolute মান বের করতে চাইলে লিখতে হবে –
BigInteger ans = n.abs();

বিগ ইন্টিজার ৩

সম্ভাব্য-মৌলিক সংখ্যা
আমাদের অনেক সময় প্রাইম নাম্বার বের করার প্রয়োজন হতে পারে। বিশেষ করে ক্রিপ্টোগ্রাফীর জন্য প্রাইম নাম্বার জেনারেট করা অনেক জরুরি। একটি বিগ-ইন্টিজার সম্ভাব্য প্রাইম নাম্বার কি না তাও আমরা বের করতে পারি। এজন্য BigInteger ক্লাসে isProbablePrime() মেথড আছে। মেথডটিতে probabilistic primality টেস্টের জন্য Miller–Rabin অ্যালগরিদম ব্যবহার করা হয়েছে। মেথডটি প্যারামিটারে certainty হিসেবে একটি ইন্টিজার ভ্যালু নিয়ে থাকে এবং একটি বুলিয়ান ডাটা রিটার্ন করে। certainty দিয়ে অসম্ভাব্যতার হার বের করা হয়। তারপর তা থেকে সম্ভাব্যতার হার বের করা হয়। সম্ভাব্যতার হার বের করা হয় (1 – 0.5certainty) এভাবে। কোনো একটি সংখ্যা প্রাইম নাম্বার হবার সম্ভাব্যতা যদি এই মানকে অতিক্রম করে তাহলে মেথড টি true রিটার্ন করে, অন্যথায় false রিটার্ন করে। অর্থাৎ certainty এর মান যত বড় হবে, সম্ভাব্যতার হার তত বাড়বে। আবার অন্য দিকে সম্ভাব্যতার হার যত বাড়বে, প্রোগ্রামের এক্সিকিউশন টাইম ততো বেশি লাগবে। তাই এটা ব্যবহারকারীর উপর নির্ভর করে যে সে কতটুকু সময়ের মধ্যে কত সম্ভাব্যতার প্রাইম নাম্বার চায়।
কোন একটি সংখ্যা n, certainty c-এর সাপেক্ষে প্রাইম কি না, বের করতে হলে আমাদের লিখতে হবে –
boolean flag = n.isProbablePrime(c);

আবার কোনো একটি সংখ্যার পরবর্তি কোন সংখ্যাটি একটি সম্ভাব্য প্রাইম, তা বের করার জন্য বিগ ইন্টিজারে আছে nextProbablePrime() মেথড। মেথডটি একটি সম্ভাব্য প্রাইম নাম্বার রিটার্ন করে এবং রিটার্ন করা নাম্বারটি একটি কম্পোজিট নাম্বার হবার সম্ভাব্যতা থাকে 2-100 এর কম। কোনো একটি সংখ্যা n-এর পরবর্তি সম্ভাব্য প্রাইম সংখ্যাটি বের করতে হলে আমাদের লিখতে হবে-
BigInteger ans = n .nextProbablePrime();

আমাদের অনেক সময় র‍্যান্ডম প্রাইম নাম্বারের দরকার হতে পারে। বিগ ইন্টিজারে র‍্যান্ডম ভাবেও সম্ভাব্য প্রাইম নাম্বার জেনারেট করা যায়। এজন্য বিগ ইন্টিজারে probablePrime() মেথড আছে। মেথডটি প্যারামিটারে bitLength হিসেবে একটি ইন্টিজার এবং rnd হিসেবে একটি র‍্যান্ডম ডাটা নিয়ে থাকে। মেথডটির রিটার্ন করা নাম্বারটি এই bitLength-সংখ্যক বিটের হবে। মেথডটি কল করার সময় এর মান সব সময় 2 বা তার বেশি হতে হবে। আর rnd হচ্ছে একটি র‍্যান্ডম বিট সোর্স, একটি সম্ভাব্য প্রাইম নাম্বার রিটার্ন করার জন্য যার primality টেস্ট করা হয়। মেথডটি একটি সম্ভাব্য প্রাইম নাম্বার রিটার্ন করে এবং রিটার্ন করা নাম্বারটি একটি কম্পোজিট নাম্বার হবার সম্ভাব্যতা থাকে 2^-100 এর কম। এখন আমাদের যদি n সংখ্যক বিটের একটি র‍্যান্ডম সম্ভাব্য প্রাইম নাম্বার বের করতে হয়, তাহলে আমাদের লিখতে হবে –
Random rnd = new Random();
BigInteger ans =  BigInteger.probablePrime(n, rnd);

বিগ ইন্টিজার ৪

Bitwise অপারেশন
বিগ ইন্টিজারেও আমরা বিট-ওয়াইজ অপারেশন করতে পারি। এজন্য BigInteger ক্লাসে কিছু বিল্ট-ইন মেথড রয়েছে।

AND (a&b): বিগ ইন্টিজারের বিট-ওয়াইজ AND ভ্যালু বের করার জন্য রয়েছে and() মেথড। দুটি বিগ ইন্টিজার a এবং b-এর AND ভ্যালু বের করতে চাইলে লিখতে হবে –
BigInteger ans = a.and(b);

OR (a|b): বিগ ইন্টিজারের বিট-ওয়াইজ OR ভ্যালু বের করার জন্য রয়েছে or() মেথড। দুটি বিগ ইন্টিজার a এবং b-এর OR ভ্যালু বের করতে চাইলে আমাদের লিখতে হবে –
BigInteger ans = a.or(b);

XOR (a^b): বিগ ইন্টিজারে xor() মেথড টি দিয়ে বিট-ওয়াইজ XOR বা Exclusive OR ভ্যালু বের করা হয়। দুটি বিগ ইন্টিজার a এবং b এর XOR ভ্যালু বের করতে চাইলে আমাদের লিখতে হবে-
BigInteger ans = a.xor(b);

NOT (~a): বিগ ইন্টিজারের বিট-ওয়াইজ NOT ভ্যালু বের করার জন্য রয়েছে not() মেথড। কোন একটি বিগ ইন্টিজার a এর NOT ভ্যালু বের করতে চাইলে আমাদের লিখতে হবে-
BigInteger ans = a.not();

Shift-Left (a<<n): আমরা চাইলে বিগ ইন্টিজারের বিটগুলোকে শিফটও করতে পারি। বিটগুলোকে বাম দিকে শিফট করার জন্য আমাদেরকে shiftLeft() মেথডটি ব্যবহার করতে হবে। মেথডটি প্যারামিটারে একটি ইন্টিজার সংখ্যা নিয়ে থাকে। একটি নাম্বারের বিটগুলোকে আমরা বাম দিকে কত বিট শিফট করবো এটি হচ্ছে তার মান। কোনো একটি সংখ্যা a-কে আমরা যদি n বিট বামে শিফট করতে চাই, তাহলে লিখতে হবে –
BigInteger ans = a. shiftLeft(n);

Shift-Right (a>>n): বিগ ইন্টিজারের বিট গুলো কে ডান দিকে শিফট করার জন্য আমাদেরকে shiftRight() মেথডটি ব্যবহার করতে হবে। এটি shiftLeft() মেথডটির মতই। কোনো একটি সংখ্যা a-কে আমরা যদি n বিট ডানে শিফট করতে চাই, তাহলে লিখতে হবে –
BigInteger ans = a.shiftRight(n);

Test-Bit (a&(1<<n)): একটি বিগ ইন্টিজারের n-তম বিটটি 0 নাকি 1, তা বের করার জন্য BigInteger ক্লাসে আছে testBit() মেথড। মেথডটি প্যারামিটারে n-এর মান নেয় এবং n-তম বিট 1 হলে true রিটার্ন করে, আর 0 হলে false রিটার্ন করে। এখন আমরা যদি কোনো একটি সংখ্যা a-এর n-তম বিট পরীক্ষা করতে চাই, তাহলে লিখতে হবে-
boolean flag = a.testBit(n);

Clear-Bit (a & ~(1<<n)): একটি বিগ ইন্টিজারের কোনো একটি বিটকে 0 করতে হলে আমাদের clearBit() মেথডটি ব্যবহার করতে হবে। কোনো একটি সংখ্যা a-এর n-তম বিটকে 0 করতে চাইলে আমাদের লিখতে হবে-
BigInteger ans = a.clearBit(n);

Set-Bit (a|(1<<n)): একটি বিগ ইন্টিজারের কোনো একটি বিটকে 1 করতে হলে আমাদের setBit() মেথডটি ব্যবহার করতে হবে। কোনো একটি সংখ্যা a-এর n-তম বিটকে 1 করতে চাইলে আমাদের লিখতে হবে –
BigInteger ans = a.setBit(n);

Flip-Bit (a ^ (1<<n)): একটি বিগ ইন্টিজারের কোনো একটি বিটকে ফ্লিপ করতে হলে অর্থাৎ 0 থাকলে 1 করতে অথবা 1 থাকলে 0 করতে চাইলে আমাদের flipBit() মেথডটি ব্যবহার করতে হবে। কোনো একটি সংখ্যা a-এর n-তম বিটকে ফ্লিপ করতে চাইলে আমাদের লিখতে হবে-
BigInteger ans = a.flipBit(n);

AND-NOT (a & ~b): দুটি বিগ ইন্টিজারের বিট-ওয়াইজ AND-NOT ভ্যালু বের করতে চাইলে andNot() মেথডটি ব্যবহার করতে হবে। দুটি বিগ ইন্টিজার a এবং b এর AND-NOT ভ্যালু বের করতে চাইলে আমাদের লিখতে হবে-
BigInteger ans = a.andNot(b);

Lowest Set Bit (log2(a & -a)): কোনো সংখ্যার সবচেয়ে ছোট কোন বিটে 1 আছে, তা বের করার জন্য বিগ ইন্টিজারে getLowestSetBit() মেথড আছে। কোনো একটি বিগ ইন্টিজার a-এর সবচেয়ে ছোট কোন বিটটি 1 তা বের করতে চাইলে আমাদের লিখতে হবে –
int ans = a.getLowestSetBit();

আরো কিছু প্রয়োজনীয় মেথড
toString(): বিগ ইন্টিজার কে স্ট্রিং এ কনভার্ট করতে ব্যবহার করা হয়।
toByteArray(): বিগ ইন্টিজার কে বাইট-অ্যারে তে কনভার্ট করতে ব্যবহার করা হয়।
negate(): বিগ ইন্টিজারের সাইন পরিবর্তন করতে ব্যবহার করা হয়।
bitCount(): কোন সংখ্যার 2’s complement এ সাইন বিটের বিপরীত কয়টি বিট আছে তা বের করার জন্য ব্যবহার করা হয়।
bitLength(): একটি সংখ্যা কে বাইনারি বেইজে রিপ্রেজেন্ট করতে (সাইন বিট ছাড়া) কয়টি বিটের প্রয়োজন তা জানার জন্য ব্যবহার করা হয়।
signum(): কোন সংখ্যা ধনাত্মক, ঋণাত্মক অথবা শূন্য কি না তা জানার জন্য ব্যবহার করা হয়। ধনাত্মক হলে 1, ঋণাত্মক হলে -1 এবং শূন্য হলে মেথড টি 0 রিটার্ন করে।
intValue(): BigInteger থেকে int ডাটায় কনভার্ট করতে ব্যবহার করা হয়। তবে এ ক্ষেত্রে ডাটা ওভারফ্লো হলে মেথড টি কোন এক্সেপশন থ্রো করে না। এক্ষেত্রে intValueExact() ব্যবহার করলে এই মেথড টি এক্সেপশন থ্রো করে।
longValue(): BigInteger থেকে long ডাটায় কনভার্ট করতে ব্যবহার করা হয়। এই মেথড টি ও ডাটা ওভারফ্লো হলে এক্সেপশন থ্রো করে না। এক্ষেত্রে longValueExact() ব্যবহার করলে এই মেথড টি এক্সেপশন থ্রো করে।
floatValue(): BigInteger থেকে float ডাটায় কনভার্ট করতে ব্যবহার করা হয়।
doubleValue(): BigInteger থেকে double ডাটায় কনভার্ট করতে ব্যবহার করা হয়।
hashCode(): হ্যাশ-কোড বের করার জন্য ব্যবহার করা হয়।
divideAndRemainder(): মেথড টি দুটি সংখ্যার ভাগফল এবং ভাগশেষ এক সাথে একটি BigInteger অ্যারে আকারে রিটার্ন করে। রিটার্ন করা অ্যারে টির [0] ইন্ডেক্সে থাকে ভাগফলের মান এবং [1] ইন্ডেক্সে থাকে ভাগশেষ এর মান।

import java.util.*;
import java.math.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner (System.in); 
        BigInteger a=sc.nextBigInteger();
        BigInteger b=sc.nextBigInteger();
        BigInteger arr[] = a.divideAndRemainder(b); 
        System.out.println("Quotient = "+arr[0]);
        System.out.println("Remainder = "+arr[1]); 
    }
}

এই ছিলো আমাদের BigInteger নিয়ে আলোচনা। Java-তে BigDecimal নামে আরো একটি ক্লাস আছে যা দিয়ে Decimal সংখ্যার হিসাব নিকাশ করা যায়। এটির ব্যবহার BigInteger-এর মতোই।

বিগ ইন্টিজার ১

জাভার একটি চমৎকার জিনিস হচ্ছে বিগ ইন্টিজার (BigInteger)। সেটি নিয়ে আমার ব্লগের পাঠকদের জন্য একাধিক পর্বের সিরিজ লিখেছে তুষার রায় (বাংলাদেশ ইউনিভার্সিটি অব বিজনেস এন্ড টেকনোলোজি (বি ইউ বি টি)-তে কম্পিউটার বিজ্ঞান বিভাগে অধ্যয়নরত)।

প্রথম পর্ব

আমরা বিভিন্ন প্রোগ্রামিং ভাষায় হিসাব-নিকাশ করার জন্য সাধারণত int (32-bit) বা long (64-bit) টাইপের ডাটা ব্যবহার করে থাকি। এদের মধ্যে int ডাটা দিয়ে খুব বড় সংখ্যাগুলোর হিসাব-নিকাশ করা না গেলেও long ডাটা দিয়ে মোটামুটি 10^18 এর কাছাকাছি সংখ্যাগুলো এক্সেস করা যায়। সমস্যা হয় তখন যখন আমাদেরকে এর চেয়েও অনেক অনেক বড় সংখ্যা নিয়ে কাজ করার দরকার হয়। তখন আমরা কোনো সাধারণ ডাটা টাইপ দিয়ে সরাসরি এদের হিসাব-নিকাশ করতে পারি না, কারণ এতে করে আমাদের ভেরিয়েবলগুলোতে ডাটার ওভারফ্লো হয়।

এ ধরণের সমস্যা দূর করবার জন্য Java-তে BigInteger নামের একটি বিল্ট-ইন ক্লাস তৈরি করা আছে। যা দিয়ে খুব সহজেই অনেক বড় বড় সংখ্যার হিসাব-নিকাশ করে ফেলা যায়। BigInteger-এর সাইজ JVM-এর পর্যাপ্ত মেমোরির উপর নির্ভর করে। তবে প্রয়োজন ছাড়া এটি ব্যবহার করা উচিত নয়, কারণ BigInteger সাধারন ডাটা-টাইপ এর তুলনায় অনেক ধীরে কাজ করে। এখন তাহলে দেখা যাক, বিগ ইন্টিজার ব্যবহার করে আমরা কী কী কাজ করতে পারি এবং কীভাবে।

প্যাকেজ ইম্পোর্ট করাঃ
BigInteger ক্লাসটি জাভার math প্যাকেজের অন্তর্ভুক্ত। তাই BigInteger ব্যবহার করার জন্য আমাদেরকে প্রথমেই math প্যাকেজটি ইম্পোর্ট করে নিতে হবে।
import java.math.BigInteger;

ভেরিয়েবল ডিক্লেয়ার করাঃ
বিগ ইন্টিজার ভেরিয়েবল ডিক্লেয়ার করা অন্য সব ডাটা টাইপের মতোই। এখানে মূলত BigInteger ক্লাসের অবজেক্ট তৈরি করা হয়। যেমন, আমরা যদি a, b এবং c নামের তিনটি ভেরিয়েবল ডিক্লেয়ার করতে চাই তাহলে আমাদের এভাবে লিখতে হবে –
BigInteger a, b, c;

ইনপুট ও আউটপুটঃ
BigInteger এর ইনপুট ও আউটপুটও অন্য সব ডাটা টাইপের মতো। যেমন, আমরা যদি একটি ভেরিয়েবলের মান ইনপুট নিয়ে তা আউটপুটে দেখাতে চাই তাহলে আমাদের প্রোগ্রাম টি এভাবে লিখতে হবে –

import java.util.*;
import java.math.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner (System.in);
        BigInteger n;
        n = sc.nextBigInteger();
        System.out.println(n);
    }
}

ভ্যালু অ্যাসাইন করাঃ
আমাদেরকে অনেক সময় এক ভেরিয়েবলের মান অন্য ভেরিয়েবলে অথবা সরাসরি কোন মান একটি ভেরিয়েবলে অ্যাসাইন করার প্রয়োজন হতে পারে। এক ভেরিয়েবল থেকে অন্য ভেরিয়েবলে ভ্যালু অ্যাসাইন করতে আমরা সরাসরি ‘=’ ব্যবহার করতে পারি। যেমন, একটি ভেরিয়েবল b-এর মান অপর একটি ভেরিয়েবল a-তে অ্যাসাইন করতে চাইলে হলে লিখতে হবে –
BigInteger a = b;

কিন্তু সরাসরি যদি কোনো মান একটি ভেরিয়েবলে অ্যাসাইন করতে চাই, তাহলে BigInteger এর কন্সট্রাক্টর ব্যবহার করে ভেরিয়েবলে (যেটি আসলে একটি BigInteger অবজেক্ট) তার মান অ্যাসাইন করতে হবে। BigInteger-এর কন্সট্রাক্টরটি প্যারামিটার হিসেবে একটি নাম্বারের স্ট্রিং নিয়ে থাকে। যেমন –
BigInteger n = new BigInteger(“1234567890123456789”);

আবার আমরা BigInteger.valueOf(int_value) ব্যবহার করে যেকোনো ইন্টিজারকে সরাসরি BigInteger হিসেবে ব্যবহার করতে পারি।

BigInteger অ্যারেঃ
BigInteger এর আবার অ্যারে! অবাক হবার কিছু নেই। বিগ-ইন্টিজারের অ্যারেও আমরা ব্যবহার করতে পারি। এটিও অন্য সব ডাটা টাইপের অ্যারের মতোই।
BigInteger[] array_name = new BigInteger[array_size];

এখন আমরা চাইলে এই অ্যারেটি সর্টও করে ফেলতে পারি। সম্পুর্ন অ্যারে সর্ট করতে চাইলে লিখতে হবে Arrays.sort(array_name);, আর কোনো একটা নির্দিষ্ট রেঞ্জের ভ্যালু গুলো সর্ট করতে চাইলে লিখতে হবে Arrays.sort(array_name, fromIndex, toIndex+1);। সর্ট করার ক্ষেত্রে খেয়াল রাখতে হবে যাতে অ্যারেটির কোনো ইন্ডেক্সে নাল ভ্যালু না থাকে, নইলে আমাদের প্রোগ্রামটি এক্সেপশন থ্রো করবে।

দ্বিতীয় পর্ব

তৃতীয় পর্ব

চতুর্থ পর্ব

কোন পথে যে চলি

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

confusion-311388_640

তো এখন আমি যেটা দেখি, সবাই একটা বিষয় নিয়ে খুব দ্বিধাগ্রস্ত থাকে। পিএইচপি নাকি জাভা? এন্ড্রয়েড অ্যাপ নাকি পাইথন? আবার অনেকের ধারণা, ডট নেটে কাজ করতে না পারলে তার জীবন ব্যর্থ। এরকম কনফিউশন থাকাটা অস্বাভাবিক কিছু না, বরং খুবই স্বাভাবিক। কয়েকদিন আগে সরকারের একটা প্রজেক্ট FTFL (Fast Track Future Leader)-এর শেষ সপ্তাহে প্রোগ্রামিং ট্রেনিং দিতে গিয়েছিলাম। সেখানে এক মাসের ফাউন্ডেশন ট্রেনিং (কমিউনিকেশন স্কিল, আদব-কায়দা, সফট স্কিল ও একটু প্রোগ্রামিং স্কিল) শেষে সবার জন্য বিভিন্ন ট্র্যাক দেওয়া হল। আগ্রহ ও দক্ষতার বিচার করে বিভিন্ন জনকে বিভিন্ন ট্র্যাকে দেওয়া হলো। সেই ট্র্যাকের উপর ৩ মাসের প্রশিক্ষণ হবে। ট্র্যাকগুলো ছিলো ডট নেট, পিএচইপি (লারাভেল ফ্রেমওয়ার্ক), মোবাইল অ্যাপস্ (অ্যান্ড্রয়েড), জাভা ইত্যাদি। শিক্ষার্থীদের মাঝে এই ট্র্যাক নির্বাচন নিয়ে ব্যাপক টেনশন! কয়েকজন আমার সাথে কথা বলল, ভাইয়া অমুক ট্র্যাক নিচ্ছি, ভুল করছি না তো?

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

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

আমার সফটওয়্যার ইঞ্জিনিয়ারিং ক্যারিয়ারের প্রথম চাকরিতে পার্ল (Perl) প্রোগ্রামিং ভাষা ব্যবহার করতে হত। কিন্তু আমি এই চাকরি নেওয়ার আগে পার্ল জানতাম না। আর ইন্টারভিউতে আমাকে পার্ল নিয়ে কোনো প্রশ্নও করা হয় নি, বরং আমি কী জানতাম, সেটার উপরই প্রশ্ন হয়েছে। তেমনি দ্বিতীয় চাকরিতে মূল কাজ ছিল পিএচইপি ও জাভা স্ক্রিপ্ট। কিন্তু পিএচইপি ও জাভা স্ক্রিপ্টে আমার জ্ঞান ছিল একেবারে সামান্য। তাতে কিন্তু ইন্টারভিউ ফেস করতে কোনো সমস্যা হয় নি। আবার ওই অফিসে এক বছর পিএচইপিতে কাজ করার পরে হঠাৎ আমি (এবং আরো কয়েকজন) নতুন প্রজেক্টে ঢুকে গেলাম যেখানে মূল ল্যাঙ্গুয়েজ ছিল একশন স্ক্রিপ্ট (action script)। কিছুই পারতাম না, কিন্তু সেটা শিখে নিতে সময় লাগে নি। আমি চাইলে পিএচইপি ছাড়া আমি বাঁচবো না বলে জানালা দিয়ে লাফ দিতে পারতাম, কিন্তু সেটা দেই নাই। আমার অন্য কলিগরাও দেয় নাই। আমার মতো সাধারণ মেধার মানুষেরও ক্যারিয়ার এমন সহজ হওয়ার কারণ ছিল আমি ভার্সিটিতে কয়েক হাজার ঘণ্টা কোড করেছিলাম। আর এখন আমার বেশিরভাগ কাজই পাইথন প্রোগ্রামিং ভাষায়।

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

বেসিক জ্ঞান শক্ত কর, আত্মবিশ্বাসী হও, আচার-আচরণে ভদ্র হও। তোমাদের জন্য শুভকামনা।

জাভা দিয়ে ছোট্ট ওয়েব ক্রলার

জাভা প্রোগ্রামিং ল্যাঙ্গুয়েজ ব্যবহার করে সহজ একটি ওয়েব ক্রলার (বা স্পাইডার বা স্ক্রেপার)-এর কোড শেয়ার করছি। কোডটি আমি অনেক আগে একটি প্রজেক্ট করতে গিয়ে লিখেছিলাম। এটি সম্পূর্ণ ওয়েব ক্রলার নয়, কেবল একটি নমুনা (বা উদাহরণ) মাত্র।


কাজের ধাপ:

১) ব্যবহারকারীর কাছ থেকে ইনপুট হিসেবে ওয়েব সাইটের এড্রেস (ইউআরএল) নিতে হবে।

২) ওই ইউআরএল-এর এইচটিএমএল সোর্স কোড পড়তে হবে বা বের করতে হবে (getUrlContent(url))।

৩) এইচটিএমএল সোর্স কোড থেকে সব হাইপার-লিঙ্কগুলো বের করতে হবে (getHyperlinks(content))।

৪) প্রতিটি ইউআরএল-এর জন্য এইচটিএমএল সোর্স কোড বের করতে হবে এবং সেই সাথে এইচটিটিপি রেসপন্স কোডও বের করতে হবে (getHTTPResponseCode(url))।

 

সম্পূর্ণ সোর্স কোড নিচে দেওয়া হলো :

 import java.io.BufferedReader;    
 import java.io.IOException;    
 import java.io.InputStreamReader;    
 import java.io.FileWriter;    
 import java.io.BufferedWriter;    
 import java.net.HttpURLConnection;    
 import java.net.URL;    
 import java.net.SocketTimeoutException;    
 import java.net.UnknownHostException;    
 import java.util.ArrayList;    
 import java.util.regex.Matcher;    
 import java.util.regex.Pattern;    
 public class Checker {    
     public static void main(String args[]) throws Exception    
     {    
         String url = null;    
         if (args.length > 0) {    
             url = args[0];    
             System.out.println(url);    
         }    
         else {    
             System.out.println("Please enter the URL as a command line parameter.");    
             return;    
         }    
         String content = getUrlContent(url);    
         ArrayList<String> links = getHyperlinks(content);    
         FileWriter fstream = new FileWriter("out.txt");    
         BufferedWriter out = new BufferedWriter(fstream);    
         int status;    
         for (int i = 0; i < links.size(); i++) {    
             url = (String) links.get(i);    
             System.out.println(url);    
             status = getHTTPResponseCode(url);    
             if (status != 200) {    
                 if (status > 0) {    
                     out.write(url + ", HTTP Response Code: " + status + "n");    
                 }    
                 else {    
                     out.write(url + ", Unknown Errorn");    
                 }    
             }                
         }    
         out.close();    
     }    
     private static ArrayList<String> getHyperlinks(String html)    
     {    
         ArrayList<String> links = new ArrayList<String>();    
         Pattern p = Pattern.compile("<a [^<>]*?href="(http.*?)"");    
         Matcher m = p.matcher(html);    
         while(m.find()) {    
             links.add(m.group(1));    
         }    
         p = Pattern.compile("<a [^<>]*?href='(http.*?)'");    
         m = p.matcher(html);    
         while(m.find()) {    
             links.add(m.group(1));    
         }    
         return links;    
     }    
     private static String getUrlContent(String targetUrl) throws Exception    
     {    
         HttpURLConnection connection = null;    
         BufferedReader br = null;    
         StringBuilder sb = null;    
         String line = null;    
         String content = null;    
         URL target = null;    
         try {    
             target = new URL(targetUrl);    
             connection = (HttpURLConnection)target.openConnection();    
             connection.setRequestMethod("GET");    
             connection.setReadTimeout(30 * 1000); // timeout 30 seconds    
             connection.connect();    
             br = new BufferedReader(new InputStreamReader(connection.getInputStream()));    
             sb = new StringBuilder();    
             while ((line = br.readLine()) != null) {    
                 sb.append(line);    
             }    
             content = sb.toString();    
         } catch (SocketTimeoutException e) {    
             System.out.println("Timed Out!");                
         } catch (UnknownHostException e) {    
             System.out.println("Unknown Host");    
         } catch (Exception e) {    
             System.out.println("Unknown Error");    
         }    
         finally {    
             connection.disconnect();    
             br = null;    
             sb = null;    
             connection = null;    
         }    
         return content;    
     }    
     private static int getHTTPResponseCode(String targetUrl) throws Exception    
     {    
         HttpURLConnection connection = null;    
         int response;    
         URL target = null;    
         try {    
             target = new URL(targetUrl);    
             connection = (HttpURLConnection)target.openConnection();    
             connection.setRequestMethod("GET");    
             connection.setReadTimeout(10 * 1000); // timeout 10 seconds    
             connection.connect();    
             response = ((HttpURLConnection) connection).getResponseCode();    
         } catch (SocketTimeoutException e) {    
             response = -100;    
         } catch (UnknownHostException e) {    
             response = -101;    
         }catch (Exception e) {    
             response = -102;    
         }    
         finally {    
             connection.disconnect();    
             connection = null;    
         }    
         return response;    
     }    
 }