ট্র্যাক
/
Python
Python
/
সিলেবাস
/
জটিল সংখ্যা
জট

জটিল সংখ্যা মধ্যে Python

{one: "১টি অনুশীলনী", other: "%{count}টি অনুশীলনী"}

জটিল সংখ্যা সম্পর্কে

Complex numbers মোটেই জটিল নয়। এগুলোর জন্য শুধু একটা কম ভয়ংকর নাম দরকার।

এগুলো এতটাই কাজের, বিশেষ করে ইঞ্জিনিয়ারিং আর বিজ্ঞানে, যে Python ইন্টিজার (ints) ও ফ্লোটিং-পয়েন্ট সংখ্যার (floats) পাশাপাশি complex-কে একটি স্ট্যান্ডার্ড নিউমেরিক টাইপ হিসেবে অন্তর্ভুক্ত করেছে।

মূল বিষয়

Python-এ একটি complex মান আসলে দুটি ফ্লোটিং-পয়েন্ট সংখ্যার জোড়া। দুঃখজনক ঐতিহাসিক কারণে এদের বলা হয় "বাস্তব" ও "কাল্পনিক" অংশ। আবারও বলি, অদ্ভুত নামগুলো নয়, বরং ভেতরের সরলতাটির দিকেই মন দেওয়াই ভালো।

জটিল সংখ্যা তৈরি করার দুটি কমন উপায় আছে।

  1. complex(real, imag) কনস্ট্রাক্টরটি দুটি float প্যারামিটার নেয়:
>>> z1 = complex(1.5, 2.0)
>>> z1
(1.5+2j)

কনস্ট্রাক্টরটি স্ট্রিং ইনপুটও পার্স করতে পারে। এর একটা অদ্ভুত সীমাবদ্ধতা হলো, স্ট্রিংয়ে স্পেস থাকলে এটি ব্যর্থ হয়।

>>> complex('4+2j')
(4+2j)

>>> complex('4 + 2j')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string
  1. জটিল সংখ্যাটি <real part> + <complex part>j লিটারাল হিসেবে লেখা যায়, অথবা বাস্তব অংশটি শূন্য হলে শুধু <complex part>j হিসেবেও লেখা যায়:
>>> z2 = 2.0 + 1.5j
>>> z2
(2+1.5j)

শেষ ফলাফল complex() কনস্ট্রাক্টর ব্যবহার করার মতোই।

জটিল সংখ্যার ওই কাল্পনিক অংশের জন্য দুটি নিয়ম আছে:

  • এটি j দিয়ে চিহ্নিত করা হয় (i দিয়ে নয়, যেভাবে হয়তো আপনি গণিতের বইয়ে দেখেছেন)।

  • Python যাতে j-কে ভ্যারিয়েবলের নাম হিসেবে না দেখে, সেজন্য এটি অবশ্যই একটি সংখ্যার ঠিক পরে থাকতে হবে। প্রয়োজনে 1j ব্যবহার করুন।

>>> j
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined

>>> 1j
1j

>>> type(1j)
<class 'complex'>

বেশিরভাগ ইঞ্জিনিয়ার j নিয়েই খুশি। বেশিরভাগ বিজ্ঞানী ও গণিতবিদ কাল্পনিক বোঝাতে i গাণিতিক প্রতীকটি পছন্দ করেন, কিন্তু এই প্রতীকটি ইলেকট্রিক্যাল ইঞ্জিনিয়ারিংয়ে কারেন্ট বোঝাতে i ব্যবহারের সাথে সংঘর্ষে পড়ে। তাই Python ডিজাইন করার সময় জিতেছিলেন ইলেকট্রিক্যাল ইঞ্জিনিয়াররা।

জটিল সংখ্যার অংশগুলো আলাদা আলাদাভাবে পেতে:

>>> z2.real
2.0
>>> z2.imag
1.5

যেকোনো একটি অংশ শূন্য হতে পারে, আর তখন গণিতবিদরা হয়তো সংখ্যাটিকে "সম্পূর্ণ বাস্তব" বা "সম্পূর্ণ কাল্পনিক" বলে ডাকবেন। তবে Python-এ এটি তখনও একটি জটিল সংখ্যাই:

>>> complex(0, 1)
1j
>>> type(complex(0, 1))
<class 'complex'>

>>> complex(1, 0)
(1+0j)

আপনি হয়তো শুনেছেন, "i (বা j) হলো -1 এর বর্গমূল"।

