من ربات ترجمیار هستم و خلاصه مقالات علمی رو به صورت خودکار ترجمه میکنم. متن کامل مقالات رو میتونین به صورت ترجمه شده از لینکی که در پایین پست قرار میگیره بخونین
سادهسازی اعداد مرکب با پایتون
منتشر شده در: realpython به تاریخ ۲۱ ژوئن ۲۰۲۱
لینک منبع: Simplify Complex Numbers With Python
فهرست
- ساخت اعداد مرکب در پایتون
- اعداد مرکب دقیق
- تابع complex() Factory
- آشنایی با اعداد مرکب پایتون
- دسترسی به بخشهای واقعی و تصویری
- محاسبه تابع یک عدد مرکب
- محاسبات اعداد مرکب
- اضافه کردن
- تفریق
- ضرب
- تقسیم
- به توان رساندن
- استفاده از اعداد مرکب پایتون به عنوان بردارهای دو بعدی
- دریافت مختصات
- محاسبه بزرگی
- پیدا کردن فاصله بین دو نقطه
- انتقال، برعکس کردن، مقیاس گذاری و چرخش
- کاوش ماژول ریاضی برای اعداد مرکب: cmath
- استخراج ریشه یک عدد مرکب
- تبدیل بین مختصات مستطیلی و قطبی
- نمایش اعداد مرکب به طور متفاوت
- جدا کردن یک عدد مرکب در پایتون
- تست کیفیت اعداد مرکب
- مرتبسازی اعداد مرکب
- قالببندی اعداد پیچیده به عنوان رشته
- ایجاد نوع دادههای پیچیده خودتان
- محاسبه تبدیل فوریه گسسته با اعداد مرکب
- نتیجهگیری
بیشتر زبانهای برنامهنویسی با اهداف عمومی هیچ پشتیبانی یا پشتیبانی محدودی برای اعداد مرکب ندارند. گزینههای معمول شما یادگیری برخی ابزارهای تخصصی مانند MATLAB یا پیدا کردن کتابخانه شخص ثالث است. پایتون یک استثنا نادر است زیرا اعداد مرکبی در آن ساخته شدهاند.
با وجود این نام، اعداد مرکب، پیچیده نیستند! آنها در حل مشکلات عملی که در این آموزش طعم آنها را میچشید راحت هستند. شما گرافیک برداری و تحلیل فرکانس صدا را بررسی خواهید کرد، اما اعداد پیچیده میتوانند برای مثال به ترسیم مقاطع نیز کمک کنند.
در این برنامه آموزشی یاد خواهید گرفت که چگونه:
- اعداد مرکب را با حروف در پایتون تعریف کنید
- نمایش مجدد اعداد مرکب در مختصات مستطیلی و قطبی
- از اعداد مرکب در عبارات ریاضی استفاده کنید
- از مزیت ماژول ساختهشده در محاسبات ریاضی استفاده کنید.
- تبدیل فرمولهای ریاضی مستقیم به کد پایتون
اگر به یک یادآوری سریع یا معرفی آرام نظریه اعداد مرکب نیاز دارید، میتوانید سری فیلمهای آکادمی خان را ببینید. برای دانلود کد نمونه استفادهشده در این برنامه آموزشی، روی لینک زیر کلیک کنید:
دریافت کد نمونه: برای دریافت نمونه کدی که برای یادگیری اعداد مختلط در پایتون در این مقاله آموزشی استفاده خواهید کرد، اینجا کلیک کنید.
ساخت اعداد مرکب در پایتون
ایجاد و دستکاری اعداد پیچیده در پایتون تفاوت زیادی با دیگر انواع داده داخلی، به ویژه انواع عددی ندارد. این امکان وجود دارد چون این زبان با آنها به عنوان شهروندان درجه یک برخورد میکند. این به این معنی است که شما میتوانید فرمولهای ریاضی که شامل اعداد پیچیده با سربار کم هستند را بیان کنید.
پایتون به شما این امکان را میدهد که از اعداد مرکب در عبارات ریاضی استفاده کنید و بر روی آنها توابع فراخوانی کنید، درست مانند اعداد دیگر در پایتون. این منجر به ترکیب زیبایی میشود که تقریبا مانند یک کتاب ریاضی خوانده میشود.
حروف اعداد مرکب
سریعترین راه برای تعریف یک عدد مرکب در پایتون، تایپ کردن متن آن به صورت مستقیم در کد منبع است:
>>> z = 3 + 2j
اگرچه این یک فرمول جبری به نظر میرسد، عبارت سمت راست علامت تساوی در حال حاضر یک مقدار ثابت است که نیازی به ارزیابی بیشتر ندارد. زمانی که نوع آن را بررسی میکنید، تایید خواهید کرد که واقعا یک عدد مرکب است:
>>> type(z)
<class 'complex'>
چگونه با اضافه کردن دو عدد با اپراتور بعلاوه تفاوت دارد؟ نکته واضح این است که حرف j به عدد دوم چسبیدهاست، که به طور کامل معنای عبارت را تغییر میدهد. اگر حرف را حذف کنید، به جای آن یک نتیجه عدد صحیح آشنا به دست خواهید آورد:
>>> z = 3 + 2
>>> type(z)
<class 'int'>
در ضمن میتوانید از اعداد شناور برای ایجاد اعداد مرکب نیز استفاده کنید:
>>> z = 3.14 + 2.71j
>>> type(z)
<class 'complex'>
اعداد مرکب در پایتون نماد ریاضی را تقلید میکنند که به عنوان فرم استاندارد، فرم جبری یا گاهی فرم قانونی یک عدد مرکب نیز شناخته میشود. در پایتون میتوانید از حروف کوچک یا بزرگ در آن حروف استفاده کنید.
اگر در کلاس ریاضی با اعداد مرکب آشنا شدید، ممکن است دیده باشید که آنها با استفاده از i به جای j بیان میشوند.
فرم جبری یک عدد مرکب از قوانین استاندارد جبر پیروی میکند که در انجام محاسبات مناسب است. برای مثال، جمع خاصیت جا به جایی دارد که به شما این امکان را میدهد که ترتیب دو بخش از یک عدد مرکب را به صورت تحتاللفظی و بدون تغییر مقدار آن عوض کنید:
>>> 3 + 2j == 2j + 3
True
به طور مشابه، میتوانید جمع را برای تفریق در یک عدد مرکب به صورت تحتاللفظی جایگزین کنید چون علامت منفی فقط یک نماد کوتاه برای یک شکل معادل است:
>>> 3 - 2j == 3 + (-2j)
True
آیا یک عدد مرکب تحتاللفظی در پایتون همیشه باید شامل دو عدد باشد؟ آیا چیز بیشتری میتواند داشته باشد؟ آیا سفارش شدهاند؟ برای پاسخ به این سوالات، بیایید چند آزمایش انجام دهیم. جای تعجب نیست که اگر شما تنها یک عدد را بدون حرف j مشخص کنید، در نهایت به یک عدد صحیح منظم یا یک عدد نقطه شناور خواهید رسید:
>>> z = 3.14
>>> type(z)
<class 'float'>
از سوی دیگر، ارسال حرف j به یک حرف عددی بلافاصله آن را به یک عدد مرکب تبدیل خواهد کرد:
>>> z = 3.14j
>>> type(z)
<class 'complex'>
به بیان دقیقتر، از نقطهنظر ریاضی، شما فقط یک عدد مجازی خالص ایجاد کردهاید، اما پایتون نمیتواند آن را به عنوان یک نوع داده مستقل نشان دهد. بنابراین، بدون بخش دیگر، این فقط یک عدد پیچیده است.
عکس این قضیه چطور است؟ برای ایجاد یک عدد مرکب بدون بخش مجازی، میتوانید از صفر استفاده کنید و آن را به این شکل اضافه یا کم کنید:
>>> z = 3.14 + 0j
>>> type(z)
<class 'complex'>
در واقع، هر دو بخش عدد مرکب همیشه وجود دارند. وقتی یک عدد را نمیبینید، به این معنی است که مقدار آن صفر است. بیایید ببینیم چه اتفاقی میافتد زمانی که سعی میکنید عبارات بیشتری را نسبت به قبل وارد کنید:
>>> 2 + 3j + 4 + 5j
(6+8j)
این بار، عبارت شما دیگر لفظی نیست زیرا پایتون آن را به یک عدد پیچیده متشکل از تنها دو بخش ارزیابی کرد. به یاد داشته باشید که قوانین اساسی جبر به اعداد پیچیده منتقل میشوند، بنابراین اگر عبارات مشابه را گروهبندی کنید و جمع جز به جز را اعمال کنید، در نهایت به ۶ + ۸ j خواهید رسید.
توجه کنید که چگونه پایتون اعداد پیچیده را به طور پیشفرض نمایش میدهد. ارائه متنی آنها شامل یک جفت ضمیمه پرانتز، یک حرف کوچک j، و بدون فضای خالی است. علاوه بر این، بخش مجازی در جایگاه دوم قرار دارد.
اعداد مرکب که همچنین اعداد مجازی خالص هستند بدون پرانتز ظاهر میشوند و تنها بخش مجازی خود را نشان میدهند:
>>> 3 + 0j
(3+0j)
>>> 0 + 3j
3j
این کار به تمایز اعداد مجازی از پیچیدهترین اعداد ساختهشده از بخشهای حقیقی و مجازی کمک میکند.
تابع complex() Factory
پایتون یک تابع داخلی، complex() دارد که شما میتوانید از آن به عنوان یک جایگزین برای عدد مرکب تحتاللفظی استفاده کنید:
>>> z = complex(3, 2)
در این شکل، شبیه به یک تاپل یا یک جفت منظم از اعداد معمولی است. این قیاس چندان دور از ذهن نیست. اعداد مرکب یک تفسیر هندسی در سیستم مختصات دکارتی دارند که شما در یک بیت آن را کت خواهید کرد. شما میتوانید اعداد مرکب را دو بعدی بدانید.
واقعیت جالب: در ریاضیات، اعداد مرکب به طور سنتی با حرف z نشان داده میشوند زیرا حرف بعدی در الفبای بعد از x و y است که معمولا نشاندهنده مختصات است.
تابع کارخانه عدد مرکب دو پارامتر عددی را میپذیرد. مورد اول نشاندهنده بخش واقعی است، در حالی که مورد دوم نشاندهنده بخش مجازی است که با حرف j به صورت تحتاللفظی که قبلا دیدید نشان داده میشود:
>>> complex(3, 2) == 3 + 2j
True
هر دو پارامتر اختیاری هستند، با مقادیر پیشفرض صفر، که تعریف اعداد مرکب بدون بخش مجازی یا هر دو بخش حقیقی و مجازی را کمتر ناخوشایند میسازد:
>>> complex(3) == 3 + 0j
True
>>> complex() == 0 + 0j
True
نسخه تک انتخابی میتواند در انتخاب نوع مفید باشد. به عنوان مثال، میتوانید یک مقدار غیر عددی مانند یک رشته حروف را برای بدست آوردن یک شی پیچیده مربوطه منتقل کنید. توجه داشته باشید که رشته نمیتواند هیچ فضای خالی داشته باشد:
>>> complex("3+2j")
(3+2j)
>>> complex("3 + 2j")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string
بعدا متوجه خواهید شد که چگونه کلاسهای خود را با این مکانیزم ریختهگری سازگار کنید. جالب است که وقتی عدد پیچیدهای را به عدد complex() تبدیل میکنید، همان مثال را به دست میآورید:
>>> z = complex(3, 2)
>>> z is complex(z)
True
این مساله با نحوه کار انواع دیگر اعداد در پایتون همخوانی دارد، چون همه آنها تغییر ناپذیر هستند. برای ساختن یک نسخه متمایز از یک عدد مرکب، باید تابع را با هر دو استدلال دوباره فراخوانی کنید یا متغیر دیگری را با عدد مرکب حرفی اعلام کنید:
>>> z = complex(3, 2)
>>> z is complex(3, 2)
False
زمانی که شما دو استدلال برای این تابع ارائه میدهید، آنها همیشه باید اعداد باشند، مانند int، شناور، یا پیچیده. در غیر این صورت، یک خطای زمان اجرا میگیرید. از نظر فنی، bool یک زیر کلاس از int است، بنابراین کار خواهد کرد:
>>> complex(False, True) # Booleans, same as complex(0, 1)
1j
>>> complex(3, 2) # Integers
(3+2j)
>>> complex(3.14, 2.71) # Floating-point numbers
(3.14+2.71j)
>>> complex("3", "2") # Strings
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: complex() can't take second arg if first is a string
وقتی که شما تابع complex() factory را با اعداد پیچیده به عنوان استدلال تامین میکنید، همه چیز به ظاهر عجیب و غریب تر میشود. با این حال، اگر شما تنها استدلال اول را ارائه دهید، مانند قبل رفتار خواهد کرد:
>>> complex(complex(3, 2))
(3+2j)
با این حال، زمانی که دو استدلال وجود دارند و حداقل یکی از آنها یک عدد پیچیده است، نتایجی به دست خواهید آورد که ممکن است در نگاه اول توضیح آنها دشوار باشد:
>>> complex(1, complex(3, 2))
(-1+3j)
>>> complex(complex(3, 2), 1)
(3+3j)
>>> complex(complex(3, 2), complex(3, 2))
(1+5j)
برای به دست آوردن پاسخها، بیایید نگاهی به مدارک عملکرد کارخانه یا اسناد و مدارک آنلاین بیندازیم، که توضیح میدهند وقتی پیچیده (واقعی، ساختگی) هستید چه اتفاقی در حال رخ دادن است:
یک عدد مرکب را با مقدار real + imag * 1j برگردانید یا یک رشته یا عدد را به عدد مرکب تبدیل کنید. (منبع)
در این توضیحات، real و imag نام آرگومانهای تابع هستند. آرگومان دوم در واحد j مجازی ضرب میشود و نتیجه به آرگومان اول اضافه میشود. نگران نباشید اگر هنوز هم معنی ندارد. زمانی که در مورد اعداد مرکب ریاضی خواندهاید، میتوانید به این بخش برگردید. قوانینی که در مورد آنها یاد خواهید گرفت این کار را ساده خواهند کرد.
چه زمانی میخواهید از عملکرد complex() factory به صورت تحتاللفظی استفاده کنید؟ بستگی دارد، اما فراخوانی تابع ممکن است زمانی که شما با دادههای پویا ایجاد شده سر و کار دارید راحتتر باشد، برای مثال.
آشنایی با اعداد مرکب پایتون
در ریاضیات، اعداد مرکب مجموعهای از اعداد حقیقی هستند، به این معنی که هر عدد حقیقی نیز یک عدد مرکب است که بخش مجازی آن برابر با صفر است. مدلهای پایتون این رابطه را از طریق مفهومی به نام برج عددی، که در PEP ۳۱۴۱ شرح داده شد، مدلسازی میکنند:
>>> import numbers
>>> issubclass(numbers.Real, numbers.Complex)
True
ماژول اعداد built-in سلسله مراتبی از انواع عددی را از طریق کلاسهای انتزاعی تعریف میکند که میتواند برای بررسی نوع و طبقهبندی اعداد مورد استفاده قرار گیرد. به عنوان مثال، برای تعیین اینکه آیا مقداری به مجموعه خاصی از اعداد تعلق دارد، می توانید isinstance () را روی آن فراخوانی کنید:
>>> isinstance(3.14, numbers.Complex)
True
>>> isinstance(3.14, numbers.Integral)
False
مقدار نقطه شناور ۳.۱۴ یک عدد حقیقی است که همچنین یک عدد پیچیده است اما یک عدد انتگرال نیست. توجه داشته باشید که شما نمیتوانید از انواع built-in به طور مستقیم در چنین آزمونی استفاده کنید:
>>> isinstance(3.14, complex)
False
تفاوت بین اعداد و اعداد پیچیده این است که آنها به شاخههای جداگانه در درخت سلسله مراتبی نوع عددی تعلق دارند و دومی یک کلاس پایه انتزاعی بدون هیچ گونه پیادهسازی است:
کلاسهای پایه انتزاعی، که در نمودار بالا با رنگ قرمز مشخص شدهاند، میتوانند با ثبت کلاسهای غیر مرتبط به عنوان زیر کلاسهای مجازی خود، مکانیزم بررسی وراثت منظم را دور بزنند. به همین دلیل به نظر میرسد که یک مقدار نقطه شناور در مثال نمونهای از اعداد Complex است اما پیچیده نیست.
دسترسی به بخشهای واقعی و مجازی
برای بدست آوردن قسمتهای واقعی و مجازی یک عدد مرکب در پایتون، میتوانید به ویژگیهای مربوطه .real و .imag متصل شوید:
>>> z = 3 + 2j
>>> z.real
3.0
>>> z.imag
2.0
هر دو ویژگی read-only هستند زیرا اعداد مرکب غیرقابل تغییر هستند، بنابراین تلاش برای تعیین مقدار جدید به هر یک از آنها ناموفق خواهد بود:
>>> z.real = 3.14
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
از آنجا که هر عدد در پایتون نوع خاصی از اعداد پیچیده است، ویژگیها و روشهای تعریف شده در اعداد.مجموعه نیز در همه انواع عددی، از جمله int و float در دسترس است:
>>> x = 42
>>> x.real
42
>>> x.imag
0
بخش مجازی چنین اعدادی همیشه صفر است.
محاسبه مزدوج یک عدد مرکب
اعداد مرکب پایتون تنها سه عضو عمومی دارند. به غیر از ویژگیهای .real و .imag ، آنها روش .conjugate () را نشان میدهند که نشانه قسمت مجازی را برمیگرداند:
>>> z = 3 + 2j
>>> z.conjugate()
(3-2j)
برای اعدادی که بخش مجازی آنها برابر با صفر است، هیچ اثری ندارد:
>>> x = 3.14
>>> x.conjugate()
3.14
این عمل معکوس خاص خود است، بنابراین با دوبار فراخوانی آن عدد اصلی که با آن شروع کردهاید بدست میآید:
>>> z.conjugate().conjugate() == z
True
گرچه ممکن است ارزش کمی داشته باشد، مزدوج مرکب دارای چند ویژگی محاسباتی مفید است که میتواند تقسیم دو عدد مرکب را با قلم و کاغذ، در میان موارد دیگر محاسبه کند.
محاسبات اعداد مرکب
از آنجا که Complex یک نوع داده بومی در پایتون است، میتوانید اعداد مرکب را به عبارات حسابی وصل کنید و بسیاری از توابع داخلی را روی آنها فراخوانی کنید. توابع پیشرفتهتر برای اعداد مرکب در ماژول cmath که بخشی از کتابخانه استاندارد است، تعریف شدهاند. در قسمت بعدی این آموزش مقدمهای در مورد آن خواهید دید.
در حال حاضر، به یاد آوردن یک قانون به شما این امکان را میدهد که دانش ابتدایی ریاضی خود را برای محاسبه عملیات پایه شامل اعداد مرکب به کار ببرید. قانونی که باید به یاد آوریم، تعریف واحد مجازی است که معادله زیر را برآورده می کند:
وقتی j را به عنوان یک عدد واقعی تصور میکنید درست به نظر نمیرسد، اما وحشت نکنید. اگر لحظهای آن را نادیده بگیرید و هر رخداد j2 را با -1 جایگزین کنید، در صورتی که یک ثابت باشد، آماده خواهید شد. بیایید ببینیم که چگونه کار می کند.
اضافه کردن
مجموع دو یا چند عدد مرکب برابر است با اضافه کردن جزء قطعات حقیقی و مجازی آنها:
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 + z2
(6+8j)
پیش از این، شما متوجه شدید که عبارات جبری متشکل از اعداد حقیقی و مجازی از قوانین استاندارد جبر پیروی میکنند. زمانی که آن را به صورت جبری بنویسید، میتوانید ویژگی توزیعی را اعمال کرده و فرمول را با فاکتورگیری و گروهبندی عبارات رایج ساده کنید:
پایتون به طور خودکار عملوند ها را به نوع داده پیچیده زمانی که شما مقادیر انواع عددی مرکب را اضافه میکنید، ارتقا میدهد:
>>> z = 2 + 3j
>>> z + 7 # Add complex to integer
(9+3j)
این همان تبدیل ضمنی از int به float است که شاید با آن بیشتر آشنا باشید.
تفریق
تفریق اعداد مرکب مشابه جمع کردن آنها است، که به این معنی است که شما میتوانید آن را به صورت element-wise نیز به کار ببرید:
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 - z2
(-2-2j)
با این حال، برخلاف مجموع، ترتیب عملوندها قابلتوجه است و نتایج متفاوتی را درست مانند اعداد واقعی به دست میدهد:
>>> z1 + z2 == z2 + z1
True
>>> z1 - z2 == z2 - z1
False
همچنین میتوانید از عملگر منهای unary (-) برای منفی کردن عدد مرکب استفاده کنید:
>>> z = 3 + 2j
>>> -z
(-3-2j)
این کار هم قسمتهای حقیقی و هم قسمتهای مجازی عدد مرکب را قرینه میکند.
ضرب
محصول دو یا چند عدد پیچیدهتر جالبتر میشود:
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 * z2
(-7+22j)
چگونه بر روی زمین یک عدد منفی از فقط اعداد مثبت به دست میآورید؟ برای پاسخ به این سوال، شما باید تعریف واحد مجازی را به یاد بیاورید و عبارت را به صورت بخشهای واقعی و مجازی بازنویسی کنید:
مشاهده کلیدی این است که j بار j j2 را می دهد، که می تواند با -1 جایگزین شود. این علامت یکی از جمعوندها را برعکس میکند، در حالی که بقیه قوانین دقیقا مثل قبل باقی میمانند.
تقسیم
تقسیم اعداد مرکب در اولین برخورد میتواند ترسناک به نظر برسد:
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 / z2
(0.5609756097560976+0.0487804878048781j)
باور کنید یا نه، شما میتوانید با استفاده از یک قلم و کاغذ نتیجه یکسانی به دست آورید! (خب، یک ماشینحساب ممکن است کمی از سردردها را کاهش دهد.) زمانی که هر دو عدد به شکل استاندارد خود بیان میشوند، ترفند ضرب صورت کسر و مخرج کسر با مزدوج آن است:
مخرج به مدول مربعی مقسومعلیه تبدیل میشود. بعدا درباره مدول اعداد مرکب بیشتر یاد خواهید گرفت. زمانی که به گرفتن فرمول ادامه میدهید، این چیزی است که به دست خواهید آورد:
توجه داشته باشید که اعداد مرکب از تقسیم خطی پشتیبانی نمیکنند، که به عنوان تقسیم صحیح نیز شناخته میشود:
>>> z1 // z2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.
>>> z1 // 3.14
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.
این مورد قبلاً در پایتون 2.x کار میکرد اما بعداً برای جلوگیری از ابهام حذف شد.
به توان رساندن
شما میتوانید اعداد مرکب را با استفاده از عملگر توان دودویی (**) یا built-in pow() افزایش دهید اما نه آنچه در ماژول ریاضی تعریف شده است، که فقط از مقادیر شناور پشتیبانی می کند:
>>> z = 3 + 2j
>>> z**2
(5+12j)
>>> pow(z, 2)
(5+12j)
>>> import math
>>> math.pow(z, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float
هم پایه و هم توان میتوانند از هر نوع عددی باشند، از جمله عدد صحیح، ممیز شناور، مجازی، یا مرکب:
>>> 2**z
(1.4676557979464138+7.86422192328995j)
>>> z**2
(5+12j)
>>> z**0.5
(1.8173540210239707+0.5502505227003375j)
>>> z**3j
(-0.13041489185767086-0.11115341486478239j)
>>> z**z
(-5.409738793917679-13.410442370412747j)
توان دستی اعداد پیچیده زمانی که به شکل استاندارد خود بیان میشوند، بسیار دشوار میشود. نوشتن دوباره عدد به شکل مثلثاتی و محاسبه توان با استفاده از برخی مثلثات پایه بسیار راحتتر است. اگر به ریاضیات علاقهمند هستید، فرمولDe Moivre را مطالعه کنید، که به شما امکان میدهد این کار را انجام دهید.
استفاده از اعداد مرکب پایتون به عنوان بردارهای دو بعدی
شما میتوانید اعداد مرکب را به صورت نقاط یا بردارها در صفحه اقلیدسی در سیستم مختصات دکارتی یا مستطیلی مجسم کنید:
محور X در صفحه مرکب که به عنوان صفحه Gauss یا نمودار Argand نیز شناخته میشود، بخش حقیقی عدد مرکب را نشان میدهد، در حالی که محور Y بخش مجازی آن را نشان میدهد.
این حقیقت منجر به یکی از جالبترین ویژگیهای نوع داده پیچیده در پایتون میشود، که پیادهسازی ابتدایی یک بردار دو بعدی رایگان را در بر میگیرد. در حالی که همه عملیات در هر دو مورد یکسان عمل نمیکنند، بردارها و اعداد پیچیده شباهتهای بسیاری دارند.
دریافت مختصات
مثلث برمودا یک منطقه افسانهای است که به خاطر پدیدههای فراطبیعی خود مشهور است و در طول نوک جنوبی فلوریدا، پورتوریکو و جزیره کوچک برمودا گسترده شدهاست. رئوس آن تقریبا توسط سه شهر اصلی که مختصات جغرافیایی آنها به شرح زیر است، تعیین میشوند:
1. Miami: 25° 45’ 42.054” N, 80° 11’ 30.438” W
2. San Juan: 18° 27’ 58.8” N, 66° 6’ 20.598” W
3. Hamilton: 32° 17’ 41.64” N, 64° 46’ 58.908” W
بعد از تبدیل این مختصات به اعشاری، شما دو عدد ممیز شناور برای هر شهر خواهید داشت. شما میتوانید از نوع دادههای پیچیده برای ذخیره جفتهای مرتب اعداد استفاده کنید. از آنجا که عرض جغرافیایی مختصات عمودی و طول جغرافیایی مختصات افقی است، بهتر است آنها را جابجا کنیم تا ترتیب سنتی مختصات دکارتی را دنبال کنیم:
miami_fl = complex(-80.191788, 25.761681)
san_juan = complex(-66.105721, 18.466333)
hamilton = complex(-64.78303, 32.2949)
مقادیر منفی طول جغرافیایی، نیمکره غربی را نشان میدهند، در حالی که مقادیر مثبت عرض جغرافیایی، نیمکره شمالی را نشان میدهند.
به یاد داشته باشید که اینها مختصات کروی هستند. برای اینکه آنها را به درستی بر روی یک صفحه تخت قرار دهید، باید انحنای زمین را در نظر بگیرید. یکی از اولین طرحهای نقشهای که در نقشه نگاری استفاده شد، طرح مرکاتور بود که به ملوانان کمک کرد تا کشتیها را هدایت کنند. اما بیایید همه این موارد را نادیده بگیریم و فرض کنیم که مقادیر در حال حاضر در سیستم مختصات مستطیلی بیان شدهاند.
زمانی که اعداد را در یک صفحه پیچیده رسم میکنید، تصویر سختی از مثلث برمودا خواهید داشت:
در مطالب همراه، یک Jupyter Notebook تعاملی پیدا خواهید کرد که مثلث برمودا را با استفاده از کتابخانه Matplotlib ترسیم میکند. برای دانلود کد منبع و مواد برای این برنامه آموزشی، روی لینک زیر کلیک کنید:
گرفتن نمونه کد: اینجا کلیک کنید تا کد نمونهای که برای یادگیری در مورد اعداد پیچیده در پایتون در این برنامه آموزشی استفاده خواهید کرد را به دست آورید.
اگر فراخوانی تابع complex() factory را دوست ندارید، می توانید یک نام مستعار نوع با نام مناسب تر ایجاد کنید یا از شکل حروف یک عدد مرکب برای ذخیره چند کلید استفاده کنید:
CityCoordinates = complex
miami_fl = CityCoordinates(-80.191788, 25.761681)
miami_fl = -80.191788 + 25.761681j
اگر لازم بود ویژگیهای بیشتری را در یک شهر جمع کنید، میتوانید از یک تاپل یا یک کلاس داده نام گذاری شده استفاده کنید یا یک کلاس سفارشی ایجاد کنید.
حساب کردن بزرگی
اندازه، که به عنوان مدول یا شعاع یک عدد مرکب نیز شناخته میشود، طول برداری است که آن را در صفحه مرکب نشان میدهد:
شما میتوانید آن را از روی قضیه فیثاغورث با گرفتن ریشه دوم مجموع مربع بخش حقیقی و مربع بخش مجازی محاسبه کنید:
شما فکر میکنید که پایتون به شما اجازه میدهد که طول چنین برداری را با حلقه داخلی محاسبه کنید، اما این طور نیست. برای به دست آوردن بزرگی یک عدد مرکب، شما باید یک تابع جهانی دیگر به نام abs () را فراخوانی کنید، که معمولا برای محاسبه مقدار مطلق یک عدد استفاده میشود:
>>> len(3 + 2j)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'complex' has no len()
>>> abs(3 + 2j)
3.605551275463989
این تابع علامت اعداد صحیح را حذف میکند، اما برای اعداد مرکب، اندازه یا طول بردار را بر میگرداند:
>>> abs(-42)
42
>>> z = 3 + 2j
>>> abs(z)
3.605551275463989
>>> from math import sqrt
>>> sqrt(z.real**2 + z.imag**2)
3.605551275463989
ممکن است از بخش قبلی به خاطر داشته باشید که یک عدد مرکب ضرب شده توسط مزدوج آن، مربع بزرگی خود را تولید میکند.
پیدا کردن فاصله بین دو نقطه
بیایید مرکز هندسی مثلث برمودا و فواصل آن را از سه شهری که مرزهای آن را تشکیل میدهند، پیدا کنیم. اول، شما باید تمام مختصات را جمع کرده و نتیجه را به تعداد آنها تقسیم کنید تا میانگین را به دست آورید:
geometric_center = sum([miami_fl, san_juan, hamilton]) / 3
این به شما یک نقطه واقع در اقیانوس اطلس، جایی در مثلث میدهد:
حال میتوانید بردارهای لنگر انداخته در شهرها را بسازید و به سمت مرکز هندسی مثلث هدایت کنید. بردارها با کم کردن منبع از نقطه هدف ساخته میشوند:
v1 = geometric_center - miami_fl
v2 = geometric_center - san_juan
v3 = geometric_center - hamilton
از آنجایی که شما اعداد مرکب را کم میکنید، هر بردار نیز یک عدد پیچیده است که از دو بخش تشکیل شدهاست. برای به دست آوردن فواصل، اندازه هر بردار را محاسبه کنید:
>>> abs(v1)
9.83488994681275
>>> abs(v2)
8.226809506084367
>>> abs(v3)
8.784732429678444
این طولهای بردار فواصل معنیداری را منعکس نمیکنند اما تقریبهای خوبی برای یک مثال اسباببازی مانند این هستند. برای نشان دادن نتایج دقیق در واحدهای محسوس، ابتدا باید مختصات را از کروی به مستطیلی تبدیل کنید و یا فاصله را با استفاده از روش دایره بزرگ محاسبه کنید.
انتقال، برعکس کردن، مقیاس گذاری و چرخش
ممکن است شما را اذیت کند که مثلث در ربع دوم سیستم مختصات دکارتی ظاهر میشود. بیایید آن را طوری حرکت دهیم که مرکز هندسی آن با مبدا هم تراز باشد. هر سه راس با طول بردار نشاندادهشده توسط مرکز هندسی اما در جهت مخالف ترجمه خواهند شد:
triangle = miami_fl, san_juan, hamilton
offset = -geometric_center
centered_triangle = [vertex + offset for vertex in triangle]
توجه داشته باشید که شما دو عدد پیچیده را با هم جمع میکنید، که جمع المان آنها را انجام میدهد. این یک تغییر شکل afine است زیرا شکل مثلث یا محل قرارگیری رأس آن را تغییر نمیدهد:
انعکاس آینه ای مثلث در اطراف محور حقیقی یا مجازی مستلزم وارونه سازی مولفه مربوطه در رأس آن است. به عنوان مثال، برای این که آن را به صورت افقی بچرخانید، باید از منفی بخش حقیقی استفاده کنید، که مربوط به جهت افقی است. برای این که آن را به صورت عمودی وارونه کنید، بخش منفی قسمت مجازی را در نظر خواهید گرفت:
flipped_horizontally = [complex(-v.real, v.imag) for v in centered_triangle]
flipped_vertically = [complex(v.real, -v.imag) for v in centered_triangle]
مورد آخر در واقع همان محاسبه مزدوج عدد مرکب است، بنابراین شما میتوانید .conjugate () را بر روی هر راس مستقیماً فراخوانی کنید تا کار سخت را برای شما انجام دهد:
flipped_vertically = [v.conjugate() for v in centered_triangle]
به طور طبیعی، هیچ چیزی برای جلوگیری از اعمال تقارن در هر جهت یا هر دو جهت به طور همزمان وجود ندارد. در چنین حالتی میتوانید از عملگر نامنفی در مقابل عدد مرکب برای برگرداندن بخشهای حقیقی و مجازی آن استفاده کنید:
flipped_in_both_directions = [-v for v in centered_triangle]
با استفاده از نوت بوک تعاملی Jupyter موجود در مواد قابل دانلود با ترکیبهای مختلف بازی کنید. در اینجا مثلث ظاهر میشود که وقتی آن را در امتداد هر دو محور قرار میدهید:
مقیاس گذاری شبیه ترجمه کردن است، اما به جای اضافه کردن یک آفست، شما میخواهید هر راس را در یک فاکتور ثابت ضرب کنید، که باید یک عدد واقعی باشد:
scaled_triangle = [1.5*vertex for vertex in centered_triangle]
انجام این کار منجر به ضرب هر دو مولفه از هر عدد مرکب در یک مقدار میشود. آن باید مثلث برمودا شما را بکشد و باعث شود در نمودار بزرگتر به نظر برسد:
از طرف دیگر ضرب رئوس مثلث در یک عدد مرکب دیگر، باعث چرخش آن در اطراف مبدأ سیستم مختصات میشود. این بسیار متفاوت از این است که شما به طور معمول چگونه بردارها را در یکدیگر ضرب میکنید. برای مثال، یک محصول نقطهای از دو بردار منجر به یک اسکالر خواهد شد، در حالی که محصول متقابل آنها یک بردار جدید را در فضای سهبعدی برمیگرداند، که عمود بر سطحی است که تعریف میکنند.
نکته: محصول دو عدد مرکب، تکثیر بردار را نشان نمیدهد. در عوض، به عنوان ضرب ماتریس در یک فضای بردار دو بعدی، با ۱ و j به عنوان پایه استاندارد تعریف میشود. ضرب (x1 + y1j) با (x2 + y2j) متناظر با ضرب ماتریس زیر است:
این ماتریس چرخش در سمت چپ است، که ریاضیات را به خوبی انجام میدهد.
زمانی که رئوس را در واحد فرضی ضرب کنید، مثلث ۹۰ درجه در خلاف جهت عقربههای ساعت میچرخد. اگر به تکرار آن ادامه دهید، در نهایت به جایی که شروع کردید خواهید رسید:
چگونه عدد مرکب خاصی را پیدا میکنید که عدد مرکب دیگری را با هر زاویه دلخواه دوران دهد وقتی که هر دو ضرب میشوند؟ اول، نگاهی به جدول زیر بیندازید، که چرخشهای متوالی را با زاویه ۹۰ درجه خلاصه میکند:
هنگامی که شما ضرب مکرر را با j برحسب نماهای عدد صحیح مثبت بیان میکنید، یک الگو ظاهر میشود. توجه کنید که چگونه بالا بردن واحد مجازی به توانهای بعدی باعث میشود که آن به طور مکرر از طریق همان مقادیر چرخه داشته باشد. شما میتوانید این را بر روی نماهای کسری برون یابی کنید و انتظار داشته باشید که آنها متناظر با زوایای میانی باشند.
به عنوان مثال نمای نیمه چرخش اول برابر با ۰.۵ است و زاویه ۴۵ درجه را نشان میدهد:
بنابراین، اگر میدانید که توان یک نشان دهنده زاویه درست و هر مقیاس متناسب با آن است، می توانید این فرمول عمومی را برای چرخشهای دلخواه استخراج کنید:
def rotate(z: complex, degrees: float) -> complex:
return z * 1j**(degrees/90)
توجه داشته باشید که چرخش وقتی طبیعیتر می شود که اعداد مرکب خود را در مختصات قطبی که قبلاً زاویه را توصیف میکنند بیان کنید. سپس میتوانید از شکل نمایی استفاده کنید تا محاسبات را سادهتر کنید.
در بخش بعد درباره آنها بیشتر یاد خواهید گرفت.
کاوش ماژول ریاضی برای اعداد مرکب: cmath
شما قبلا دیدهاید که برخی توابع توکار مانند abs () و pow () اعداد مرکب را میپذیرند، در حالی که برخی دیگر این کار را نمیکنند. به عنوان مثال، شما نمیتوانید یک عدد پیچیده را گرد کنید چون چنین عملیاتی معنی ندارد:
>>> round(3 + 2j)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type complex doesn't define __round__ method
بسیاری از توابع پیشرفته ریاضی مانند توابع مثلثاتی، هایپربولیک یا لگاریتمی در کتابخانه استاندارد موجود هستند. متاسفانه، حتی اگر همه چیز را در مورد ماژول ریاضی پایتون بدانید، به این دلیل که هیچ یک از کارکردهای آن اعداد پیچیده را پشتیبانی نمیکنند، کمکی نخواهد کرد. شما باید آن را با ماژول cmath ترکیب کنید، که توابع متناظر برای اعداد پیچیده را تعریف میکند.
ماژول cmath تمام ثابتهای شناور نقطه از ریاضی را دوباره تعریف میکند به طوری که بدون نیاز به وارد کردن هر دو ماژول در دسترس شما هستند:
>>> import math, cmath
>>> for name in "e", "pi", "tau", "nan", "inf":
... print(name, getattr(math, name) == getattr(cmath, name))
...
e True
pi True
tau True
nan False
inf True
توجه داشته باشید که nan یک ارزش خاص است که هرگز با هیچ چیز دیگر از جمله خودش برابر نیست! به همین دلیل است که در خروجی بالا تنها یک اشتباه میبینید. علاوه بر این، cmath دو همتای پیچیده برای NaN (نه یک عدد) و بینهایت، با هر دو دارای بخشهای حقیقی صفر فراهم میکند:
>>> from cmath import nanj, infj
>>> nanj.real, nanj.imag
(0.0, nan)
>>> infj.real, infj.imag
(0.0, inf)
در حدود نیمی از توابع در محاسبات مرکزی وجود دارند همانطور که در ماژول استاندارد ریاضی وجود دارد. بسیاری از آنها رفتار اصلی را تقلید میکنند، اما تعداد کمی از آنها منحصر به اعداد پیچیده هستند. آنها به شما اجازه میدهند تا تبدیل بین دو سیستم مختصاتی که در این بخش بررسی خواهید کرد را انجام دهید.
استخراج ریشه یک عدد مرکب
قضیه اساسی در جبر بیان میکند که یک چند جملهای درجه n با ضرایب مرکب دقیقا n ریشه مرکب دارد. این بسیار مهم است اگر در مورد آن فکر کنید، پس کمی به آن فکر کنید.
حال بیایید تابع درجهدوم x2 + ۱ را به عنوان مثال در نظر بگیریم. از لحاظ بصری، این سهمی محور X را قطع نمیکند زیرا یک واحد بالاتر از مبدا قرار دارد. تابع تشخیص منفی است که این مقدار را به صورت حسابی مشاهده میکند. در عین حال، این یک چند جملهای درجه دو است، بنابراین باید دو ریشه پیچیده داشته باشد، حتی اگر ریشههای واقعی نداشته باشد!
برای یافتن این ریشهها، میتوانید تابع را به صورت یک معادله درجه دو بازنویسی کنید، سپس ثابت را به سمت راست حرکت دهید و ریشه دوم هر دو طرف را بگیرید:
در حوزه اعداد حقیقی، ریشه مربع تنها برای مقادیر ورودی غیر منفی تعریف میشود. بنابراین، فراخوانی این تابع در پایتون یک استثنا را با یک پیغام خطای مناسب افزایش خواهد داد:
>>> import math
>>> math.sqrt(-1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error
با این حال، زمانی که شما با √-1 به عنوان یک عدد پیچیده برخورد میکنید و تابع مربوطه را از ماژول cmath فراخوانی میکنید، نتیجه معنی دارتری به دست خواهید آورد:
>>> import cmath
>>> cmath.sqrt(-1)
1j
این منطقی به نظر میرسد. به هر حال، فرم متوسط x2 = -1 معادله درجه دوم، تعریف اصلی واحد خیالی است. اما، یک دقیقه صبر کنید. ریشه پیچیده دیگر کجا رفت؟ ریشههای پیچیده چند جملهایهای با درجه بالاتر چطور؟
برای مثال، یک چند جملهای درجه چهار x4 + ۱، که میتواند به صورت معادله x4 = -۱ نوشته شود، این چهار ریشه پیچیده دارد:
- z0 = -√2/2 + √2/2j
- z1 = -√2/2 - √2/2j
- z2 = √2/2 + √2/2j
- z3 = √2/2 - √2/2j
بالا بردن هر ریشه به توان چهارم منجر به یک عدد پیچیده برابر با ۱-+ ۰ j یا یک عدد واقعی ۱-میشود:
>>> import cmath
>>> z0 = -cmath.sqrt(2)/2 + cmath.sqrt(2)/2*1j
>>> z0**4
(-1.0000000000000004-0j)
>>> (z0**4).real
-1.0000000000000004
شما متوجه خواهید شد که مقدار حاصل دقیقا -۱ نیست به دلیل خطای گرد کردن در حساب نقطه شناور. برای توضیح این موضوع، میتوانید هر زمان که لازم باشد بگویید که آیا دو عدد مرکب نزدیک به مقدار هستند یا خیر، cmath.isclose() را فراخوانی کنید:
>>> cmath.isclose(z0**4, -1)
True
متاسفانه، شما نمیتوانید ریشههای پیچیده دیگر با پایتون خالص را محاسبه کنید چون توان منظم همیشه یک راهحل میدهد:
>>> pow(-1, 1/4)
(0.7071067811865476+0.7071067811865475j)
این تنها یکی از ریشههای ذکر شده قبلی است. فرمول ریاضی برای یافتن همه ریشههای پیچیده از فرم مثلثاتی اعداد مرکب استفاده میکند:
در اصل r و φ مختصات قطبی عدد مرکب هستند، در حالی که n درجه چند جملهای است و k شاخص ریشه است که از صفر شروع میشود. خبر خوب این است که شما نیازی به محاسبه دقیق این ریشهها ندارید. سریعترین راه برای پیدا کردن آنها نصب یک کتابخانه شخص ثالث مانند NumPy و وارد کردن آن به پروژه شماست:
>>> import numpy as np
>>> np.roots([1, 0, 0, 0, 1]) # Coefficients of the polynomial x**4 + 1
array([-0.70710678+0.70710678j, -0.70710678-0.70710678j,
0.70710678+0.70710678j, 0.70710678-0.70710678j])
دانستن اشکال مختلف اعداد مرکب و سیستمهای مختصات آنها میتواند مفید باشد. همانطور که میبینید، به حل مشکلات عملی مانند یافتن ریشههای پیچیده کمک میکند. بنابراین، در بخش بعدی، جزئیات بیشتری را بررسی خواهید کرد.
تبدیل بین مختصات مستطیلی و قطبی
از نظر هندسی، میتوانید یک عدد پیچیده را دو برابر بررسی کنید. از یک طرف، این نقطهای است که فواصل افقی و عمودی آن از مبدا به طور منحصر به فردی موقعیت آن را مشخص میکند. اینها به عنوان مختصات مستطیلی شامل بخشهای حقیق و مجازی شناخته میشوند.
از طرف دیگر شما میتوانید همان نقطه را در مختصات قطبی توصیف کنید که به شما اجازه میدهد آن را به روشنی با دو فاصله پیدا کنید:
۱. فاصله شعاعی، طول شعاع اندازهگیری شده از مبدا است.
۲. فاصله زاویه ای، زاویه ای است که بین محور افقی و شعاع اندازه گیری میشود.
شعاع، که به عنوان مدول نیز شناخته میشود، مربوط به اندازه تعداد مرکب یا طول بردار است. این زاویه معمولا به عنوان فاز یا آرگومان یک عدد مرکب شناخته میشود. بهتر است هنگام کار با توابع مثلثاتی، زاویه را بر حسب رادیان بیان کنیم تا بر حسب درجه.
این یک تصویر از یک عدد پیچیده در هر دو سیستم مختصات است:
بنابراین، یک نقطه (۳، ۲) در سیستم مختصات دکارتی دارای شعاع تقریبی ۳.۶ و زاویه حدود ۳۳.۷ درجه یا تقریبا π روی ۵.۴ رادیان است.
تبدیل بین دو سیستم مختصات با تعدادی از توابع دفنشده در ماژول cmath ممکن میشود. به طور خاص، برای به دست آوردن مختصات قطبی یک عدد مرکب، باید آن را به cmat.polar () منتقل کنید:
>>> import cmath
>>> cmath.polar(3 + 2j)
(3.605551275463989, 0.5880026035475675)
آن یک تاپل را برمی گرداند، که در آن عنصر اول شعاع و عنصر دوم زاویه در رادیان است. توجه داشته باشید که شعاع همان مقدار بزرگی را دارد که میتوانید با فراخوانی abs () روی عدد مرکب خود محاسبه کنید. در مقابل، اگر شما تنها به گرفتن زاویه یک عدد مرکب علاقهمند بودید، میتوانید آن را cmat.phase () بنامید:
>>> z = 3 + 2j
>>> abs(z) # Magnitude is also the radial distance
3.605551275463989
>>> import cmath
>>> cmath.phase(3 + 2j)
0.5880026035475675
>>> cmath.polar(z) == (abs(z), cmath.phase(z))
True
زاویه را می توان با استفاده از مثلثات پایه به دست آورد چون بخش حقیقی، بخش مجازی و اندازه با هم یک مثلث راست را تشکیل میدهند:
شما میتوانید از توابع مثلثاتی معکوس، مانند arcsine، از ریاضی یا cmath استفاده کنید، اما مورد دوم مقادیر پیچیدهای را با قسمت مجازی برابر با صفر تولید میکند:
>>> z = 3 + 2j
>>> import math
>>> math.acos(z.real / abs(z))
0.5880026035475675
>>> math.asin(z.imag / abs(z))
0.5880026035475676
>>> math.atan(z.imag / z.real) # Prefer math.atan2(z.imag, z.real)
0.5880026035475675
>>> import cmath
>>> cmath.acos(z.real / abs(z))
(0.5880026035475675-0j)
یک جزء کوچک وجود دارد که باید هنگام استفاده از تابع arctangent مراقب آن باشید ، که باعث شد بسیاری از زبانهای برنامه نویسی یک برنامه جایگزین به نام atan2 () ایجاد کنند. محاسبه نسبت بین قسمت مجازی و واقعی گاهی اوقات میتواند یک تکینگی به علت تقسیم به صفر ایجاد کند. علاوه بر این، نشانههای فردی این دو مقدار در این فرآیند از دست میروند، که بیان زاویه را با قطعیت غیر ممکن میسازد:
>>> import math
>>> math.atan(1 / 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> math.atan2(1, 0)
1.5707963267948966
>>> math.atan(1 / 1) == math.atan(-1 / -1)
True
>>> math.atan2(1, 1) == math.atan2(-1, -1)
False
توجه داشته باشید که چگونه atan() نمیتواند دو نقطه مختلف واقع در ربعهای مخالف سیستم مختصات را تشخیص دهد. از سوی دیگر، atan2() انتظار دارد که دو استدلال به جای یک استدلال، علائم فردی را قبل از تقسیم یک به دیگری حفظ کند و از مشکلات دیگر نیز اجتناب کند.
برای کسب درجه به جای رادیان، میتوانید تبدیل لازم را دوباره با استفاده از مدول ریاضی انجام دهید:
>>> import math
>>> math.degrees(0.5880026035475675) # Radians to degrees
33.690067525979785
>>> math.radians(180) # Degrees to radians
3.141592653589793
معکوس کردن این فرآیند-یعنی تبدیل مختصات قطبی به مستطیلی-به کارکرد دیگری وابسته است. با این حال، شما نمیتوانید همان چند تایی را که از cmat.polar () از cmat.rect () دریافت کردهاید را رد کنید.
>>> cmath.rect(cmath.polar(3 + 2j))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: rect expected 2 arguments, got 1
ایده خوبی است که ابتدا تاپل را در هنگام انجام یک کار باز کنید و به آن عناصر نامهای توصیفی بیشتری بدهید. حالا میتوانید cmat.rect () را درست بنامید:
>>> radius, angle = cmath.polar(3 + 2j)
>>> cmath.rect(radius, angle)
(3+1.9999999999999996j)
ممکن است شما در طول مسیر با خطاهای گرد کردن مواجه شوید در حالی که پایتون محاسبات را انجام میدهد. در پشت صحنه، توابع مثلثاتی را برای بازیابی بخشهای واقعی و فرضی فرا میخواند:
>>> import math
>>> radius*(math.cos(angle) + math.sin(angle)*1j)
(3+1.9999999999999996j)
>>> import cmath
>>> radius*(cmath.cos(angle) + cmath.sin(angle)*1j)
(3+1.9999999999999996j)
نمایش اعداد مرکب به طور متفاوت
صرفنظر از سیستم مختصات، شما میتوانید همان عدد مرکب را در چند شکل معادل ریاضی بیان کنید:
- جبری (استاندارد)
- هندسی
- مثلثاتی
- نمایی
این لیست جامع نیست زیرا بازنماییهای بیشتری وجود دارند، مانند نمایش ماتریسی اعداد پیچیده.
داشتن انتخاب به شما این امکان را میدهد که راحتترین گزینه را برای مقابله با یک مشکل مشخص انتخاب کنید. برای مثال، شما به فرم نمایی برای محاسبه تبدیل فوریه گسسته در بخش بعدی نیاز دارید. استفاده از این شکل برای ضرب و تقسیم اعداد مرکب نیز مناسب است.
در اینجا یک تجزیه سریع از اشکال اعداد مرکب فردی و مختصات آنها آورده شدهاست:
شکل جبری هنگامی که اعداد مرکب را با استفاده از ادبیاتی آنها مشخص میکنید، بومی پایتون است. همچنین میتوانید آنها را به عنوان نقاط روی صفحه اقلیدسی در سیستمهای مختصات دکارتی یا قطبی ببینید. در حالی که نمایشهای جداگانهای برای شکل مثلثاتی یا نمایی در پایتون وجود ندارد، میتوانید بررسی کنید که آیا اصول ریاضی وجود دارند یا خیر.
برای مثال، اتصال در فرمول اویلر به شکل مثلثاتی آن را به شکل نمایی تبدیل خواهد کرد. یا می توانید exp () ماژول cmath را فراخوانی کنید یا ثابت e را به توان برسانید تا همان نتیجه را بدست آورید:
>>> import cmath
>>> algebraic = 3 + 2j
>>> geometric = complex(3, 2)
>>> radius, angle = cmath.polar(algebraic)
>>> trigonometric = radius * (cmath.cos(angle) + 1j*cmath.sin(angle))
>>> exponential = radius * cmath.exp(1j*angle)
>>> for number in algebraic, geometric, trigonometric, exponential:
... print(format(number, "g"))
...
3+2j
3+2j
3+2j
3+2j
تمام اشکال در واقع روشهای مختلفی برای رمز گذاری یک عدد هستند. با این حال، به دلیل خطاهای گرد کردن که ممکن است در این میان رخ دهند، نمیتوانید آنها را به طور مستقیم مقایسه کنید. از cmath.isclose برای مقایسه ایمن یا format() اعداد به رشتهها به درستی استفاده کنید. شما در بخش بعدی یاد خواهید گرفت که چطور چنین رشتههایی را قالببندی کنید.
توضیح اینکه چرا اشکال مختلف یک عدد مرکب برابر هستند نیاز به حساب دیفرانسیل و انتگرال دارد و فراتر از دامنه این برنامه آموزشی میرود. با این حال، اگر به ریاضی علاقهمند باشید، ارتباطات بین رشتههای مختلف ریاضی را خواهید یافت که توسط اعداد پیچیده نشان داده میشوند تا جذاب باشند.
جدا کردن یک عدد مرکب در پایتون
شما قبلا یک دسته از اعداد مرکب پایتون را یاد گرفتهاید و نمونههای اولیه را دیدهاید. با این حال، قبل از حرکت بیشتر، پوشش برخی موضوعات نهایی ارزشمند است. در این بخش، شما به مقایسه اعداد پیچیده، رشتههای قالببندی شده حاوی آنها، و غیره خواهید پرداخت.
تست کیفیت اعداد مرکب
از لحاظ ریاضی، دو عدد مرکب زمانی برابر هستند که مقادیر یکسانی بدون در نظر گرفتن سیستم مختصات اتخاذ شده داشته باشند. با این حال، تبدیل بین مختصات قطبی و مستطیلی معمولا باعث بروز خطاهای گرد کردن در پایتون میشود، بنابراین شما باید هنگام مقایسه آنها مراقب تفاوتهای کوچک باشید.
به عنوان مثال، زمانی که یک نقطه در یک دایره واحد را در نظر میگیرید که شعاع آن برابر با یک است و در ۶۰ درجه کج شدهاست، مثلثات به خوبی کار میکند و تبدیل را با قلم و کاغذ ساده میکند:
>>> import math, cmath
>>> z1 = cmath.rect(1, math.radians(60))
>>> z2 = complex(0.5, math.sqrt(3)/2)
>>> z1 == z2
False
>>> z1.real, z2.real
(0.5000000000000001, 0.5)
>>> z1.imag, z2.imag
(0.8660254037844386, 0.8660254037844386)
حتی اگر میدانید که z1 و z2 یک نقطه هستند، پایتون به دلیل خطاهای گرد کردن نمیتواند آن را تعیین کند. خوشبختانه، PEP ۴۸۵ توابع را برای برابری تقریبی تعریف میکند، که در ماژولهای ریاضی و ریاضی در دسترس هستند:
>>> math.isclose(z1.real, z2.real)
True
>>> cmath.isclose(z1, z2)
True
به یاد داشته باشید که همیشه هنگام مقایسه اعداد پیچیده از آنها استفاده کنید! اگر تحمل پیشفرض برای محاسبات شما به اندازه کافی خوب نباشد، میتوانید آن را با مشخص کردن آرگومانهای اضافی تغییر دهید.
مرتبسازی اعداد مرکب
اگر با تاپلها آشنا باشید، میدانید که پایتون میتواند آنها را مرتبسازی کند:
>>> planets = [
... (6, "saturn"),
... (4, "mars"),
... (1, "mercury"),
... (5, "jupiter"),
... (8, "neptune"),
... (3, "earth"),
... (7, "uranus"),
... (2, "venus"),
... ]
>>> from pprint import pprint
>>> pprint(sorted(planets))
[(1, 'mercury'),
(2, 'venus'),
(3, 'earth'),
(4, 'mars'),
(5, 'jupiter'),
(6, 'saturn'),
(7, 'uranus'),
(8, 'neptune')]
به طور پیشفرض، تاپلهای منفرد از چپ به راست مقایسه میشوند:
>>> (6, "saturn") < (4, "mars")
False
>>> (3, "earth") < (3, "moon")
True
در مورد اول، عدد ۶ بزرگتر از ۴ است، بنابراین نامهای سیاره اصلا در نظر گرفته نمیشوند. با این حال، آنها میتوانند به حل و فصل یک تساوی کمک کنند. با این حال، این مساله در مورد اعداد پیچیده صادق نیست، زیرا آنها رابطه ترتیب طبیعی را تعریف نمیکنند. به عنوان مثال، اگر سعی کنید دو عدد پیچیده را مقایسه کنید، یک خطا به دست خواهید آورد:
>>> (3 + 2j) < (2 + 3j)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'
خطای معیار: خطای معیار بین نمونههای «پیچیده» و «پیچیده» پشتیبانی نمیشود
آیا بعد مجازی باید وزن بیشتری نسبت به بعد واقعی داشته باشد؟ آیا بزرگی آنها باید مقایسه شود؟ بستگی به شما دارد و پاسخها متفاوت خواهند بود. از آنجا که نمیتوانید اعداد مرکب را به طور مستقیم مقایسه کنید، باید به پایتون بگویید که چگونه آنها را با مشخص کردن یک تابع کلید سفارشی، مانند abs () مرتب کند:
>>> cities = {
... complex(-64.78303, 32.2949): "Hamilton",
... complex(-66.105721, 18.466333): "San Juan",
... complex(-80.191788, 25.761681): "Miami"
... }
>>> for city in sorted(cities, key=abs, reverse=True):
... print(abs(city), cities[city])
...
84.22818453809096 Miami
72.38647347392259 Hamilton
68.63651945864338 San Juan
این اعداد مرکب را با بزرگی آنها به ترتیب نزولی مرتب میکند.
قالببندی اعداد پیچیده به عنوان رشته
هیچ کد فرمتی مختص اعداد مرکب وجود ندارد، اما شما میتوانید بخشهای واقعی و فرضی آنها را به طور جداگانه با استفاده از کدهای استاندارد برای اعداد نقطه شناور قالببندی کنید. در زیر چند تکنیک برای نشان دادن این موضوع پیدا خواهید کرد. برخی از آنها در واقع فرمت شما را هم برای قسمتهای واقعی و هم برای قسمتهای مجازی به کار میبرند.
نکته: قالببندی رشته میتواند به شما اجازه دهد تا خطای نمایش ممیز شناور را نادیده بگیرید و وانمود کنید که وجود ندارد:
>>> import cmath
>>> z = abs(3 + 2j) * cmath.exp(1j*cmath.phase(3 + 2j))
>>> str(z)
'(3+1.9999999999999996j)'
>>> format(z, "g")
'3+2j'
حرف «g» در این فرمت خاص برای فرمت کلی است، که شماره شما را به دقت درخواست میکند. دقت پیشفرض شش شکل قابلتوجه است.
بیایید عدد مرکب زیر را به عنوان مثال در نظر بگیریم و آن را با دو رقم اعشار در هر دو بخش قالببندی کنیم:
>>> z = pow(3 + 2j, 0.5)
>>> print(z)
(1.8173540210239707+0.5502505227003375j)
یک راه سریع برای انجام این کار یا فراخوانی format() با یک فرمت عددی خاص و یا با ایجاد یک f-string با فرمت مناسب است:
>>> format(z, ".2f")
'1.82+0.55j'
>>> f"{z:.2f}"
'1.82+0.55j'
برای مثال، اگر کنترل بیشتری میخواهید، اضافه کردن لایه اضافی در اطراف اپراتور بعلاوه، در این صورت f-string انتخاب بهتری خواهد بود:
>>> f"{z.real:.2f} + {z.imag:.2f}j"
'1.82 + 0.55j'
شما همچنین می توانید .format () را روی یک اشیا رشتهای فراخوانی کرده و آرگومانهای موقعیتی یا کلیدی را به آن منتقل کنید:
>>> "{0:.2f} + {0:.2f}j".format(z.real, z.imag)
'1.82 + 1.82j'
>>> "{re:.2f} + {im:.2f}j".format(re=z.real, im=z.imag)
'1.82 + 0.55j'
استدلالهای موقعیتی یک توالی از ارزشها را فراهم میکنند، در حالی که استدلالهای کلمات کلیدی به شما اجازه میدهند تا با نام به آنها اشاره کنید. به طور مشابه، شما میتوانید از عملگر پیمانه رشته (%) با یک تاپل یا یک فرهنگ لغت استفاده کنید:
>>> "%.2f + %.2fj" % (z.real, z.imag)
'1.82 + 0.55j'
>>> "%(re).2f + %(im).2fj" % {"re": z.real, "im": z.imag}
'1.82 + 0.55j'
با این حال، این کار از نحو جایگزین متفاوتی استفاده میکند و کمی قدیمی است.
ایجاد نوع دادههای پیچیده خودتان
مدل داده پایتون مجموعهای از روشهای خاص را تعریف میکند که شما میتوانید آنها را برای سازگار کردن کلاسهای خود با انواع داخلی خاص اجرا کنید. فرض کنید که شما با نقاط و بردارها کار میکنید و میخواهید زاویه بین دو بردار محدود را به دست آورید. شما میتوانید محصول نقطهای آنها را محاسبه کنید و کمی مثلثات انجام دهید. همچنین میتوانید از اعداد مرکب استفاده کنید.
بیایید ابتدا کلاسهای خود را تعریف کنیم:
from typing import NamedTuple
class Point(NamedTuple):
x: float
y: float
class Vector(NamedTuple):
start: Point
end: Point
یک نقطه مختصات x و y دارد، در حالی که یک بردار دو نقطه را به هم متصل میکند. شما ممکن است cMAT.phas e () را به خاطر داشته باشید که فاصله زاویهای یک عدد پیچیده را محاسبه میکند. حال، اگر با بردارهای خود به عنوان اعداد مرکب رفتار میکنید و مراحل آنها را میدانید، میتوانید آنها را کم کنید تا زاویه مورد نظر را بدست آورید.
برای اینکه پایتون نمونههای برداری را به عنوان اعداد مرکب تشخیص دهد ، باید .__complex__() را در بدنه کلاس تهیه کنید:
class Vector(NamedTuple):
start: Point
end: Point
def __complex__(self):
real = self.end.x - self.start.x
imag = self.end.y - self.start.y
return complex(real, imag)
کد داخلی همیشه باید نمونهای از نوع داده پیچیده را برگرداند، بنابراین به طور معمول یک عدد پیچیده جدید را از شی شما ایجاد میکند. در اینجا، شما نقاط اولیه و نهایی را کم میکنید تا جابجاییهای افقی و عمودی را به دست آورید، که به عنوان بخشهای واقعی و فرضی عمل میکنند. این روش هنگامی که شما complex() جهانی را در یک نمونه برداری فراخوانی میکنید از نماینده تفویض اجرا میشود:
>>> vector = Vector(Point(-2, -1), Point(1, 1))
>>> complex(vector)
(3+2j)
در بعضی موارد، مجبور نیستید این نوع انتخاب نوع را خود انجام دهید. بیایید یک مثال در عمل ببینیم:
>>> v1 = Vector(Point(-2, -1), Point(1, 1))
>>> v2 = Vector(Point(10, -4), Point(8, -1))
>>> import math, cmath
>>> math.degrees(cmath.phase(v2) - cmath.phase(v1))
90.0
شما دو بردار دارید که توسط چهار نقطه متمایز شناسایی شدهاند. سپس، شما آنها را مستقیما به cmat.phase () منتقل میکنید، که تبدیل را به یک عدد مرکب برای شما انجام میدهد و فاز را باز میگرداند. تفاوت فاز، زاویه بین دو بردار است.
آیا این زیبا نبود؟ شما خودتان را از تایپ کردن بسیاری از کدهای مستعد خطا با استفاده از اعداد مرکب و کمی جادوی پایتون حفظ کردهاید.
محاسبه تبدیل فوریه گسسته با اعداد مرکب
در حالی که شما میتوانید از اعداد حقیقی برای محاسبه ضرایب سینوسی و کسینوسی فرکانسهای تابع تناوبی با تبدیل فوریه استفاده کنید، معمولا راحتتر است که تنها با یک ضریب مرکب در هر فرکانس سر و کار داشته باشید. تبدیل فوریه گسسته در حوزه مرکب با فرمول زیر داده میشود:
برای هر فرکانس bin k، همبستگی سیگنال و یک موج سینوسی خاص که به صورت یک عدد مرکب به صورت نمایی بیان میشود را اندازهگیری میکند. (متشکرم، لئونهارد اویلر!) فرکانس زاویهای موج را می توان با ضرب زاویه گرد، که شعاع ۲ π است، با k روی تعداد نمونههای گسسته محاسبه کرد:
کدگذاری این مورد در پایتون زمانی که از نوع داده پیچیده استفاده میکنید، کاملا تمیز به نظر میرسد:
from cmath import pi, exp
def discrete_fourier_transform(x, k):
omega = 2 * pi * k / (N := len(x))
return sum(x[n] * exp(-1j * omega * n) for n in range(N))
این تابع یک نسخه حرفی از فرمولهای بالا است. حالا شما میتوانید یک تحلیل فرکانسی بر روی صدایی که از یک فایل صوتی با استفاده از ماژول موج پایتون بارگذاری میکنید و یا از نو ترکیب میکنید، اجرا کنید. یکی از نوت بوک های Jupyter که این برنامه آموزشی را همراهی میکند به شما اجازه میدهد تا با ترکیب صدا و تحلیل تعاملی بازی کنید.
برای ترسیم طیف فرکانس با Matplotlib، باید فرکانس نمونهبرداری را بدانید که تفکیک بین فرکانس شما و همچنین محدوده Nyquist را تعیین میکند:
import matplotlib.pyplot as plt
def plot_frequency_spectrum(
samples,
samples_per_second,
min_frequency=0,
max_frequency=None,
):
num_bins = len(samples) // 2
nyquist_frequency = samples_per_second // 2
magnitudes = []
for k in range(num_bins):
magnitudes.append(abs(discrete_fourier_transform(samples, k)))
# Normalize magnitudes
magnitudes = [m / max(magnitudes) for m in magnitudes]
# Calculate frequency bins
bin_resolution = samples_per_second / len(samples)
frequency_bins = [k * bin_resolution for k in range(num_bins)]
plt.xlim(min_frequency, max_frequency or nyquist_frequency)
plt.bar(frequency_bins, magnitudes, width=bin_resolution)
تعداد سطلهای فرکانس در طیف برابر با نیمی از نمونهها است ، در حالی که فرکانس Nyquist بالاترین فرکانس اندازهگیری را محدود میکند. این تبدیل عدد پیچیدهای را برمی گرداند که بزرگی آن با دامنه موج سینوسی در فرکانس دادهشده متناظر است، در حالی که زاویه آن فاز است.
توجه: برای به دست آوردن مقادیر دامنه صحیح، شما باید تعداد را دو برابر کرده و مقدار حاصل را به تعداد نمونه تقسیم کنید. از سوی دیگر، اگر تنها به هیستوگرام فرکانس توجه داشته باشید، آنگاه میتوانید بزرگی را با مجموع آنها یا حداکثر فرکانس نرمال کنید.
در اینجا یک نمودار فرکانس نمونه از یک موج صوتی شامل سه تن-۴۴۰ هرتز، ۱.۵ کیلو هرتز، و ۵ کیلو هرتز-با دامنههای برابر آورده شدهاست:
توجه داشته باشید که این یک مثال کاملا آکادمیک است زیرا محاسبه تبدیل فوریه گسسته با تکرارهای تودرتو دارای پیچیدگی زمانی O (n2) است که آن را در عمل غیرقابلاستفاده میسازد. برای کاربردهای زندگی واقعی، شما میخواهید از الگوریتم تبدیل فوریه سریع (FFT) که به بهترین شکل در کتابخانه C اجرا میشود، مانند FFT در SciPy استفاده کنید.
نتیجهگیری
سهولت استفاده از اعداد مرکب در پایتون آنها را به یک ابزار جالب و عملی تبدیل کردهاست. شما بردارهای دو بعدی را دیدید که عملا به صورت رایگان اجرا شدند، و شما قادر به تجزیه و تحلیل فرکانسهای صدا به لطف آنها بودید. اعداد مرکب به شما اجازه میدهند تا به طور زیبایی فرمولهای ریاضی را در کد بدون وجود کدهای تکراری در مسیر، بیان کنید.
در این برنامه آموزشی یاد گرفتید که چگونه:
- اعداد مرکب را با حروف در پایتون تعریف کنید
- نمایش مجدد اعداد مرکب در مختصات مستطیلی و قطبی
- از اعداد مرکب در عبارات ریاضی استفاده کنید
- از مزیت ماژول ساختهشده در محاسبات ریاضی استفاده کنید.
- تبدیل فرمولهای ریاضی مستقیم به کد پایتون
تجربه شما با اعداد مرکب پایتون تا کنون چه بودهاست؟ آیا شما هرگز توسط آنها مرعوب شدهاید؟ فکر میکنید آنها به شما اجازه حل کردن چه مشکلات جالب دیگری را میدهند؟
شما میتوانید روی لینک زیر کلیک کنید تا کد منبع کامل برای این برنامه آموزشی به دست آورید:
گرفتن نمونه کد: اینجا کلیک کنید تا کد نمونهای که برای یادگیری در مورد اعداد پیچیده در پایتون در این برنامه آموزشی استفاده خواهید کرد را به دست آورید.
این متن با استفاده از ربات ترجمه مقالات علم داده ترجمه شده و به صورت محدود مورد بازبینی انسانی قرار گرفته است.در نتیجه میتواند دارای برخی اشکالات ترجمه باشد.
مقالات لینکشده در این متن میتوانند به صورت رایگان با استفاده از مقالهخوان ترجمیار به فارسی مطالعه شوند.
مطلبی دیگر از این انتشارات
۱۲۰ سال از بازیهای المپیک
مطلبی دیگر از این انتشارات
آمازون به کارمندان هشدار میدهد که مراقب ChatGPT باشند
مطلبی دیگر از این انتشارات
۴ عادت ساده که شما را در محل کار متمرکزتر و سازندهتر میکند