আপাতত এর অর্থ কেবল এইটুকুই, কাল্পনিক অংশটি সংজ্ঞা অনুযায়ী একটি সমতা মেনে চলে

1j * 1j == -1  # => True

এটি একটি সরল ধারণা, তবে এর পরিণতি মজার।

গাণিতিক কাজ

ফ্লোট আর ইন্টিজারের সাথে ব্যবহৃত বেশিরভাগ operators জটিল সংখ্যার সাথেও কাজ করে:

>>> z1 = (1.5+2j)
>>> z2 = (2+1.5j)


>>> z1 + z2  # addition
(3.5+3.5j)

>>> z1 - z2  # subtraction
(-0.5+0.5j)

>>> z1 * z2  # multiplication
6.25j

>>> z1 / z2  # division
(0.96+0.28j)

>>> z1 ** 2  # exponentiation
(-1.75+6j)

>>> 2 ** z1  # another exponentiation
(0.5188946835878313+2.7804223253571183j)

>>> 1j ** 2  # j * j == -1
(-1+0j)

জটিল সংখ্যার গুণ ও ভাগের নিয়ম ব্যাখ্যা করা এই কনসেপ্টের পরিধির বাইরে (আর এই কাজগুলো আপনাকে খুব একটা "নিজে হাতে" করতে হবে বলেও মনে হয় না)।

জটিল সংখ্যার যেকোনো গাণিতিক বা ইলেকট্রিক্যাল ইঞ্জিনিয়ারিং ভূমিকা এ বিষয়ে আলোচনা করবে, যদি আপনি বিষয়টি নিয়ে গভীরে যেতে চান।

অথবা, Exercism-এ Complex Numbers নামে একটি প্র্যাকটিস অনুশীলনী আছে, যেখানে আপনি একেবারে মূল নীতি থেকে এই অপারেশনগুলো দিয়ে একটি জটিল সংখ্যার ক্লাস তৈরি করতে পারেন।

জটিল সংখ্যায় ইন্টিজার ডিভিশন সম্ভব নয়, তাই // ও % অপারেটর এবং divmod() ফাংশন জটিল সংখ্যা টাইপের ক্ষেত্রে ব্যর্থ হবে।

নিউমেরিক টাইপের জন্য এমন দুটি ফাংশন তৈরি করা হয়েছে, যা জটিল সংখ্যা নিয়ে কাজ করার সময় খুবই উপকারী:

  • <complex number>.conjugate() কেবল জটিল সংখ্যার কাল্পনিক অংশের চিহ্ন উল্টে দেয় (+ থেকে - অথবা উল্টোটাও)।
    • জটিল সংখ্যার গুণ যেভাবে কাজ করে, তার কারণে এটা আপনার ভাবনার চেয়েও বেশি কাজের।
  • abs(<complex number>) নিশ্চিতভাবেই এমন একটি বাস্তব সংখ্যা রিটার্ন করে যার কাল্পনিক অংশ নেই।
>>> z1
(1.5+2j)

>>> z1.conjugate() # flip the z1.imag sign
(1.5-2j)

>>> abs(z1) # sqrt(z1.real ** 2 + z1.imag ** 2)
2.5

cmath মডিউল

Python স্ট্যান্ডার্ড লাইব্রেরিতে বাস্তব সংখ্যা নিয়ে কাজ করার জন্য দরকারি ফিচারে ভরা একটি math মডিউল আছে।

জটিল সংখ্যা নিয়ে কাজ করার জন্য আছে সমতুল্য একটি cmath মডিউলও।

আমরা আপনাকে মডিউলটি ভালোভাবে পড়ে পরীক্ষা-নিরীক্ষা করতে উৎসাহ দিচ্ছি, তবে মূল বিভাগগুলো হলো:

  • কার্টেসিয়ান ও পোলার স্থানাঙ্কের মধ্যে রূপান্তর,
  • এক্সপোনেনশিয়াল ও লগ ফাংশন,
  • ত্রিকোণমিতিক ফাংশন,
  • হাইপারবোলিক ফাংশন,
  • ক্লাসিফিকেশন ফাংশন, এবং
  • দরকারি ধ্রুবক।

নিচে কিছু ধ্রুবক ব্যবহারের একটি উদাহরণ:

>>> import cmath

>>> euler = cmath.exp(1j * cmath.pi) # Euler's equation

>>> euler.real
-1.0
>>> round(euler.imag, 15) # round to 15 decimal places
0.0

তাহলে প্রকৃতির সবচেয়ে গুরুত্বপূর্ণ তিনটি ধ্রুবক e, i (বা j) আর pi নিয়ে গড়া একটি সরল এক্সপ্রেশনই দেয় ফলাফল -1। কেউ কেউ এটিকে গোটা গণিতের সবচেয়ে সুন্দর ফলাফল মনে করেন। এর উৎস ১৭৪০ সালের দিকে।


ঐচ্ছিক অংশ: জটিল সংখ্যা নিয়ে একটি FAQ

আগ্রহ না থাকলে এই অংশটি বাদ দিতে পারেন।

এটা কি বিশুদ্ধ গণিতের কোনো অদ্ভুত নতুন অংশ নয়?

ষোড়শ শতকে এটি অদ্ভুত ও নতুন ছিল।

৫০০ বছর পরে এসে এটি ইঞ্জিনিয়ারিং ও প্রাকৃতিক বিজ্ঞানের বেশিরভাগ শাখার কেন্দ্রে।

কেউ এগুলো ব্যবহার করবে কেন?

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

ঘুরপাক খাওয়া জিনিস আপনি চোখেই দেখতে পান। জটিল সংখ্যা হয়তো পৃথিবীকে ঘোরায় না, কিন্তু পৃথিবী ঘোরার ফলে কী ঘটে তা ব্যাখ্যা করার জন্য এগুলো দারুণ কাজ করে: বড় কোনো ঝড়ের যেকোনো স্যাটেলাইট ছবি দেখুন।

কম স্পষ্ট হলেও, শব্দ তরঙ্গের মতো, আলো তরঙ্গের মতো, রেডিও সিগন্যাল তরঙ্গের মতো, এমনকি আপনার দেশের অর্থনীতিও অন্তত আংশিকভাবে তরঙ্গের মতো।

এই তরঙ্গ প্রসেসিংয়ের অনেকটাই ট্রিগ ফাংশন (sin() ও cos()) দিয়ে করা যায়, কিন্তু সেটা খুব দ্রুতই গোলমেলে হয়ে পড়ে।

জটিল এক্সপোনেনশিয়াল নিয়ে কাজ করা অনেক সহজ।

কিন্তু আমার তো জটিল সংখ্যার দরকার নেই!

এটা সত্যি হয় শুধু তখনই, যখন আপনি কোনো গুহায় থাকেন আর খাবার জোগাড় করতে বের হন।

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

  1. সেমিকন্ডাক্টর চিপ।

    • ক্লাসিক্যাল পদার্থবিজ্ঞানে এগুলোর কোনো মানে হয় না, আর এগুলো কেবল কোয়ান্টাম মেকানিক্স (QM) দিয়েই ব্যাখ্যা (ও ডিজাইন) করা যায়।
    • QM-এ সংজ্ঞা অনুযায়ী সবকিছুই জটিল-মানবিশিষ্ট। (শেষ পর্যন্ত সবকিছুই ওয়েভফর্ম)
  2. ফাস্ট ফুরিয়ার ট্রান্সফর্ম (FFT) অ্যালগরিদম।

    • FFT হলো জটিল সংখ্যার একটি প্রয়োগ, আর শব্দ প্রেরণ, অডিও প্রসেসিং, ছবি আর ভিডিওর সাথে যুক্ত সবকিছুতেই এটি আছে।

    • MP3 আর অন্যান্য অডিও ফরম্যাট কম্প্রেশনের জন্য FFT ব্যবহার করে, যাতে কম স্টোরেজ জায়গায় বেশি অডিও ধরে।

    • আরও অনেক ইমেজ ও ভিডিও ফরম্যাটের মধ্যে JPEG কম্প্রেশন ও MP4 ভিডিওও কম্প্রেশনের জন্য FTT ব্যবহার করে।

    • মোবাইল টাওয়ারগুলো আপনার নিজের সেল সিগন্যালকে বাকি সবার থেকে আলাদা করতে যে ডিজিটাল ফিল্টার ব্যবহার করে, সেখানেও FFT কাজে লাগে।

তাহলে আপনি সম্ভবত এমন প্রযুক্তি ব্যবহার করছেন, যা সেকেন্ডে হাজার হাজার বার জটিল সংখ্যার হিসাবের ওপর নির্ভর করে।

GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি নতুন একটি উইন্ডো বা ট্যাবে খুলবে