رفتن به مطلب

تمامی فعالیت ها

این جریان به طور خودکار بروزرسانی می شود

  1. هفته گذشته
  2. sina
    sina عکس نمایه خود را تغییر داد
  3. sina
    سندروم ایمپاستر یا همون حس جعل هویت، یه موضوع خیلی رایج بین برنامه‌نویس‌ها و مهندس‌های نرم‌افزاره که شاید خودمون هم گاهی نفهمیم داریم باهاش دست‌وپنجه نرم می‌کنیم. فکرش رو بکن: ساعت‌ها کد زدی، پروژه رو به موقع تحویل دادی و حتی تونستی باگ‌های پیچیده رو حل کنی، ولی هنوز یه صدای کوچیک توی سرت می‌گه: «تو فقط شانسی این کار رو کردی، بالاخره یه روز همه می‌فهمن که تو به اندازه کافی خوب نیستی.» اگه این حس برات آشناست، بدون که تنها نیستی. توی این مقاله قراره با هم نگاه عمیق‌تری به سندروم ایمپاستر بندازیم، ببینیم چرا توی دنیای برنامه‌نویسی اینقدر شایعه و چطور می‌تونیم باهاش کنار بیایم یا حتی ازش به نفع خودمون استفاده کنیم. سندروم ایمپاستر چیه و چرا برنامه‌نویس‌ها رو هدف گرفته؟سندروم ایمپاستر یه حس روان‌شناختیه که باعث می‌شه آدما موفقیت‌هاشون رو به شانس، زمان‌بندی خوب یا حتی اشتباه بقیه نسبت بدن، نه به توانایی و تلاش خودشون. حالا چرا توی دنیای برنامه‌نویسی و مهندسی نرم‌افزار اینقدر این حس قویه؟ یه دلیلش اینه که این حوزه همیشه در حال تغییره. یه روز داری با یه فریم‌ورک جدید کار می‌کنی، فردا یه تکنولوژی دیگه میاد که انگار همه‌چیز رو از نو باید یاد بگیری. این سرعت تغییرات باعث می‌شه خیلی از برنامه‌نویس‌ها فکر کنن که همیشه یه پله عقب‌تر از بقیه‌ان. یه چیز دیگه هم هست: فرهنگ مقایسه توی این صنعت. توی شبکه‌های اجتماعی مثل توییتر یا لینکدین، مدام می‌بینیم که فلان برنامه‌نویس یه پروژه خفن رو توی دو روز تموم کرده یا یه نفر دیگه توی ۲۵ سالگی مدیر فنی یه شرکت بزرگ شده. این مقایسه‌ها باعث می‌شه خودمون رو زیر سؤال ببریم و فکر کنیم که «من چرا هنوز اونجا نیستم؟» نشانه‌های سندروم ایمپاستر توی زندگی یه برنامه‌نویسشاید برات پیش اومده که یه پروژه رو با موفقیت تموم کنی، ولی به جای اینکه به خودت افتخار کنی، بشینی فکر کنی که «اگه بیشتر وقت گذاشته بودم، بهتر نمی‌شد؟» یا مثلاً موقع کد زدن، مدام از خودت بپرسی که «اگه همکارم این کد رو ببینه، فکر نمی‌کنه خیلی مبتدی‌ام؟» اینا همشون نشونه‌های سندروم ایمپاستره. بیایم چند تا از این نشانه‌ها رو با هم مرور کنیم: ترس از لو رفتن: همیشه فکر می‌کنی که یه روز بقیه می‌فهمن تو اون آدم باهوشی که فکر می‌کنن نیستی. کم اهمیت دونستن موفقیت‌ها: مثلاً می‌گی «این پروژه که چیزی نبود، هرکی دیگه هم بود می‌تونست انجامش بده.» فشار برای کامل بودن: اگه کدت ۱۰۰٪ بی‌نقص نباشه، حس می‌کنی شکست خوردی. خودت رو با بقیه مقایسه می‌کنی: مدام خودت رو با برنامه‌نویس‌های دیگه که به نظرت موفق‌ترن مقایسه می‌کنی و حس می‌کنی به گرد پاشون هم نمی‌رسی. چرا برنامه‌نویس‌ها بیشتر درگیر این حس می‌شن؟یه لحظه فکر کن به محیط کار یه برنامه‌نویس: ددلاین‌های فشرده، پروژه‌های پیچیده و انتظاراتی که گاهی از واقعیت خیلی دورن. توی این موقعیت‌ها، حتی اگه کارمون رو خوب انجام بدیم، ممکنه فکر کنیم که فقط داریم ادای یه برنامه‌نویس حرفه‌ای رو درمی‌آریم. یه دلیل دیگه هم اینه که توی برنامه‌نویسی، همیشه یه راه حل «بهتر» وجود داره. مثلاً کدت کار می‌کنه، ولی یه نفر می‌گه «اگه از این الگوریتم استفاده کرده بودی، بهینه‌تر بود.» این جور بازخوردها، حتی اگه سازنده باشن، می‌تونن حس ناکافی بودن رو تقویت کنن. یه موضوع دیگه هم هست: خیلی از برنامه‌نویس‌ها خودشون یاد گرفتن که چطور کد بزنن. این یعنی ممکنه مدرک رسمی نداشته باشن و همین باعث بشه فکر کنن که از بقیه «کمترن». در حالی که توی دنیای واقعی، مهارت و تجربه خیلی بیشتر از یه تکه کاغذ ارزش داره. چطور با سندروم ایمپاستر کنار بیایم؟حالا که فهمیدیم این حس از کجا میاد، بیایم ببینیم چطور می‌تونیم باهاش روبه‌رو بشیم. خبر خوب اینه که سندروم ایمپاستر یه چیز قابل مدیریته و حتی می‌تونه به یه نیروی مثبت تبدیل بشه. این چند تا راهکار رو امتحان کن: موفقیت‌هات رو ثبت کن: یه دفترچه داشته باش و هر بار که یه باگ رو حل کردی، یه پروژه رو تموم کردی یا حتی یه خط کد خوب نوشتی، یادداشتش کن. این کار باعث می‌شه به مرور ببینی که چقدر توانایی داری. با بقیه حرف بزن: یه بار با همکارات یا دوستات که برنامه‌نویس هستن راجع به این حس صحبت کن. می‌بینی که خیلی‌ها همین حس رو دارن و تو تنها نیستی. کمال‌گرایی رو بذار کنار: قبول کن که هیچ کدی توی دنیا کامل نیست. مهم اینه که کار کنه و مشکل رو حل کنه. یادگیری رو بپذیر: به جای اینکه از تغییرات سریع تکنولوژی بترسی، بهش به چشم یه فرصت نگاه کن. هر چی بیشتر یاد بگیری، اعتماد به نفست بیشتر می‌شه. از مقایسه دست بکش: به جای اینکه خودت رو با بقیه مقایسه کنی، پیشرفت خودت رو نسبت به گذشته‌ات بسنج. مثلاً ببین پارسال کجا بودی و الان کجایی. وقتی سندروم ایمپاستر می‌تونه مفید باشهباور کن یا نه، این حس گاهی می‌تونه به نفعمون باشه. مثلاً همین که همیشه دنبال بهتر شدن هستی و نمی‌خوای توی کارات کم بذاری، خودش یه نقطه قوته. خیلی از برنامه‌نویس‌های موفق می‌گن که این حس باعث شده بیشتر مطالعه کنن، کدهای بهتری بنویسن و توی کارشون پیشرفت کنن. فقط کافیه نذاری این حس کنترلت کنه و به جاش ازش به عنوان یه انگیزه استفاده کنی. حرف آخر: تو به اندازه کافی خوبی!سندروم ایمپاستر یه چیزیه که خیلی از برنامه‌نویس‌ها و مهندس‌های نرم‌افزار باهاش روبه‌رو می‌شن، ولی قرار نیست همیشه باهات بمونه. دفعه بعدی که حس کردی به اندازه کافی خوب نیستی، یه نفس عمیق بکش و به خودت یادآوری کن که همین که داری کد می‌زنی، پروژه تحویل می‌دی و هر روز یه چیز جدید یاد می‌گیری، یعنی داری راه رو درست می‌ری. دنیای برنامه‌نویسی جای آدمای باهوش و باپشتکاره، و تو قطعاً یکی از اونایی.
  4. sina
    تقویم شمسی به‌عنوان یک استاندارد رسمی در ایران و برخی کشورهای دیگر، جایگاه ویژه‌ای در کاربردهای روزمره و حرفه‌ای دارد. با این حال، در اکوسیستم Rust، ابزارهای محدودی برای پشتیبانی از این تقویم وجود داشت. کتابخانه‌های موجود یا به زبان‌های دیگری توسعه یافته بودند که با نیازهای بهینه‌سازی Rust همخوانی نداشتند، یا فاقد به‌روزرسانی و پشتیبانی کافی بودند به همین دلیل تصمیم گرفتم برای رفع نیاز خودم و سایر برنامه نویسان این پکیج رو بنویسم و منتشر کنم قابلیت‌هاتبدیل دوطرفه تاریخ: امکان تبدیل تاریخ میلادی به شمسی و از شمسی به میلادی. تشخیص سال کبیسه: تابع is_persian_leap_year برای شناسایی سال‌های کبیسه شمسی. محاسبه روز هفته: تابع weekday که نام روز هفته را به زبان فارسی بازمی‌گرداند. سبکی و کارایی: طراحی شده با حداقل وابستگی‌ها و بهره‌مندی از کتابخانه chrono. منبع‌باز بودن: کد منبع در دسترس عموم قرار دارد و امکان مشارکت در توسعه آن فراهم است. نحوه عملکردParsidate از کتابخانه استاندارد chrono برای مدیریت تاریخ‌های میلادی استفاده می‌کند و با پیاده‌سازی الگوریتم‌های معتبر تبدیل تقویم، تاریخ‌ها را به‌صورت دقیق به شمسی تبدیل می‌نماید. نمونه‌ای از استفاده از این کتابخانه به شرح زیر است: use chrono::NaiveDate; use parsidate::ParsiDate; fn main() { // تبدیل تاریخ میلادی به شمسی let gregorian_date = NaiveDate::from_ymd_opt(2025, 3, 28).unwrap(); let persian_date = ParsiDate::from_gregorian(gregorian_date).unwrap(); println!("تاریخ شمسی: {}", persian_date.to_string()); // خروجی: 1404/01/08 println!("روز هفته: {}", persian_date.weekday()); // خروجی: جمعه // تبدیل تاریخ شمسی به میلادی let persian_date = ParsiDate { year: 1404, month: 1, day: 8 }; let gregorian_date = persian_date.to_gregorian().unwrap(); println!("تاریخ میلادی: {}", gregorian_date); // خروجی: 2025-03-28 }مشخصات فنیوابستگی‌ها: تنها وابستگی این کتابخانه، chrono است که برای مدیریت تاریخ‌های میلادی به کار می‌رود. الگوریتم تبدیل: مبتنی بر فرمول‌های استاندارد تبدیل تقویم میلادی به شمسی، با پشتیبانی از محاسبات سال‌های کبیسه. رابط برنامه‌نویسی (API): توابعی نظیر from_gregorian و to_gregorian با استفاده از نوع بازگشتی Result، مدیریت خطاها را به‌صورت ایمن تضمین می‌کنند. نحوه نصب و استفادهبرای افزودن Parsidate به پروژه خود، کافی است خط زیر را به فایل Cargo.toml اضافه کنید: [dependencies] parsidate = "0.1.1" # نسخه جاری یا آخرین نسخه chrono = "0.4"مثال و جزییات بیشتر را در crates.io قرار داده ام.
  5. جدیدا
  6. sina
    SubAI، یک وب‌اپلیکیشن برای ترجمه خودکار فایل‌های زیرنویس (SRT) با استفاده از API Gemini است. هدف این پروژه، ارائه ابزاری ساده و کاربردی برای ترجمه زیرنویس‌ها به زبان‌های مختلف و مدیریت فایل‌های ترجمه‌شده است ویژگی‌های اصلیترجمه خودکار زیرنویس‌ها با انتخاب زبان مقصد. امکان مشاهده، جستجو و دانلود فایل‌های ترجمه‌شده. تنظیمات پیشرفته شامل کلید API، مدل ترجمه و کش. امنیت تضمین‌شده با CSRF و فیلتر ورودی‌ها. تکنولوژی‌های مورد استفادهPHP: برای بک‌اند و منطق اصلی. MySQL: برای ذخیره‌سازی داده‌ها. Gemini API: برای پردازش ترجمه. Bootstrap: برای رابط کاربری. JavaScript: برای تعاملات کاربر. نحوه کاردریافت Gemini API و وارد کردن آن در تنظیمات. فایل SRT را آپلود و زبان مقصد را انتخاب کنید. ترجمه با نمایش پیشرفت انجام می‌شود. فایل ترجمه‌شده را دانلود یا در بخش "Translated Files" مدیریت کنید. کاربردمناسب علاقه‌مندان به فیلم و سریال برای ترجمه زیرنویس. ابزار کمکی برای مترجمان حرفه‌ای. برنامه‌های آیندهپشتیبانی از فرمت‌های دیگر (مثل VTT). افزودن سایر مدل ها برای استفاده در ترجمه دسترسی و اجرابرنامه از طریق (این لینک) قابل دسترسی میباشد. کلید API Gemini نیز مورد نیاز است.
  7. sina
    اگه برنامه‌نویس باشی و با Rust کار کرده باشی، حتما شنیدی که این زبان چقدر رو سرعت و امنیت تمرکز داره. از اون طرف، C هم که یه زبان قدیمی و قدرتمنده و هنوز توی خیلی از پروژه‌ها، مخصوصا پروژه‌های سیستمی، حرف اول رو می‌زنه. حالا فکر کن بخوای این دو تا رو با هم ترکیب کنی! هم قدرت و انعطاف C رو داشته باشی، هم ایمنی و مدرن بودن Rust رو. توی این مطلب می‌خوام بهت نشون بدم چطور می‌تونی Rust و C رو به هم وصل کنی و کدات رو بین این دو تا جابجا کنی. چرا اصلا Rust و C رو به هم وصل کنیم؟قبل از اینکه بریم سراغ کد و جزییات، بذار یه لحظه ببینیم چرا این کار منطقیه. Rust یه زبان نسبتا جدیده که خیلی از مشکلات C مثل مدیریت دستی حافظه و خطاهای اشاره‌گر (pointer errors) رو حل کرده. اما خب، C یه اکوسیستم عظیم داره؛ کتابخونه‌هایی مثل POSIX یا حتی کدهای قدیمی پروژه‌ات که نمی‌خوای از صفر با Rust بازنویسی‌شون کنی. اینجا اتصال این دو زبان به کار میاد. می‌تونی از کتابخونه‌های C توی Rust استفاده کنی یا برعکس، کدهای Rust رو توی پروژه‌های C وارد کنی. مفاهیم اولیه: FFI چیه؟برای اینکه Rust و C با هم حرف بزنن، از یه چیزی به اسم FFI استفاده می‌کنیم. FFI مخفف "Foreign Function Interface" هست و به زبون ساده، یه جور پل ارتباطی بین زبون‌های مختلفه. توی این مورد، FFI به Rust اجازه می‌ده توابع C رو فراخوانی کنه و برعکس. اما این کار یه سری اصول داره که باید رعایت کنی، چون Rust و C توی مدیریت حافظه و ساختار داده‌ها خیلی فرق دارن. قدم اول: یه تابع C بنویسبیا با یه مثال ساده شروع کنیم. فرض کن توی C یه تابع داری که دو تا عدد رو می‌گیره و جمع‌شون می‌کنه: // math.c int add(int a, int b) { return a + b; }برای اینکه Rust بتونه این تابع رو ببینه، باید یه فایل هدر (header) هم بسازی: // math.h #ifndef MATH_H #define MATH_H int add(int a, int b); #endifحالا این فایل C رو کامپایل می‌کنیم تا یه کتابخونه استاتیک بسازیم: gcc -c math.c -o math.o ar rcs libmath.a math.oتا اینجا یه کتابخونه به اسم libmath.a داریم که قراره توی Rust ازش استفاده کنیم. قدم دوم: اتصال به Rustتوی پروژه Rust، باید به کامپایلر بگی که این کتابخونه خارجی رو لینک کنه. برای این کار از build.rs استفاده می‌کنیم. اگه پروژه‌ات هنوز فایل build.rs نداره، توی ریشه پروژه یه فایل با این اسم بساز و این کد رو توش بذار: // build.rs fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-link-lib=math"); println!("cargo:rustc-link-search=native=."); }این کد به Rust می‌گه که کتابخونه libmath.a رو پیدا کنه و به پروژه لینک کنه. یادت باشه فایل libmath.a رو توی همون دایرکتوری پروژه‌ات کپی کنی. قدم سوم: تعریف تابع در Rustحالا باید به Rust بگیم که تابع add توی C چه شکلیه. این کار رو با استفاده از بلاک extern "C" انجام می‌دیم. توی فایل main.rs اینجوری می‌نویسی: // main.rs extern "C" { fn add(a: i32, b: i32) -> i32; } fn main() { unsafe { let result = add(5, 3); println!("Result: {}", result); } }ری می‌کنه که مسئولیت هر مشکلی گردن خودته! اجرا و تستحالا کافیه پروژه رو با cargo run اجرا کنی. اگه همه چیز درست پیش بره، خروجی باید این باشه: Result: 8تبریک! تونستی یه تابع C رو توی Rust فراخوانی کنی. برعکسش چطوره؟ Rust به Cحالا فرض کن بخوای یه تابع توی Rust بنویسی و توی C ازش استفاده کنی. بیایم یه مثال بزنیم. توی Rust یه تابع می‌سازیم که یه رشته رو می‌گیره و طولش رو برمی‌گردونه: // lib.rs #[no_mangle] pub extern "C" fn string_length(s: *const i8) -> i32 { unsafe { let c_str = std::ffi::CStr::from_ptr(s); c_str.to_bytes().len() as i32 } }#[no_mangle]به Rust می‌گه اسم تابع رو تغییر نده تا C بتونه پیداش کنه. حالا این پروژه رو به صورت کتابخونه کامپایل می‌کنیم: cargo build --releaseفایل librust.a توی پوشه target/release ساخته می‌شه. توی C اینجوری ازش استفاده می‌کنیم: // main.c #include <stdio.h> #include <stdint.h> extern int32_t string_length(const char* s); int main() { const char* text = "Hello from Rust!"; int32_t len = string_length(text); printf("Length: %d\n", len); return 0; }کامپایلش می‌کنیم: gcc -L ./target/release -lrust main.c -o testاگه اجرا کنی، خروجی می‌شه: Length: 16نکات مهم و چالش‌هااتصال Rust و C خیلی هم ساده نیست. باید حواست به مدیریت حافظه باشه؛ مثلا اگه توی C حافظه تخصیص دادی، Rust انتظار نداره خودش آزادش کنه. یا برعکس، اگه Rust یه چیزی رو آزاد کرد، C نباید دوباره بخواد باهاش کار کنه. یه ابزار خوب برای این کار، استفاده از کتابخونه‌هایی مثل cbindgen و bindgen هست که فایل‌های هدر و تعاریف رو خودکار تولید می‌کنن و کار رو راحت‌تر می‌کنن. جمع‌بندیوصل کردن Rust به C یه راه عالیه برای اینکه از بهترین‌های هر دو دنیا استفاده کنی. با FFI و چند خط کد، می‌تونی پروژه‌هات رو قوی‌تر و انعطاف‌پذیرتر کنی.
  8. sina
    sina پاسخی ارسال کرد برای یک پروژه در پروژه های من
    CLAP (مخفف Command Line Audio Player) یکی از پروژه های تفریحی من هست که با زبان برنامه نویسی RUST و با هدف ایجاد یک پخش کننده موسیقی ساده و سریع طراحی شده است. ویژگی های فنیزبان برنامه نویسی Rust رابط کاربری TUI یا Terminal User Interface استفاده از کتابخانه tui-rs موتور پخش صدا rodio پشتیبانی از فرمت های رایج MP3,WAV,OGG,FLAC استفاده از کتابخانه crossterm برای مدیریت ترمینال کراس پلتفرم ویژگی های فنی پیشرفتهاستفاده از Arc و Mutex برای اشتراک گذاری امن داده ها بین thread ها پیاده سازی الگوی طراحی Observer برای بروزرسانی وضعیت پخش بهینه سازی مصرف حافظه با استفاده از streaming برای پخش فایل های صوتی سایر توضیحات در فایل README قابل مشاهده میباشد.
  9. sina
    به عنوان یک توسعه‌دهنده که همیشه علاقمند به برنامه های خط فرمان و تحت ترمینال هستم،یه ابزار خط فرمان (CLI) که با استفاده از زبان Rust و کتابخونه ratatui ساختم. GuardXبرای مدیریت پوشه‌ها و فایل‌ها با قابلیت رمزنگاری طراحی شده و رابط کاربری غنی ترمینالی شیک و تعاملی داره. ویژگی‌های کلیدیاینجا یه نگاه کلی به قابلیت‌های GuardX می‌ندازیم: مدیریت فایل و پوشه: مرور آسون با کلیدهای جهت‌نما و چیدمان دوپنلی برای پوشه‌ها و فایل‌ها. رمزنگاری و رمزگشایی: محافظت از پوشه‌ها با یه کلید دلخواه و نمایش پیشرفت عملیات با نوار پیشرفت. پیش‌نمایش فایل: مشاهده محتوای فایل‌ها بدون نیاز به خروج از برنامه. رابط کاربری قابل تنظیم: انتخاب بین تم تیره و روشن و تنظیم طول کلید رمزنگاری از طریق پنجره تنظیمات. داشبورد و تاریخچه: بررسی آمار پوشه‌ها/فایل‌ها و مرور عملیات قبلی توی یه نوار کناری شیک. طراحی فنیرابط کاربری از یه سیستم رویدادمحور بهره می‌بره که با crossterm پیاده‌سازی شده و به کاربر اجازه می‌ده با کلیدها و حتی ماوس (برای کلیک روی آیتم‌ها) تعامل داشته باشه. برای جذابیت بصری، از رنگ‌های سفارشی (مثل Rgb(20, 20, 30) برای تم تیره) و آیکون‌های یونیکد (مثل 🔐 برای فایل‌های رمزنگاری‌شده) استفاده کردم. بررسی این پروژه رو به افرادی که به زبان Rust علاقمندن و قصد دارن پروژه های رمزگذاری و مشابه انجام بدن پیشنهاد میکنم.
  10. sina
    sina پاسخی ارسال کرد برای یک مطلب در شخصی و روزانه
    سال نو همیشه یادآور امید، شروع‌های تازه و فرصت‌های جدید است. هر سال با خودش چالش‌ها، لحظات شیرین و گاه تلخ را به همراه دارد؛ اما همین تغییرات و فراز و نشیب‌هاست که زندگی را پر از معنا و تجربه می‌کند. با آمدن سال نو، همه ما به دنبال فرصتی هستیم تا از اشتباهات گذشته درس بگیریم و با انرژی و انگیزه‌ای نو، به سمت آینده گام برداریم. این روزها که طبیعت لباس سبز به تن می‌کند و شکوفه‌ها دوباره جان می‌گیرند، دل‌های ما هم از امید و آرزوهای تازه پر می‌شود. در این سال نو، برایتان روزهایی پر از شادی، سلامتی، عشق و آرامش آرزو دارم. امیدوارم که لحظه‌هایتان سرشار از لبخندهای صادقانه و دل‌های شاد باشد. سالی سرشار از موفقیت، رشد و پیشرفت در انتظارتان باشد و هر قدمی که برمی‌دارید به سوی اهداف بزرگ‌تر و آرزوهای زیباتر باشد. بیایید در این سال جدید، مهربان‌تر، صبورتر و قدرشناستر باشیم؛ در کنار همدیگر بمانیم و برای ساختن آینده‌ای روشن‌تر تلاش کنیم. امیدوارم که این سال برای همه‌ی ما سالی پر از آرامش، دوستی‌های ناب و لحظات به یادماندنی باشد. سال نو مبارک! 🎉
  11. sina
    sina پاسخی ارسال کرد برای یک پروژه در پروژه های من
    Live RTL Fixer یک افزونه قدرتمند و متن‌باز برای مرورگر کروم اج و فایرفاکس است که با هدف بهبود تجربه کاربری زبان‌های راست‌به‌چپ (RTL) مانند فارسی و عربی طراحی شده است. این افزونه به‌طور خاص برای رفع مشکلات جهت‌گیری و ترازبندی متن در صفحات وب که در میان متن آنها لغات و کلمات انگلیسی و لاتین وجود دارد و موجب به هم ریختگی میشود طراحی شده است—به‌ویژه در شرایطی که از ابزارهای ترجمه مرورگر (مانند Google Translate) استفاده می‌شود. این افزونه با ارائه قابلیت‌های پیشرفته و رابط کاربری ساده، به کاربران اجازه می‌دهد متن‌ها را به‌صورت زنده و بدون نیاز به رفرش صفحه اصلاح کنند. ویژگی‌های کلیدیاصلاح زنده متن: با استفاده از MutationObserver، تغییرات DOM را در لحظه رصد می‌کند و جهت‌گیری متن (RTL یا LTR) را به‌طور خودکار یا دستی تنظیم می‌کند. تشخیص هوشمند زبان: الگوریتم تشخیص زبان مبتنی بر regex، با آستانه قابل تنظیم (پیش‌فرض 0.2)، به‌صورت دقیق متن‌های RTL (مثل فارسی و عربی) و LTR (مثل انگلیسی) را شناسایی می‌کند. حالت‌های خودکار و دستی: در حالت خودکار، استایل‌ها به‌طور مستقیم اعمال می‌شوند؛ در حالت دستی، کاربران می‌توانند با برچسب‌گذاری اولیه و اعمال تغییرات دلخواه کنترل بیشتری داشته باشند. مدیریت استثناها: بخش‌های کد (مثل تگ‌های <code> و <pre>) از فیکس مستثنی شده‌اند تا ساختار اصلی کدها حفظ شود. رابط کاربری تعاملی: پنجره popup با امکاناتی مثل فعال/غیرفعال کردن افزونه، انتخاب حالت، افزودن سایت‌ها به لیست سیاه، و ریست تغییرات. بهینه‌سازی عملکرد: با محدود کردن رصد تغییرات به المنت‌های متنی و استفاده از انتخابگرهای هدفمند، بار پردازشی به حداقل رسیده است. پشتیبانی از لیست سیاه: کاربران می‌توانند سایت‌هایی که نمی‌خواهند افزونه در آن‌ها اجرا شود را مشخص کنند. جزئیات فنیاین افزونه با جاوااسکریپت خالص و APIهای کروم و فایرفاکس توسعه داده شده و از ساختار زیر بهره می‌برد: فایل manifest.json: تنظیمات اصلی افزونه شامل مجوزها (activeTab, storage) و اتصال اسکریپت‌ها. content.js: هسته منطقی پروژه که با MutationObserver تغییرات DOM را رصد کرده و استایل‌های direction, text-align, و unicode-bidi را اعمال می‌کند. popup.js و popup.html: رابط کاربری و مدیریت تنظیمات کاربر با استفاده از chrome.storage.sync برای ذخیره‌سازی پایدار. styles.css: استایل‌های کمکی برای اطمینان از سازگاری بصری. یکی از نقاط قوت این افزونه، ماژولاریتی کد و مدیریت خطاهاست. با استفاده از توابع جداگانه (مثل detectLanguage و applyTextDirection) و try-catch، پایداری و خوانایی کد تضمین شده است. همچنین، بهینه‌سازی‌هایی مثل محدود کردن دامنه رصد به المنت‌های متنی و حذف بررسی‌های غیرضروری DOM، عملکرد را در صفحات شلوغ بهبود داده است. موارد استفادهاین افزونه برای کاربرانی که مرتباً با محتوای چندزبانه کار می‌کنند—مثل مترجمان، توسعه‌دهندگان وب، یا خوانندگان محتوای بین‌المللی—بسیار مناسب است. به‌عنوان مثال، کافیست یک صفحه انگلیسی را با ابزار ترجمه کروم به فارسی ترجمه کنید؛ Live RTL Fixer فوراً جهت‌گیری متن را اصلاح می‌کند، بدون اینکه ساختار کد یا بخش‌های LTR را مختل کند. نصب و استفادهبرای نصب، کافیست مخزن پروژه را از گیت‌هاب کلون کنید یا فایل ZIP را دانلود کرده و در حالت توسعه‌دهنده کروم بارگذاری کنید (chrome://extensions/). پس از نصب، آیکن افزونه در نوار ابزار ظاهر می‌شود و با یک کلیک می‌توانید تنظیمات را مدیریت کنید.توضیحات بیشتر در فایل README آورده شده است بروزرسانی 8/1/1404 : نسخه فایرفاکس افزوده شد لینگ Repository فایرفاکس
  12. sina
    SubAI، یک اپلیکیشن نوشته شده با پایتون برای ترجمه خودکار فایل‌های زیرنویس (SRT) با استفاده از API Gemini است. هدف این پروژه، ارائه ابزاری ساده و کاربردی برای ترجمه زیرنویس‌ها به زبان‌های مختلف است ویژگی‌های کلیدیاین برنامه امکانات متعددی را در اختیار کاربران قرار می‌دهد که آن را به ابزاری متمایز تبدیل می‌کند: رابط کاربری زیبا و کاربرپسند: طراحی شده با PyQT5،شامل جدول نمایش زیرنویس‌ها، دکمه‌های کنترلی و منوهای تنظیمات است. پشتیبانی از زبان‌های متنوع: امکان انتخاب زبان‌های هدف مانند انگلیسی، فرانسه، آلمانی، اسپانیایی، فارسی، چینی و ژاپنی. ترجمه مبتنی بر هوش مصنوعی: استفاده از API مدل‌های زبانی پیشرفته (مانند Gemini) برای ترجمه دقیق و سریع. مدیریت کش ترجمه: قابلیت ذخیره ترجمه‌ها در حافظه RAM یا فایل SQLite برای جلوگیری از ترجمه‌های تکراری. کنترل فرآیند ترجمه: امکان شروع، توقف و ادامه ترجمه‌ها همراه با نوار پیشرفت. تنظیمات پیشرفته: گزینه‌هایی برای تنظیم نرخ درخواست‌ها (RPM)، مدل زبانی، اندازه دسته (Batch Size) و نوع کش. معماری و پیاده‌سازیاین پروژه با استفاده از پایتون و فریم‌ورک Qt توسعه یافته است که به دلیل عملکرد بالا و قابلیت‌های گسترده در ساخت رابط‌های کاربری، انتخاب شده است. معماری پروژه به صورت زیر است: کلاس اصلی (SubtitleTranslatorApp): هسته برنامه که رابط کاربری را مدیریت می‌کند. شامل ویجت‌هایی مانند QTableWidget برای نمایش زیرنویس‌ها، QPushButton برای اقدامات کاربر و QProgressBar برای نشان دادن پیشرفت ترجمه. از QSqlDatabase برای مدیریت دیتابیس تنظیمات و کش استفاده می‌کند. پنجره‌های تنظیمات (SettingsDialog و AdvancedSettingsDialog): پنجره تنظیمات عمومی برای ورود کلید API و تنظیمات پروکسی. پنجره تنظیمات پیشرفته برای مدیریت پارامترهای ترجمه مانند RPM و مدل زبانی. همزمانی (TranslationWorker): یک کلاس مبتنی بر QThread که ترجمه‌ها را به صورت ناهمزمان انجام می‌دهد. از QNetworkAccessManager برای ارسال درخواست‌های HTTP به API ترجمه استفاده می‌کند. پشتیبانی از پردازش دسته‌ای (Batch Processing) برای بهینه‌سازی درخواست‌ها. منابع و دیتابیس: فایل‌های منبع مانند لوگوی برنامه (logo.png) با استفاده از سیستم منابع Qt (main.qrc) مدیریت می‌شوند. دیتابیس SQLite برای ذخیره تنظیمات و کش ترجمه‌ها. برنامه‌های آیندهاین پروژه هنوز جای توسعه دارد. برخی از ایده‌ها برای آینده شامل موارد زیر است: پشتیبانی کامل از فرمت‌های زیرنویس: اضافه کردن Parser پیشرفته‌تر برای SRT و فرمت‌های دیگر مانند ASS. ترجمه آفلاین: ادغام مدل‌های محلی هوش مصنوعی برای استفاده بدون اینترنت. مدل های متنوع:افزوده شدن مدل های متنوع هوش مصنوعی در کنار Gemini بهینه‌سازی بیشتر: کاهش حجم و بهبود زمان پاسخ‌دهی API. نحوه استفادهبرای استفاده از این نرم‌افزار: با توجه به توضیحات فایل README پایتون و نیازمندی های برنامه را نصب نمایید و اجرا کنید. از منوی "Public Settings" کلید API و پروکسی (در صورت نیاز) را تنظیم کنید. از منوی "Advanced Settings" پارامترهای ترجمه را مشخص کنید. فایل SRT را با دکمه "Choose File" انتخاب کنید. زبان مقصد را انتخاب کرده و "Start Translate" را بزنید. پس از اتمام ترجمه، فایل نهایی را با "Save" ذخیره کنید. این نرم‌افزار نه تنها ابزاری کاربردی برای کاربران عادی است، بلکه برای توسعه‌دهندگان نیز یک مطالعه موردی جذاب از مهندسی نرم‌افزار بهینه ارائه می‌دهد. اگر علاقه‌مند به مشارکت در توسعه یا استفاده از این پروژه هستید، خوشحال می‌شوم بازخورد شما را دریافت کنم.
  13. sina
    گاهی اوقات در برنامه‌ها و وب‌سایت‌ها نیاز داریم که کد ملی کاربران را دریافت کنیم. شاید تا به حال تنها کاری که برای اعتبارسنجی انجام می‌دادیم، بررسی این بود که کد ملی دقیقاً ده رقم داشته باشد و فقط شامل اعداد باشد. در این حالت، کاربر می‌توانست با وارد کردن یک عدد ده‌رقمی غیرمعتبر به راحتی از این مرحله عبور کند. اخیراً به دلیل نیاز شخصی‌ام، کدی برای بررسی صحت کد ملی نوشتم. از آنجا که مطمئنم افراد زیادی هم به این موضوع نیاز دارند، در این مقاله توابع و مراحل انجام کار را توضیح می‌دهم. کد ملی یک شماره ده‌رقمی است که سه رقم اول از سمت چپ نشان‌دهنده کد شهرستان محل صدور شناسنامه، شش رقم بعدی یک کد منحصربه‌فرد برای فرد در آن شهرستان و رقم آخر یک رقم کنترلی است که بر اساس نه رقم قبلی محاسبه می‌شود. برای تأیید صحت کد، کافی است رقم کنترلی را دوباره از روی نه رقم اول محاسبه کنیم. با توجه به اینکه در سیستم کد ملی معمولاً صفرهایی قبل از کد وجود دارد (رقم اول یا دوم از سمت چپ ممکن است صفر باشد)، گاهی کاربران این صفرها را وارد نمی‌کنند یا نرم‌افزار آن‌ها را ذخیره نمی‌کند. بنابراین، بهتر است ابتدا بررسی کنیم که اگر طول کد بین ۸ تا ۹ رقم است، به تعداد لازم (یک یا دو صفر) به سمت چپ عدد اضافه کنیم. الگوریتم محاسبهبرای محاسبه رقم کنترلی، هر رقم را در موقعیتش (از رقم یک تا رقم نه از چپ به راست) ضرب کرده و همه نتایج را با هم جمع می‌کنیم. مجموع به‌دست‌آمده را بر ۱۱ تقسیم می‌کنیم. اگر باقیمانده کمتر از ۲ باشد، رقم کنترلی باید برابر باقیمانده باشد؛ در غیر این صورت، رقم کنترلی برابر است با ۱۱ منهای باقیمانده. مثال: آیا کد 7731689951 معتبر است؟محاسبه: 7×10 + 7×9 + 3×8 + 1×7 + 6×6 + 8×5 + 9×4 + 9×3 + 5×2 = 313 313 ÷ 11 = 28 (باقیمانده = 5)چون باقیمانده (۵) بزرگ‌تر یا برابر ۲ است، رقم کنترلی باید ۱۱ - ۵ = ۶ باشد. اما در کد واردشده، رقم آخر ۱ است. پس این کد ملی معتبر نیست. نمونه کد جاوااسکریپت: /** * Validates an Iranian National Code based on the official algorithm. * * @param {string} nationalCode - The national code to validate * @returns {boolean} - True if valid, false otherwise */ function validateIranianNationalCode(nationalCode = '') { // Remove non-numeric characters const cleanedCode = (nationalCode || '').replace(/[^0-9]/g, ''); // Check length (must be 8 to 10 digits) const codeLength = cleanedCode.length; if (codeLength < 8 || codeLength > 10) { return false; } // Standardize to 10 digits by padding with leading zeros const standardizedCode = cleanedCode.padStart(10, '0'); // Check if all digits are the same if (standardizedCode.split('').every(digit => digit === standardizedCode[0])) { return false; } // Extract check digit (last digit) const checkDigit = parseInt(standardizedCode.slice(-1)); const digits = standardizedCode.slice(0, -1).split('').map(Number); // Calculate weighted sum (weights: 10 down to 2) const sum = digits.reduce((acc, digit, i) => acc + digit * (10 - i), 0); // Compute remainder and check digit const remainder = sum % 11; const calculatedCheckDigit = remainder < 2 ? remainder : 11 - remainder; // Return true if check digits match return calculatedCheckDigit === checkDigit; } // Test console.log(validateIranianNationalCode('6587452158')); // falseبرای راحتی کار، این الگوریتم را به زبان‌های برنامه‌نویسی مختلف پیاده‌سازی کرده‌ام و در گیت‌هاب قرار داده‌ام. کد در Repository در دسترس است و توضیحات تکمیلی در فایل README نوشته شده است. مثال زندهبرای استفاده از این پروژه میتوانید از صفحه زیر استفاده کنید. jalalvandi.github.io/IR-NationalCode توجه فرمایید اعدادی که وارد میکنید در هیچ جایی ذخیره نخواهند شد.
  14. sina
    زبان C به دلیل سادگی، کارایی بالا و دسترسی مستقیم به سخت‌افزار، یکی از پرکاربردترین زبان‌های برنامه‌نویسی است. اما یکی از قابلیت‌های قدرتمند و در عین حال کمتر شناخته‌شده آن، برنامه‌نویسی متا با استفاده از ماکروها و پیش‌پردازنده است. این قابلیت به شما امکان می‌دهد کدهایی انعطاف‌پذیر، بهینه و خودکار تولید کنید که در زمان کامپایل پردازش شده و از نظر کارایی بسیار سریع هستند. پیش‌پردازنده C چیست؟پیش‌پردازنده C یک مرحله قبل از کامپایل است که در آن دستورات خاصی پردازش شده و کد نهایی قبل از کامپایل تولید می‌شود. این مرحله شامل: تعریف ماکروها (#define) شرطی‌سازی کامپایل (#ifdef، #ifndef) گنجاندن فایل‌ها (#include) دستورات پیش‌پردازنده‌ی دیگر مانند #pragma و #error ماکروها، که معمولاً با #define تعریف می‌شوند، پایه اصلی برنامه‌نویسی متا در C هستند. برنامه‌نویسی متا با ماکروهابرنامه‌نویسی متا در C عمدتاً به کمک ماکروها و توابع درون‌خطی انجام می‌شود. در ادامه چند نمونه از استفاده‌های پیشرفته ماکروها را بررسی می‌کنیم. 1. ماکروهای توابع (Function-like Macros)ماکروها می‌توانند مانند توابع رفتار کنند اما بدون سربار فراخوانی تابع، زیرا مستقیماً در کد جایگذاری می‌شوند. #include <stdio.h> #define SQUARE(x) ((x) * (x)) int main() { int num = 5; printf("Square of %d is %d\n", num, SQUARE(num)); return 0; } در اینجا SQUARE(5) به ((5) * (5)) تبدیل شده و مقدار 25 چاپ می‌شود. این نوع ماکروها برای بهینه‌سازی محاسبات ساده بسیار مفید هستند. 2. استفاده از # و ## در ماکروهادو عملگر خاص در ماکروهای C وجود دارند: # برای تبدیل آرگومان به رشته ## برای چسباندن دو آرگومان به هم #include <stdio.h> #define TO_STRING(x) #x #define CONCAT(a, b) a##b int main() { printf("String: %s\n", TO_STRING(Hello, World!)); int xy = 100; printf("Concatenated Variable: %d\n", CONCAT(x, y)); return 0; } در این مثال: TO_STRING(Hello, World!) مقدار "Hello, World!" را تولید می‌کند. CONCAT(x, y) باعث می‌شود xy به عنوان متغیر خوانده شود و مقدار 100 را نمایش دهد. 3. ماکروهای متغیر (Variadic Macros)ماکروهای متغیر می‌توانند تعداد نامحدودی آرگومان دریافت کنند. #include <stdio.h> #define DEBUG_PRINT(fmt, ...) printf("DEBUG: " fmt "\n", __VA_ARGS__) int main() { DEBUG_PRINT("Value of x: %d", 10); DEBUG_PRINT("Sum: %d, Product: %d", 5 + 3, 5 * 3); return 0; } در اینجا __VA_ARGS__ آرگومان‌های متغیر را پردازش کرده و امکان لاگ‌گیری انعطاف‌پذیر را فراهم می‌کند. مزایا و معایب برنامه‌نویسی متا در Cمزایا بهینه‌سازی سرعت – ماکروها مستقیماً در کد جایگزین می‌شوند و باعث حذف سربار اجرای تابع می‌شوند. کاهش تکرار کد – بسیاری از کدهای تکراری را می‌توان به ماکرو تبدیل کرد. امکان برنامه‌نویسی سطح پایین – امکان تعریف ساختارهای پیشرفته مانند مدیریت سخت‌افزار و رجیسترهای پردازنده را فراهم می‌کند. معایبدیباگ دشوار – خطاهای ناشی از ماکروها معمولاً در خروجی کامپایل ظاهر نمی‌شوند و تشخیص مشکل سخت است. عدم بررسی نوع داده – ماکروها مانند توابع تایپ‌سیف نیستند و ممکن است مشکلاتی در نوع داده ایجاد کنند. افزایش پیچیدگی کد – خوانایی کد در صورت استفاده نادرست از ماکروها کاهش می‌یابد. نمونه‌های کاربردی برنامه‌نویسی متا در C1. مدیریت حافظه هوشمندیکی از کاربردهای متا، تعریف ماکروهایی برای تخصیص و آزادسازی خودکار حافظه است. #include <stdio.h> #include <stdlib.h> #define SAFE_ALLOC(ptr, size) do { ptr = malloc(size); if (!ptr) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } } while(0) int main() { int *arr; SAFE_ALLOC(arr, 10 * sizeof(int)); // استفاده از آرایه... free(arr); return 0; } این ماکرو اطمینان حاصل می‌کند که تخصیص حافظه موفق بوده و در غیر این صورت برنامه را متوقف می‌کند. 2. تبدیل توابع به درون‌خطی (Inline Functions)اگرچه inline در C مدرن موجود است، اما در نسخه‌های قدیمی‌تر C، ماکروها برای درون‌خطی کردن توابع استفاده می‌شدند: #define MAX(a, b) ((a) > (b) ? (a) : (b)) int main() { printf("Max: %d\n", MAX(10, 20)); return 0; } در نهایتبرنامه‌نویسی متا در C با استفاده از ماکروها و پیش‌پردازنده یک ابزار قدرتمند برای بهینه‌سازی، کاهش تکرار کد و خودکارسازی عملیات پیچیده است. این تکنیک به‌ویژه در سیستم‌های نهفته، توسعه کرنل و برنامه‌های کارایی‌محور بسیار پرکاربرد است. با این حال، نیاز به درک عمیق از ساختار کد و مدیریت صحیح خطاها دارد تا از مشکلات رایج آن جلوگیری شود. استفاده مناسب از ماکروها می‌تواند توسعه نرم‌افزار را سریع‌تر، بهینه‌تر و خواناتر کند، اما باید از استفاده بیش‌ازحد و غیرضروری آن‌ها اجتناب کرد.
  15. sina
    شاتل‌های فضایی ناسا، از کلمبیا تا آتلانتیس، فقط ماشین‌های عظیم آهنی نبودن؛ اونا یه شاهکار تکنولوژیک بودن که با قدرت ذهن بشر و چند خط کد به فضا پرواز کردن. تصور کن یه شاتل با سرعت ۲۸٬۰۰۰ کیلومتر بر ساعت دور زمین می‌گرده، توی جو مانور می‌ده و بعد با دقت روی باند فرود میاد. حالا فکر کن همه اینا با کامپیوتری انجام شده که حافظه‌اش از یه فلش USB امروزی هم کمتر بود! اینجاست که سیستم‌های نرم‌افزاری و کامپیوتری شاتل‌ها وارد داستان می‌شن: یه دنیای پیچیده از کد، سخت‌افزار و هوشمندی که هر خطاش می‌تونست یه مأموریت رو به فاجعه بکشونه. توی این مقاله قراره سفری داشته باشیم به قلب این سیستم‌ها. از زبان برنامه‌نویسی خاص HAL/S که شاتل‌ها رو هدایت می‌کرد، تا کامپیوترهای قدیمی‌ای که مثل یه ارکستر هماهنگ کار می‌کردن. می‌خوام خطاهایی که نفس‌ها رو حبس کردن و درس‌هایی که ازشون گرفته شد رو باهم ببینیم. این نه فقط یه داستان فنیه، بلکه روایتی از تلاش بشر برای فتح فضاست با ابزارهایی که الان شاید ساده به نظر بیان. پس اگه کنجکاوی که بدونی چطور این غول‌های فضایی با چند خط کد زنده بودن، بیا با من همراه شو! کامپیوترهای GPC - ستون فقرات شاتل‌ها هر شاتل فضایی به پنج تا کامپیوتر IBM AP-101 مجهز بود که بهشون General Purpose Computers یا GPC می‌گفتن. اینا هسته مرکزی عملیات بودن و همه‌چیز، از پرتاب و کنترل مداری تا فرود، رو مدیریت می‌کردن. حالا فکر کن هر کدوم از این کامپیوترها فقط ۱ مگابایت حافظه و قدرت پردازش ۰٫۴ میلیون دستور در ثانیه داشتن. برای مقایسه، یه لپ‌تاپ معمولی امروزی هزاران برابر قوی‌تره! چهار تا از این GPCها یه برنامه مشترک به اسم PASS (Primary Avionics Software System) رو اجرا می‌کردن و مدام با هم مقایسه می‌شدن. این طراحی "redundant" یعنی اگه یکی خراب می‌شد یا اشتباه می‌کرد، بقیه می‌تونستن تشخیص بدن و کار رو ادامه بدن. پنجمی اما یه نقش خاص داشت: فقط سیستم پشتیبان (Backup Flight System یا BFS) رو اجرا می‌کرد و برای مواقع اضطراری آماده بود. این کامپیوترها توی شرایط سخت فضا کار می‌کردن: تشعشع کیهانی، دمای شدید و لرزش‌های وحشتناک. با این حال، ناسا طوری اونا رو ساخته بود که حتی با این محدودیت‌ها، دقتشون از دست نره. چطور؟ جواب توی نرم‌افزارهاییه که این سخت‌افزار ساده رو به یه ماشین فضایی تبدیل کرده بود. توی بخش بعدی، زبانی که این کدها رو شکل داد رو بررسی می‌کنیم. HAL/S - زبان برنامه‌نویسی شاتل‌هاناسا برای شاتل‌ها نمی‌تونست سراغ زبان‌های معمولی مثل فورترن یا اسمبلی بره. به جاش یه زبان اختصاصی به اسم HAL/S (High-order Assembly Language/Shuttle) طراحی کرد که دهه ۱۹۷۰ توسط شرکت Intermetrics ساخته شد. این زبان انگار برای شاتل‌ها زاده شده بود: هم قدرتمند بود، هم بهینه برای سخت‌افزار محدود GPCها. HAL/S برای سیستم‌های "بلادرنگ" (real-time) طراحی شده بود، یعنی می‌تونست توی کسری از ثانیه به تغییرات واکنش نشون بده؛ چیزی که توی فضا حیاتیه. مثلاً وقتی شاتل توی جو باید زاویه‌اش رو تنظیم می‌کرد، این زبان به برنامه‌نویس‌ها اجازه می‌داد زمان‌بندی دقیق دستورات رو کنترل کنن. یه نمونه کد ساده: DCL THRUST VECTOR(3) FIXED; UPDATE THRUST WITH NEW_VALUES; SCHEDULE THRUST_ADJUST AT 0.1 SECONDS; اینجا یه بردار رانش تعریف می‌شه، با داده‌های جدید آپدیت می‌شه و بعد توی ۰٫۱ ثانیه تنظیم می‌شه. یه ویژگی دیگه HAL/S، مدیریت خطاهاش بود. اگه یه متغیر از محدوده خارج می‌شد، خودش هشدار می‌داد. این برای شاتل‌ها حیاتی بود، چون یه خطای کوچیک می‌تونست فاجعه بیاره. حجم کدها هم کم نبود: PASS حدود ۴۰۰٬۰۰۰ خط کد داشت و BFS نزدیک ۱۰۰٬۰۰۰ خط. برنامه‌نویس‌ها باید این کدها رو طوری می‌نوشتن که توی ۱ مگابایت حافظه جا بشه و کند نشه. برای همین، تست‌ها و شبیه‌سازی‌ها گاهی ماه‌ها طول می‌کشید تا مطمئن بشن همه‌چیز بی‌نقصه. اما آیا واقعاً بی‌نقص بود؟ بیایم چندتا خطای واقعی رو ببینیم. خطاهای نرم‌افزاری - لحظات نفس‌گیرهرچند سیستم شاتل‌ها خیلی دقیق بود، اما خطاها گاهی خودشون رو نشون می‌دادن. یکی از معروف‌ترینش توی اولین پرتاب شاتل (STS-1، کلمبیا، ۱۹۸۱) بود. قرار بود ۱۰ آوریل پرتاب بشه، ولی ۲۰ دقیقه قبل از بلند شدن، سیستم قفل کرد. چهار تا GPC که PASS رو اجرا می‌کردن، باید همزمان باهم sync می‌شدن، ولی یه اختلاف یک میلی‌ثانیه‌ای توی زمان‌بندی همه‌چیز رو متوقف کرد. مشکل از یه "race condition" توی کد HAL/S بود. یه بخش از برنامه که زمان‌بندی رو چک می‌کرد، به این شکل بود: SYNC_CLOCKS: READ MASTER_CLOCK INTO LOCAL_TIME; IF LOCAL_TIME ≠ EXPECTED_TIME THEN HALT; یه تأخیر ریز توی انتقال داده باعث شد LOCAL_TIME مقدار قدیمی بخونه و سیستم فکر کنه یه جای کار خرابه. ناسا دو روز پرتاب رو عقب انداخت و با اضافه کردن یه بافر زمانی، مشکل رو حل کرد. این خطا نشون داد که حتی با تست‌های گسترده، شرایط نادر می‌تونن غافلگیرکننده باشن. یه مورد دیگه توی STS-9 (۱۹۸۳) بود. وقتی شاتل کلمبیا برای فرود آماده می‌شد، دو تا GPC به‌خاطر مشکل سخت‌افزاری (شاید تشعشع کیهانی) از کار افتادن. BFS فعال شد، ولی یه باگ باعث شد یه جت کنترلی (RCS) بیش از حد روشن بمونه و شاتل یه چرخش ناخواسته بکنه. مشکل از یه متغیر بود که توی سوئیچ به BFS درست ریست نشده بود. خلبان‌ها با مهارتشون فرود رو نجات دادن، ولی ناسا بعدش کد BFS رو آپدیت کرد. این خطاها درس‌های بزرگی داشتن: تست‌ها باید سخت‌گیرانه‌تر بشن و حتی سیستم‌های پشتیبان هم نیاز به دقت دارن. BFS - خط دفاعی شاتل‌هاBackup Flight System یا BFS مثل یه سپر اضطراری بود. اگه PASS به هر دلیلی از کار می‌افتاد، BFS با ۱۰۰٬۰۰۰ خط کدش کنترل رو می‌گرفت. این سیستم فقط برای کارهای ضروری طراحی شده بود: نویگیشن پایه، کنترل موتورها و فرود امن. BFS توسط تیمی جدا از PASS نوشته شده بود تا باگ‌های مشترک نداشته باشن. حتی از نسخه کمی متفاوت HAL/S استفاده می‌کرد. توی کابین خلبان، یه دکمه به اسم "BFS Engage" بود که با زدنش، GPC پنجم فعال می‌شد و شاتل رو نجات می‌داد. توی STS-9 دیدیم که BFS چطور وارد عمل شد، ولی همون باگ جت کنترلی نشون داد که سادگی BFS هم محدودیت‌هایی داره. ناسا بعدش مطمئن شد که هر وقت BFS فعال می‌شه، همه متغیرها از نو مقداردهی بشن. این سیستم یه فلسفه مهم رو یادآوری کرد: توی فضا، گاهی ساده نگه داشتن بهترین راه‌حله. تست‌ها و شبیه‌سازی‌ها - نبرد با ناشناخته‌هاناسا نمی‌تونست ریسک کنه. برای همین قبل از هر مأموریت، هزاران ساعت شبیه‌سازی انجام می‌داد. توی مرکز Shuttle Avionics Integration Laboratory (SAIL) توی هیوستون، یه نسخه کامل از شاتل ساخته شده بود که همه سناریوها رو تست می‌کرد: از پرتاب توی طوفان خورشیدی تا فرود توی شرایط بحرانی. هر خط کد بارها اجرا می‌شد تا مطمئن بشن هیچ باگی نیست. ناسا از رویکرد "correct-by-construction" استفاده می‌کرد، یعنی کدها رو طوری می‌نوشتن که از اول درست باشن. اما همون‌طور که توی STS-1 دیدیم، بعضی خطاها فقط توی لحظه واقعی خودشون رو نشون می‌دادن. تست‌ها انقدر دقیق بود که گاهی یه مأموریت ماه‌ها عقب می‌افتاد. مثلاً قبل از STS-1، ناسا ده ها هزار بار پرتاب رو شبیه‌سازی کرد، ولی بازم اون باگ زمان‌بندی غافلگیرشون کرد. بعد از هر خطا، سناریوهای جدید به تست‌ها اضافه می‌شد تا دیگه تکرار نشه. این دقت باعث شد توی ۱۳۵ مأموریت شاتل، هیچ فاجعه‌ای مستقیماً به‌خاطر نرم‌افزار رخ نده. مقایسه با امروز - شاتل‌ها در برابر فضاپیما های امروزیحالا که شاتل‌ها بازنشسته شدن، فضاپیماهای مدرن مثل Crew Dragon اسپیس‌ایکس جای اونا رو گرفتن. تفاوتشون با شاتل‌ها مثل مقایسه یه ماشین‌حساب با یه سوپرکامپیوتره. Crew Dragon از پردازنده‌های چند هسته‌ای با گیگابایت‌ها حافظه استفاده می‌کنه و نرم‌افزارش با زبان‌های مدرن مثل C++ نوشته شده. شاتل‌ها با ۱ مگابایت حافظه و HAL/S کار می‌کردن، ولی این محدودیت باعث شده بود ناسا روی دقت و بهینه‌سازی تمرکز کنه. توی سیستم‌های مدرن، قدرت پردازش اجازه می‌ده کدها پیچیده‌تر باشن و حتی هوش مصنوعی برای تصمیم‌گیری استفاده بشه. اما یه تفاوت بزرگ اینه که شاتل‌ها برای هر مأموریت دستی تنظیم می‌شدن، در حالی که فضاپیماهای جدید مثل Crew Dragon خودکارترن. با این حال، شاتل‌ها یه میراث بزرگ گذاشتن: نشون دادن که با منابع کم هم می‌شه کارهای بزرگ کرد. این فلسفه هنوز توی طراحی سیستم‌های فضایی دیده می‌شه.
  16. sina
    اگر توسعه‌دهنده وب باشید یا به دنیای برنامه‌نویسی جاوا اسکریپت علاقه داشته باشید، احتمالاً با چالش‌هایی مثل خطای undefined یا null هنگام دسترسی به خواص یک شیء مواجه شده‌اید. این مشکل معمولاً زمانی رخ می‌دهد که بخواهید به یک ویژگی عمیق در یک شیء دسترسی پیدا کنید، اما مطمئن نباشید که تمام زنجیره مسیر دسترسی به آن ویژگی وجود دارد یا نه. خوشبختانه، جاوا اسکریپت با معرفی Optional Chaining یا زنجیره اختیاری در نسخه ES11 (سال 2020) این مشکل را به شکلی زیبا و کارآمد حل کرده است. در این مقاله قصد دارم شما را با این قابلیت جدید، نحوه کارکرد آن، کاربردهایش و تأثیرش بر کدنویسی روزمره آشنا کنم. زنجیره اختیاری چیست؟زنجیره اختیاری که با عملگر ?. نشان داده می‌شود، به شما اجازه می‌دهد به خواص یا متدهای یک شیء دسترسی پیدا کنید، بدون اینکه نگران باشید که آیا مقدار آن شیء یا بخشی از زنجیره مسیرش null یا undefined است یا نه. اگر در هر مرحله از زنجیره، مقدار null یا undefined پیدا شود، به جای پرتاب خطا، به سادگی مقدار undefined برگردانده می‌شود. این ویژگی نه تنها کدنویسی را تمیزتر می‌کند، بلکه از بسیاری از خطاهای رایج که توسعه‌دهندگان با آن دست‌وپنجه نرم می‌کنند، جلوگیری می‌کند. بیایید با یک مثال ساده شروع کنیم. فرض کنید یک شیء به شکل زیر دارید: const user = { name: "علی", address: { city: "تهران" } };حالا اگر بخواهید به user.address.city دسترسی پیدا کنید، مشکلی نیست چون مسیر کامل وجود دارد. اما اگر شیء address وجود نداشته باشد چه؟ مثلاً: const user = { name: "علی" }; console.log(user.address.city); // TypeError: Cannot read property 'city' of undefinedدر این حالت، چون address وجود ندارد، جاوا اسکریپت نمی‌تواند به city دسترسی پیدا کند و خطای TypeError پرتاب می‌شود. قبل از معرفی زنجیره اختیاری، توسعه‌دهندگان مجبور بودند با شرط‌های متعدد این مشکل را مدیریت کنند: const city = user && user.address && user.address.city; console.log(city); // undefinedاین روش کار می‌کند، اما کد را شلوغ و خواندنش را سخت‌تر می‌کند. حالا با زنجیره اختیاری، همین کار را می‌توان به این شکل انجام داد: const city = user?.address?.city; console.log(city); // undefinedخیلی ساده‌تر و خواناتر، نه؟ نحو و نحوه کارکردعملگر ?. در سه موقعیت اصلی استفاده می‌شود: دسترسی به خواص شیء: مثل obj?.prop دسترسی به آرایه‌ها: مثل arr?.[index] فراخوانی متدها: مثل obj?.method() هر وقت از این عملگر استفاده می‌کنید، جاوا اسکریپت ابتدا بررسی می‌کند که مقدار سمت چپ ?. آیا null یا undefined است یا نه. اگر باشد، فرآیند متوقف می‌شود و undefined برمی‌گرداند. اگر نه، به دسترسی یا فراخوانی ادامه می‌دهد. مثال دیگر برای آرایه‌ها: const data = [1, 2, 3]; console.log(data?.[1]); // 2 const emptyData = null; console.log(emptyData?.[1]); // undefinedیا برای متدها: const user = { sayHello() { return "سلام!"; } }; console.log(user?.sayHello?.()); // "سلام!" console.log(null?.sayHello?.()); // undefinedچرا زنجیره اختیاری مهم است؟حالا که با نحوه کارش آشنا شدید، بیایید ببینیم چرا این قابلیت اینقدر مورد استقبال قرار گرفته است: کاهش خطاها: دیگر نیازی نیست نگران خطاهای غیرمنتظره باشید. اگر داده‌ای که از API یا منبع خارجی می‌آید ناقص باشد، زنجیره اختیاری به شما کمک می‌کند بدون دردسر از آن عبور کنید. کد تمیزتر: به جای نوشتن شرط‌های طولانی و پیچیده، با یک عملگر ساده می‌توانید همان نتیجه را بگیرید. این یعنی خوانایی بیشتر و نگهداری آسان‌تر. انعطاف‌پذیری با داده‌های پویا: در دنیای واقعی، داده‌ها همیشه طبق انتظار ما نیستند. مثلاً وقتی با یک API کار می‌کنید، ممکن است بعضی فیلدها گاهی وجود داشته باشند و گاهی نه. زنجیره اختیاری این عدم قطعیت را به خوبی مدیریت می‌کند. سازگاری با فریم‌ورک‌ها: در کتابخانه‌هایی مثل React یا Vue که با داده‌های پویا زیاد سر و کار دارید، این قابلیت به شدت زمان توسعه را کاهش می‌دهد. کاربردهای عملیبیایید چند سناریوی واقعی را بررسی کنیم که زنجیره اختیاری در آن‌ها می‌درخشد: 1. کار با API‌هافرض کنید از یک API اطلاعاتی درباره کاربر دریافت می‌کنید: fetch("https://api.example.com/user") .then((response) => response.json()) .then((data) => { const street = data?.user?.address?.street || "خیابان نامشخص"; console.log(street); });اگر هر یک از این فیلدها وجود نداشته باشد، به جای خطا، مقدار پیش‌فرض نمایش داده می‌شود. 2. مدیریت تنظیمات اختیاریتصور کنید یک تابع دارید که تنظیماتی را به صورت اختیاری می‌پذیرد: function configure(options) { const timeout = options?.timeout ?? 5000; // اگر timeout نباشد، 5000 console.log(`تنظیم زمان: ${timeout} میلی‌ثانیه`); } configure({ timeout: 3000 }); // "تنظیم زمان: 3000 میلی‌ثانیه" configure({}); // "تنظیم زمان: 5000 میلی‌ثانیه"اینجا از عملگر ?? (Nullish Coalescing) هم کنار ?. استفاده شده که فقط در صورت null یا undefined مقدار پیش‌فرض را برمی‌گرداند. 3. بررسی توابع اختیاریاگر بخواهید متدی را فراخوانی کنید که ممکن است وجود نداشته باشد: const plugin = { init: () => console.log("شروع شد!") }; plugin?.init?.(); // "شروع شد!" const noPlugin = null; noPlugin?.init?.(); // هیچ خطایی نمی‌دهد، فقط undefinedمحدودیت‌ها و نکات مهمهرچند زنجیره اختیاری فوق‌العاده است، اما محدودیت‌هایی هم دارد که باید به آن‌ها توجه کنید: پشتیبانی مرورگر: این قابلیت در مرورگرهای قدیمی (مثل IE) پشتیبانی نمی‌شود. اگر پروژه‌تان نیاز به سازگاری با مرورگرهای قدیمی دارد، باید از ابزارهایی مثل Babel استفاده کنید. استفاده بیش از حد: اگر در هر خط کد از ?. استفاده کنید، ممکن است کدتان بیش از حد دفاعی شود و اشکال‌زدایی سخت‌تر شود. تفاوت با عملگرهای دیگر: ?. با && یا || فرق دارد. مثلاً 0 && "something" مقدار 0 را برمی‌گرداند، اما 0?.something خطا نمی‌دهد و undefined می‌دهد. جمع‌بندیزنجیره اختیاری (?.) یکی از بهترین قابلیت‌هایی است که جاوا اسکریپت در سال‌های اخیر به خودش دیده است. این ویژگی نه تنها زندگی توسعه‌دهندگان را آسان‌تر کرده، بلکه به ما اجازه می‌دهد کدهایی بنویسیم که هم ایمن‌ترند و هم خواناتر. اگر هنوز از این قابلیت استفاده نکرده‌اید، پیشنهاد می‌کنم همین حالا آن را در پروژه بعدی‌تان امتحان کنید. مطمئنم بعد از چند بار استفاده، دیگر نمی‌توانید بدون آن کدنویسی کنید! نظر شما چیست؟ آیا تجربه‌ای با زنجیره اختیاری دارید؟ در بخش نظرات وبلاگم برام بنویسید و اگر سوالی دارید، خوشحال می‌شم کمکتون کنم!
  17. sina
    مسئله کولاتز یکی از معروف‌ترین و در عین حال حل‌نشده‌ترین مسائل در دنیای ریاضیات است. این مسئله که گاهی با نام‌های «حدس کولاتز»، «دنباله ۳n+1» یا «مسئله سیراکیوز» نیز شناخته می‌شود، توسط لوتار کولاتز، ریاضیدان آلمانی، در سال ۱۹۳۷ مطرح شد. سادگی صورت مسئله در کنار پیچیدگی اثبات آن، این موضوع را به یکی از جذاب‌ترین معماهای ریاضی تبدیل کرده است. در این مقاله، به بررسی این مسئله، نحوه عملکرد آن، یک مثال برنامه‌نویسی و اهمیت آن در ریاضیات مدرن می‌پردازیم. مسئله کولاتز چیست؟صورت مسئله کولاتز بسیار ساده است: یک عدد طبیعی (مثبت) دلخواه انتخاب کنید و سپس از این قانون پیروی کنید: اگر عدد زوج باشد، آن را بر ۲ تقسیم کنید. اگر عدد فرد باشد، آن را در ۳ ضرب کرده و ۱ را به نتیجه اضافه کنید (۳n + 1). این روند را با عدد جدید تکرار کنید. حدس کولاتز می‌گوید که مهم نیست چه عددی را در ابتدا انتخاب کنید، با تکرار این مراحل، در نهایت به عدد ۱ خواهید رسید. پس از رسیدن به ۱، دنباله وارد یک چرخه می‌شود: ۱ → ۴ → ۲ → ۱، و این روند بی‌پایان تکرار می‌شود. به این ترتیب، سؤال اصلی این است: آیا این حدس برای همه اعداد طبیعی صادق است؟ مثال سادهبرای درک بهتر، بیایید با عدد ۱۳ شروع کنیم و مراحل را دنبال کنیم: ۱۳ فرد است: ۳ × ۱۳ + ۱ = ۴۰ ۴۰ زوج است: ۴۰ ÷ ۲ = ۲۰ ۲۰ زوج است: ۲۰ ÷ ۲ = ۱۰ ۱۰ زوج است: ۱۰ ÷ ۲ = ۵ ۵ فرد است: ۳ × ۵ + ۱ = ۱۶ ۱۶ زوج است: ۱۶ ÷ ۲ = ۸ ۸ زوج است: ۸ ÷ ۲ = ۴ ۴ زوج است: ۴ ÷ ۲ = ۲ ۲ زوج است: ۲ ÷ ۲ = ۱ حالا به ۱ رسیدیم و دنباله وارد چرخه ۱ → ۴ → ۲ → ۱ می‌شود. این مثال نشان می‌دهد که حدس کولاتز برای عدد ۱۳ برقرار است. اما آیا این برای همه اعداد صادق است؟ تاکنون هیچ کس نتوانسته این را به طور قطعی اثبات یا رد کند! برنامه‌نویسی مسئله کولاتزبرای درک بهتر رفتار این دنباله، می‌توانیم از برنامه‌نویسی استفاده کنیم. در زیر یک کد ساده به زبان پایتون ارائه شده است که دنباله کولاتز را برای یک عدد دلخواه محاسبه می‌کند: def collatz(n): print(n, end=" -> ") while n != 1: if n % 2 == 0: # اگر زوج باشد n = n // 2 else: # اگر فرد باشد n = 3 * n + 1 print(n, end=" -> ") print("پایان") # تست با یک عدد collatz(13)خروجی این کد همان دنباله‌ای است که برای عدد ۱۳ در بالا محاسبه کردیم: 13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 -> پایاناین برنامه نشان می‌دهد که دنباله چگونه به ۱ می‌رسد. می‌توانید عدد دیگری را امتحان کنید و رفتار دنباله را بررسی کنید. نکته جالب اینجاست که حتی برای اعداد بسیار بزرگ (مثلاً میلیون‌ها یا میلیاردها)، آزمایش‌ها نشان داده‌اند که دنباله در نهایت به ۱ می‌رسد، اما این فقط یک مشاهده تجربی است و نه یک اثبات ریاضی. چرا کولاتز حل‌نشده باقی مانده است؟با وجود سادگی ظاهری، اثبات یا رد حدس کولاتز به یکی از دشوارترین چالش‌های ریاضی تبدیل شده است. ریاضیدانان تا به امروز دنباله کولاتز را برای اعداد بسیار بزرگ آزمایش کرده‌اند (تا حدود ۲ به توان ۶۸) و همه آن‌ها به ۱ رسیده‌اند. با این حال، این آزمایش‌ها نمی‌توانند تضمین کنند که هیچ عددی وجود ندارد که به ۱ نرسد یا وارد یک چرخه دیگر شود. این مسئله به نظریه اعداد و رفتار غیرقابل پیش‌بینی دنباله‌ها مرتبط است و ابزارهای ریاضی فعلی هنوز برای حل کامل آن کافی به نظر نمی‌رسند. اهمیت و جذابیت کولاتزمسئله کولاتز نه تنها برای ریاضیدانان، بلکه برای برنامه‌نویسان و علاقه‌مندان به علوم کامپیوتر نیز جذاب است. سادگی پیاده‌سازی آن در کد و در عین حال عمق ریاضیاتی‌اش، آن را به یک موضوع ایده‌آل برای آموزش و پژوهش تبدیل کرده است. علاوه بر این، کولاتز نمونه‌ای از مسائلی است که نشان می‌دهد چگونه یک سؤال ساده می‌تواند به یک معمای عمیق و حل‌نشده منجر شود. نتیجه‌گیریحدس کولاتز همچنان یکی از اسرار بزرگ ریاضیات مدرن است. آیا روزی کسی خواهد توانست آن را اثبات یا رد کند؟ یا شاید این مسئله برای همیشه حل‌نشده باقی بماند؟ تا آن زمان، ما می‌توانیم با آزمایش اعداد مختلف و نوشتن برنامه‌هایی مثل مثال بالا، از زیبایی و رمز و راز این دنباله لذت ببریم. اگر به ریاضیات یا برنامه‌نویسی علاقه دارید، پیشنهاد می‌کنم خودتان چند عدد را امتحان کنید و ببینید که آیا می‌توانید الگویی جدید کشف کنید!
  18. sina
    زبان برنامه‌نویسی Rust به خاطر ویژگی‌های منحصربه‌فردش مثل ایمنی حافظه و عملکرد بالا، حسابی سر زبون‌ها افتاده. یکی از مفاهیم کلیدی که Rust رو از بقیه زبان‌ها متمایز می‌کنه، چیزیه به اسم Lifetime (طول عمر). اگه تازه با Rust آشنا شدید یا می‌خواهید عمیق‌تر این زبون رو بشناسید، این مقاله قراره شما رو با این مفهوم مهم آشنا کنه و نشون بده چرا توی نوشتن کدهای امن و کارآمد انقدر نقش داره. پس بیاید با هم وارد این موضوع بشیم و ببینیم Lifetime چیه، چرا مهمه و چطور توی عمل کار می‌کنه. Lifetime دقیقاً چیه؟توی Rust، وقتی از Lifetime صحبت می‌کنیم، داریم به یه قانون اساسی اشاره می‌کنیم که به مدیریت حافظه ربط داره. به زبان ساده، Lifetime مشخص می‌کنه که یه مرجع (Reference) توی کدتون تا چه زمانی معتبره و می‌تونید ازش استفاده کنید. مرجع همون چیزیه که با علامت & توی کد نشون داده می‌شه، مثل &x که به یه متغیر یا داده اشاره می‌کنه بدون اینکه مالکیتش رو بگیره. Rust با این سیستم مطمئن می‌شه که هیچ‌وقت به داده‌ای که دیگه توی حافظه وجود نداره (مثلاً پاک شده) اشاره نکنید. این کار از خطاهایی مثل Dangling Pointer (اشاره‌گر معلق) جلوگیری می‌کنه که توی زبان‌هایی مثل C یا C++ خیلی دردسرسازن. به عبارت دیگه، Lifetime مثل یه نگهبان هوشمنده که نمی‌ذاره کدتون به جاهای خطرناک حافظه سرک بکشه. چرا Lifetime انقدر توی Rust مهمه؟بیاید یه لحظه به این فکر کنیم که چرا Rust همچین سیستمی رو طراحی کرده. توی زبان‌های برنامه‌نویسی دیگه مثل Python یا Java، مدیریت حافظه معمولاً با یه Garbage Collector انجام می‌شه. این ابزار خودش می‌گرده و حافظه‌ای که دیگه لازم نیست رو آزاد می‌کنه. اما Rust راه دیگه‌ای رو انتخاب کرده: اینجا خبری از Garbage Collector نیست! در عوض، با قوانین سخت‌گیرانه‌ای مثل Ownership (مالکیت) و Lifetime، مدیریت حافظه رو توی زمان کامپایل انجام می‌ده. مزیتش چیه؟ اول اینکه برنامه‌هاتون سریع‌تر اجرا می‌شن چون سربار Garbage Collector رو ندارید. دوم اینکه خیلی از خطاهایی که توی زبونای دیگه موقع اجرا (Runtime) پیداشون می‌شه، توی Rust همون اول، موقع کامپایل، گیر می‌افتن. Lifetime اینجا نقشش پررنگ می‌شه چون تضمین می‌کنه هر مرجعی که استفاده می‌کنید، به داده‌ای اشاره داره که هنوز زنده‌ست. Lifetime توی کد چطور کار می‌کنه؟حالا بیاید یه نگاه عملی‌تر به موضوع بندازیم. توی Rust، Lifetime با یه علامت خاص به اسم Lifetime Annotation نشون داده می‌شه که معمولاً یه حرف مثل 'a یا 'b هست. این علامت به کامپایلر می‌گه که یه مرجع تا چه مدت معتبره و باید بهش توجه کنه. یه مثال ساده رو ببینیم: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }اینجا چی داریم؟ یه تابع به اسم longest که دو رشته (String) رو به‌عنوان مرجع می‌گیره و بلندترینش رو برمی‌گردونه. علامت 'a به کامپایلر می‌گه که مرجع خروجی تابع (یعنی چیزی که برگردونده می‌شه) باید به داده‌ای اشاره کنه که حداقل به اندازه کوتاه‌ترین Lifetime بین x و y زنده می‌مونه. اینجوری مطمئن می‌شیم خروجی همیشه به یه حافظه معتبر اشاره داره. اگه این 'a نبود، کامپایلر نمی‌تونست بفهمه که مرجع برگشتی تا کی قراره معتبر باشه و ممکن بود خطا بده یا بدتر، یه اشاره‌گر معلق بسازیم که به داده پاک‌شده اشاره کنه. یه مثال پیچیده‌تر: Lifetime توی ساختارهافرض کنید یه ساختار (Struct) دارید که داخلش یه مرجع هست. توی Rust، وقتی یه مرجع توی یه ساختار استفاده می‌شه، باید Lifetime اون رو مشخص کنید. مثلاً: struct Book<'a> { title: &'a str, author: &'a str, } fn main() { let title = String::from("The Rust Journey"); let author = String::from("Jane Doe"); let book = Book { title: &title, author: &author, }; println!("{} by {}", book.title, book.author); }توی این کد، ساختار Book دو مرجع داره: title و author. علامت 'a به کامپایلر می‌گه که این مرجع‌ها به داده‌هایی اشاره می‌کنن که حداقل تا یه مدت مشخص (یعنی Lifetime 'a) توی حافظه زنده هستن. اگه title یا author قبل از استفاده از book از حافظه پاک بشن، کامپایلر خطا می‌ده و نمی‌ذاره کد اجرا بشه. انواع Lifetime و قوانینشتوی Rust، Lifetime‌ها همیشه به‌صورت دستی نوشته نمی‌شن. خیلی وقت‌ها کامپایلر خودش می‌تونه بفهمه که Lifetime چیه و نیازی به مشخص کردنش نیست. به این می‌گن Lifetime Elision. مثلاً توی این کد: fn first_word(s: &str) -> &str { s.split(' ').next().unwrap() }نیازی به نوشتن a' نیست چون کامپایلر می‌فهمه که مرجع خروجی به ورودی s وابسته‌ست و تا وقتی s زنده‌ست، خروجی هم معتبره. اما وقتی موضوع پیچیده‌تر می‌شه (مثل تابع longest یا ساختارها)، باید خودتون دست به کار بشید و Lifetime رو مشخص کنید. قانون اصلی اینه: هر مرجعی که برمی‌گردونید یا توی یه ساختار استفاده می‌کنید، باید به داده‌ای اشاره کنه که هنوز توی حافظه وجود داره. Lifetime و ایمنی حافظهیکی از بزرگ‌ترین مزیت‌های Lifetime اینه که جلوی خطاهای حافظه رو می‌گیره. مثلاً توی C، ممکنه یه اشاره‌گر به حافظه‌ای اشاره کنه که دیگه آزاد شده و برنامه‌تون کرش کنه. اما توی Rust، کامپایلر با چک کردن Lifetime‌ها مطمئن می‌شه که همچین چیزی اتفاق نیفته. این یعنی شما به‌عنوان برنامه‌نویس، خیالتون راحته که کدتون از نظر حافظه امن و قابل‌اعتماده. چطور Lifetime رو یاد بگیریم؟اگه تازه با Rust شروع کردید، ممکنه اولش Lifetime یه کم گیج‌کننده به نظر بیاد. اما نگران نباشید! با تمرین و نوشتن کد، کم‌کم دستتون میاد که کجا باید ازش استفاده کنید. یه راه خوب برای یادگیری اینه که با مثال‌های ساده شروع کنید و بعد سراغ پروژه‌های پیچیده‌تر برید. مثلاً یه تابع بنویسید که چند مرجع رو مدیریت می‌کنه و ببینید کامپایلر چه خطاهایی می‌ده. این خطاها بهترین معلم شما توی یادگیری Rust هستن! کاربرد Lifetime توی پروژه‌های واقعیLifetime فقط یه مفهوم تئوری نیست؛ توی دنیای واقعی هم حسابی به کار میاد. مثلاً فرض کنید دارید یه سرور وب با Rust می‌نویسید (مثل پروژه‌هایی که با فریم‌ورک Actix-Web ساخته می‌شن). توی همچین برنامه‌ای، مدیریت دقیق مرجع‌ها و حافظه خیلی مهمه تا سرور پایدار بمونه و کرش نکنه. Lifetime اینجا کمک می‌کنه که مطمئن بشید هیچ مرجعی به داده نامعتبر اشاره نمی‌کنه. یا مثلاً توی توسعه سیستم‌عامل‌ها (مثل پروژه Redox که با Rust نوشته شده)، جایی که عملکرد و ایمنی حرف اول رو می‌زنه، Lifetime یه ابزار قدرتمند برای کنترل حافظه‌ست. Lifetime توی Rust مثل یه سپر محافظه که نمی‌ذاره کدتون به دردسر بیفته. این سیستم نه‌تنها باعث می‌شه برنامه‌هاتون امن‌تر باشن، بلکه بهتون کنترل بیشتری روی منابع می‌ده و کمک می‌کنه کدی بنویسید که هم سریع باشه و هم قابل‌اعتماد. اگه دنبال زبانی هستید که بهتون قدرت و امنیت رو با هم بده، Rust و مفهوم Lifetime‌ش چیزیه که نباید ازش غافل بشید.
  19. sina
    در دنیای امروز که داده‌ها حرف اول رو می‌زنن، توانایی استخراج اطلاعات از وب یه مهارت فوق‌العاده ارزشمنده. چه بخواهید قیمت محصولات یه فروشگاه آنلاین رو جمع‌آوری کنید، چه اخبار رو تحلیل کنید یا داده‌های تحقیقاتی رو از سایت‌ها بکشید بیرون، وب‌اسکرپینگ (Web Scraping) راه‌حل شماست. توی این مقاله قراره با وب‌اسکرپینگ، ابزارهای پایتون برای این کار و مراحل انجامش آشنا بشید. اگه به پایتون و داده علاقه دارید، تا آخر با من همراه باشید! وب‌اسکرپینگ چیه؟وب‌اسکرپینگ به فرآیند خودکار جمع‌آوری داده‌ها از صفحات وب گفته می‌شه. به جای اینکه دستی برید و اطلاعات رو کپی کنید، یه برنامه می‌نویسید که این کار رو براتون انجام بده. پایتون به خاطر سادگی، کتابخانه‌های قدرتمند و انعطاف‌پذیریش، یکی از بهترین زبان‌ها برای وب‌اسکرپینگه. چرا پایتون؟کتابخانه‌های آماده: ابزارهایی مثل Beautiful Soup، Requests و Scrapy کار رو خیلی راحت می‌کنن. خوانایی کد: حتی اگه تازه‌کار باشید، می‌تونید با چند خط کد شروع کنید. جامعه بزرگ: هر سوالی داشته باشید، جوابش توی انجمن‌های پایتون پیدا می‌شه. ابزارهای اصلی وب‌اسکرپینگ با پایتونبیاید با چند ابزار کلیدی که توی این مسیر نیاز دارید آشنا بشیم: Requests: برای ارسال درخواست HTTP و دریافت محتوای صفحه وب. Beautiful Soup: برای تجزیه (parse) کردن HTML و پیدا کردن داده‌های مورد نظر. Scrapy: یه فریم‌ورک کامل برای پروژه‌های بزرگ‌تر و پیچیده‌تر (اختیاری). یه مثال ساده: استخراج عنوان صفحهبیاید با یه مثال عملی شروع کنیم. فرض کنید می‌خواهیم عنوان یه صفحه وب رو بگیریم: import requests from bs4 import BeautifulSoup # آدرس صفحه‌ای که می‌خواهیم اسکرپ کنیم url = "https://example.com" # درخواست به صفحه response = requests.get(url) # چک کردن اینکه درخواست موفق بوده if response.status_code == 200: # تجزیه HTML soup = BeautifulSoup(response.text, "html.parser") # پیدا کردن تگ عنوان title = soup.find("title").text print(f"عنوان صفحه: {title}") else: print("خطا در اتصال به صفحه")خروجی چیزی شبیه اینه: عنوان صفحه: Example Domainاینجا با requests محتوای صفحه رو گرفتیم و با BeautifulSoup تگ <title> رو پیدا کردیم. ساده بود، نه؟ مراحل وب‌اسکرپینگبرای یه پروژه وب‌اسکرپینگ موفق، این مراحل رو دنبال کنید: شناسایی هدف: اول مشخص کنید چه داده‌ای می‌خواهید (مثلاً قیمت‌ها، نظرات کاربران، یا لینک‌ها). بررسی ساختار صفحه: ابزار توسعه‌دهنده مرورگر (Inspector) رو باز کنید و HTML صفحه رو نگاه کنید تا بفهمید داده‌ها کجا هستن. نوشتن کد: با پایتون درخواست بفرستید و داده‌ها رو استخراج کنید. ذخیره داده‌ها: اطلاعات رو توی فایل CSV، JSON یا دیتابیس ذخیره کنید. اتوماسیون (اختیاری): اگه نیازه، کدتون رو طوری تنظیم کنید کi (مثلاً روزانه) اجرا بشه. یه پروژه واقعی: استخراج قیمت محصولاتفرض کنید می‌خواهید قیمت یه محصول رو از یه سایت فروشگاهی بکشید بیرون: import requests from bs4 import BeautifulSoup url = "https://fake-shop.com/product/sample" # آدرس فرضی response = requests.get(url) if response.status_code == 200: soup = BeautifulSoup(response.text, "html.parser") price = soup.find("span", class_="price").text # فرض بر اینکه قیمت توی این تگ هست print(f"قیمت محصول: {price}") else: print("اتصال ناموفق")توی این کد، ما دنبال تگ <span> با کلاس price گشتیم. اگه سایت واقعی باشه، باید کلاس یا تگ دقیق رو از HTMLش پیدا کنید. نکات مهم و چالش‌هاوب‌اسکرپینگ به همین سادگیا هم نیست! یه سری نکته و چالش هست که باید حواستون باشه: قوانین سایت: قبل از اسکرپ کردن، فایل robots.txt سایت رو چک کنید و مطمئن شید که اجازه این کار رو دارید. بعضی سایت‌ها اسکرپینگ رو ممنوع کردن. بلاک شدن: اگه درخواست‌های زیادی بفرستید، ممکنه IPتون بلاک بشه. برای این کار می‌تونید از تأخیر (delay) بین درخواست‌ها یا پراکسی استفاده کنید. تغییر ساختار سایت: اگه سایت HTMLش رو عوض کنه، کدهاتون ممکنه خراب بشه. باید آماده به‌روزرسانی باشید. داده‌های پویا: بعضی سایت‌ها با جاوا اسکریپت لود می‌شن. توی این موارد، ابزارهایی مثل Selenium یا Playwright که مرورگر رو شبیه‌سازی می‌کنن، به کارتون میاد. ذخیره داده‌ها توی فایلبعد از استخراج، می‌تونید داده‌ها رو توی یه فایل CSV ذخیره کنید: import csv data = {"title": "محصول نمونه", "price": "100,000 تومان"} with open("products.csv", "w", newline="", encoding="utf-8") as file: writer = csv.DictWriter(file, fieldnames=["title", "price"]) writer.writeheader() writer.writerow(data)حالا داده‌هاتون توی یه فایل مرتب ذخیره شدن! چرا وب‌اسکرپینگ یاد بگیریم؟تحلیل بازار: قیمت‌ها و محصولات رقبا رو مقایسه کنید. تحقیقات: داده‌های علمی یا خبری رو جمع‌آوری کنید. اتوماسیون: کارای تکراری مثل چک کردن موجودی انبار رو خودکار کنید. جمع‌بندیوب‌اسکرپینگ با پایتون یه مهارت قدرتمنده که با چند خط کد ساده شروع می‌شه، اما می‌تونه به پروژه‌های پیچیده و حرفه‌ای تبدیل بشه. ابزارهایی مثل Requests و Beautiful Soup نقطه شروع عالی‌ای هستن و اگه بخواهید حرفه‌ای‌تر بشید، می‌تونید سراغ Scrapy یا Selenium برید. فقط یادتون باشه با مسئولیت‌پذیری و رعایت قوانین پیش برید.
  20. sina
    زبان برنامه‌نویسی Rust به دلیل رویکرد نوآورانه‌اش در مدیریت حافظه و ایمنی کد، در سال‌های اخیر توجه بسیاری از توسعه‌دهندگان را به خود جلب کرده است. یکی از مهم‌ترین ویژگی‌های این زبان که آن را از رقبا متمایز می‌کند، سیستم Ownership (مالکیت) و Borrowing (امانت‌دهی) است. در این مقاله، به صورت عمیق و پیشرفته به این مفاهیم می‌پردازم، نحوه کارکرد آن‌ها را بررسی می‌کنیم و نشان می‌دهیم که چرا این قابلیت‌ها، Rust را به انتخابی ایده‌آل برای پروژه‌های پیچیده و حساس تبدیل کرده‌اند. اگر به دنبال یادگیری پیشرفته Rust یا بهبود مهارت‌های برنامه‌نویسی خود هستید، تا انتها همراه من باشید. Ownership در Rust چیست و چرا اهمیت دارد؟در هسته زبان Rust، مفهومی به نام Ownership قرار دارد که به معنای مالکیت داده‌ها توسط یک متغیر خاص است. هر تکه داده در حافظه فقط یک صاحب دارد و وقتی این صاحب از دسترس خارج شود (مثلاً با پایان یافتن محدوده یا scope)، حافظه به صورت خودکار آزاد می‌شود. این مکانیزم بدون نیاز به Garbage Collector عمل می‌کند و به همین دلیل، Rust عملکردی نزدیک به زبان‌هایی مثل C++ ارائه می‌دهد، اما با ایمنی بیشتر. برای مثال، کد زیر را در نظر بگیرید: fn main() { let s = String::from("Hello, Rust"); println!("{}", s); } // حافظه متعلق به s اینجا آزاد می‌شوداین سیستم ساده به نظر می‌رسد، اما وقتی بحث انتقال مالکیت (Move) پیش می‌آید، قدرت واقعی آن مشخص می‌شود. انتقال مالکیت (Move) و جلوگیری از خطاهای حافظهدر Rust، وقتی یک متغیر به متغیر دیگری اختصاص داده می‌شود، مالکیت داده منتقل می‌شود و متغیر اولیه دیگر معتبر نیست. این رفتار که به Move معروف است، از دسترسی همزمان چند متغیر به یک حافظه جلوگیری می‌کند و خطاهایی مثل dangling pointer یا double free را حذف می‌کند. مثال زیر این موضوع را روشن‌تر می‌کند: fn main() { let s1 = String::from("Rust"); let s2 = s1; // مالکیت به s2 منتقل می‌شود // println!("{}", s1); // خطا: s1 دیگر معتبر نیست println!("{}", s2); // خروجی: Rust }این قانون سخت‌گیرانه تضمین می‌کند که در هر لحظه فقط یک متغیر کنترل داده را در اختیار داشته باشد، که برای برنامه‌نویسی امن و بدون باگ حیاتی است. Borrowing: انعطاف‌پذیری در کنار امنیتگاهی اوقات نیازی به انتقال مالکیت نیست و فقط می‌خواهید به داده دسترسی پیدا کنید یا آن را تغییر دهید. اینجا Borrowing وارد میدان می‌شود. Rust دو نوع امانت‌دهی ارائه می‌دهد: Reference غیرقابل تغییر (&): امکان خواندن داده بدون تغییر آن. Reference قابل تغییر (&mut): امکان تغییر داده با رعایت قوانین ایمنی. مثال: fn main() { let mut s = String::from("Hello"); let r1 = &s; // امانت غیرقابل تغییر println!("Reference: {}", r1); let r2 = &mut s; // امانت قابل تغییر r2.push_str(", Rust!"); println!("Updated: {}", s); // خروجی: Hello, Rust! }قانون کلیدی Borrowing در Rust این است: می‌توانید چندین امانت غیرقابل تغییر داشته باشید، اما فقط یک امانت قابل تغییر در هر لحظه مجاز است و این دو نمی‌توانند همزمان وجود داشته باشند. این محدودیت از Data Race (رقابت داده) جلوگیری می‌کند و ایمنی را تضمین می‌کند. کاربرد Ownership و Borrowing در برنامه‌نویسی چندنخییکی از حوزه‌هایی که این سیستم واقعاً می‌درخشد، برنامه‌نویسی چندنخی (multi-threaded) است. در زبان‌های سنتی مثل C++، مدیریت دسترسی thread ها به داده‌های مشترک نیازمند استفاده از قفل‌ها (locks) و هماهنگی دستی است. اما Rust با قوانین Ownership و ابزارهایی مثل Arc و Mutex، این پیچیدگی را به حداقل می‌رساند. مثال پیشرفته: use std::sync::{Arc, Mutex}; use std::thread; fn main() { let data = Arc::new(Mutex::new(vec![1, 2, 3])); let mut threads = vec![]; for i in 0..3 { let data = Arc::clone(&data); threads.push(thread::spawn(move || { let mut num = data.lock().unwrap(); num.push(i); println!("Thread {}: {:?}", i, num); })); } for t in threads { t.join().unwrap(); } }در این کد، Arc (Atomic Reference Counting) امکان اشتراک داده بین thread ها را فراهم می‌کند و Mutex تضمین می‌کند که فقط یک thread در لحظه به داده دسترسی تغییرپذیر داشته باشد. نتیجه؟ کدی امن، بدون Data Race و با عملکرد بالا. مزایای استفاده از Ownership و Borrowing در Rustایمنی حافظه: حذف خطاهای رایج مثل استفاده از اشاره‌گرهای نامعتبر. عملکرد بهینه: عدم نیاز به Garbage Collector و مدیریت دستی حافظه. کنترل دقیق: توسعه‌دهنده با قوانین مشخص، کنترل بهتری بر رفتار برنامه دارد. البته، این سیستم در ابتدا ممکن است برای برنامه‌نویسان تازه‌کار چالش‌برانگیز باشد، اما با تسلط بر آن، می‌توانید پروژه‌هایی پایدار و قابل اعتماد بسازید.
  21. sina
    sina پاسخی ارسال کرد برای یک مطلب در برنامه نویسی
    زبان برنامه‌نویسی C به عنوان یکی از پایه‌ای‌ترین و قدرتمندترین زبان‌های برنامه‌نویسی شناخته می‌شه که هنوز هم در توسعه سیستم‌عامل‌ها، نرم‌افزارهای Embedded و برنامه‌های با کارایی بالا حرف اول رو می‌زنه. یکی از قابلیت‌های خاص و برجسته این زبان، مدیریت دستی حافظه هست که به برنامه‌نویس اجازه می‌ده به طور مستقیم کنترل کاملی روی تخصیص و آزادسازی حافظه داشته باشه. این ویژگی، هم یه مزیت بزرگه و هم یه چالش مهم که درک عمیقش برای هر برنامه‌نویس C ضروریه. مدیریت دستی حافظه چیه؟در C، برخلاف زبان‌های مدرن‌تر مثل Java یا Python که از Garbage Collector برای مدیریت خودکار حافظه استفاده می‌کنن، برنامه‌نویس خودش مسئول تخصیص و آزادسازی حافظه‌ست. این کار با استفاده از توابعی مثل malloc()، calloc()، realloc() و free() انجام می‌شه. به عنوان مثال، وقتی نیاز به یه آرایه پویا دارید، می‌تونید با malloc() حافظه مورد نیاز رو تخصیص بدید و بعد از استفاده، با free() اون رو آزاد کنید. این کنترل دستی به شما اجازه می‌ده دقیقاً بفهمید چه مقدار حافظه در چه زمانی استفاده می‌شه و کی آزاد می‌شه. چرا این قابلیت خاصه؟مدیریت دستی حافظه به برنامه‌نویس قدرت بی‌نظیری می‌ده. اول اینکه، بهینه‌سازی عملکرد برنامه‌ها در C خیلی بهتر از زبان‌هایی با مدیریت خودکار حافظه‌ست. چون هیچ پروسه اضافی مثل Garbage Collection وجود نداره که به صورت غیرقابل پیش‌بینی اجرا بشه و منابع سیستم رو مصرف کنه. این ویژگی برای برنامه‌هایی که نیاز به سرعت بالا دارن، مثل سیستم‌عامل‌ها یا بازی‌های ویدیویی، حیاتیه. دوم اینکه، شما می‌تونید حافظه رو دقیقاً به شکلی که نیاز دارید مدیریت کنید؛ مثلاً یه ساختار داده پیچیده بسازید و فقط همون مقدار حافظه‌ای که لازمه رو تخصیص بدید. مثال عملیفرض کنید می‌خواید یه لیست پویا از اعداد بسازید. در C، می‌تونید این کار رو با یه اشاره‌گر و تخصیص حافظه انجام بدید: #include <stdio.h> #include <stdlib.h> int main() { int *numbers; int size = 5; numbers = (int *)malloc(size * sizeof(int)); // تخصیص حافظه برای 5 عدد if (numbers == NULL) { printf("خطا در تخصیص حافظه!\n"); return 1; } for (int i = 0; i < size; i++) { numbers[i] = i + 1; } for (int i = 0; i < size; i++) { printf("%d ", numbers[i]); } free(numbers); // آزادسازی حافظه return 0; }این کد نشون می‌ده که چطور حافظه تخصیص داده می‌شه، استفاده می‌شه و بعد آزاد می‌شه. اگه free() رو فراموش کنید، با مشکل Memory Leak مواجه می‌شید که حافظه به طور بیهوده اشغال می‌مونه. چالش‌ها و مسئولیت‌هابا این همه قدرت، یه مسئولیت بزرگ هم میاد. مدیریت نادرست حافظه می‌تونه به مشکلاتی مثل Memory Leak، Dangling Pointers (اشاره‌گرهایی که به حافظه آزادشده اشاره می‌کنن) یا Segmentation Fault منجر بشه. برای همین، برنامه‌نویس باید دقت زیادی داشته باشه و همیشه مطمئن بشه که هر حافظه‌ای که تخصیص داده، در زمان مناسب آزاد می‌شه. نتیجه‌گیریمدیریت دستی حافظه در C مثل یه شمشیر دو لبه‌ست: هم قدرت فوق‌العاده‌ای به برنامه‌نویس می‌ده و هم نیاز به دقت و مهارت داره. این قابلیت باعث شده C همچنان انتخاب اول برای پروژه‌هایی باشه که نیاز به کنترل سطح پایین و بهینه‌سازی دقیق دارن. اگه دنبال زبانی هستید که شما رو مجبور کنه عمیق‌تر به عملکرد سیستم فکر کنید و در عین حال انعطاف‌پذیری بالایی بهتون بده، C و مدیریت دستی حافظه‌ش یه گزینه بی‌رقیبه.
  22. sina
    sina پاسخی ارسال کرد برای یک مطلب در هوش مصنوعی
    در دنیای هوش مصنوعی و یادگیری ماشین، اصطلاحاتی مثل "یادگیری نظارت‌شده" یا "Supervised Learning" بارها به گوشمون می‌خوره. اما واقعاً این مفهوم چیه و چرا انقدر مهمه؟ توی این مقاله قراره به زبانی ساده و با مثال‌های ملموس، یادگیری نظارت‌شده رو توضیح بدیم، کاربردهاش رو بررسی کنیم و ببینیم چطور توی زندگی روزمره ما اثر می‌ذاره. پس اگه به دنیای تکنولوژی و داده‌ها علاقه دارید، تا آخر این مقاله همراه من باشید! یادگیری نظارت‌شده چیست؟یادگیری نظارت‌شده یکی از شاخه‌های اصلی یادگیری ماشین (Machine Learning) هست که توی اون، یه مدل کامپیوتری با استفاده از داده‌های برچسب‌گذاری‌شده آموزش داده می‌شه. حالا "داده‌های برچسب‌گذاری‌شده" یعنی چی؟ فرض کنید می‌خواهید به یه بچه یاد بدید که گربه چیه. یه عالمه عکس بهش نشون می‌دید و می‌گید: "این گربه‌ست، این سگ، اینم پرنده." بعد از یه مدت، بچه یاد می‌گیره که خودش تشخیص بده چه حیوانی توی عکس هست. توی یادگیری نظارت‌شده هم همین اتفاق می‌افته: ما به مدل داده‌هایی می‌دیم که جواب درستشون (یا همون برچسب) مشخصه، و مدل با تمرین یاد می‌گیره که چطور الگوها رو تشخیص بده و پیش‌بینی کنه. به عبارت ساده‌تر، یادگیری نظارت‌شده مثل یه معلم سخت‌گیره که به شاگردش می‌گه: "این ورودی‌ها رو بگیر، این خروجی‌ها رو به خاطر بیار، و سعی کن دفعه بعد خودت درست حدس بزنی." این فرآیند شامل دو مرحله اصلیه: آموزش (Training) و آزمایش (Testing). اجزای اصلی یادگیری نظارت‌شدهبرای اینکه یادگیری نظارت‌شده درست کار کنه، چند جزء کلیدی داریم: داده‌های آموزشی (Training Data): این داده‌ها شامل ورودی‌ها (مثل ویژگی‌ها یا Features) و خروجی‌های مرتبط (برچسب‌ها یا Labels) هستن. مثلاً اگه بخوایم یه مدل برای تشخیص ایمیل‌های اسپم بسازیم، داده‌های آموزشی شامل متن ایمیل‌ها (ورودی) و برچسب "اسپم" یا "غیراسپم" (خروجی) می‌شه. مدل (Model): مدل مثل یه مغز مصنوعیه که قراره یاد بگیره. این می‌تونه یه الگوریتم ساده مثل رگرسیون خطی باشه یا یه چیز پیچیده‌تر مثل شبکه‌های عصبی. تابع هزینه (Loss Function): این تابع به مدل می‌گه چقدر پیش‌بینیش با جواب درست فاصله داره. هدف اینه که این خطا رو کم کنیم. الگوریتم بهینه‌سازی: این بخش مدل رو تنظیم می‌کنه تا خطاهاش کمتر بشه. مثلاً الگوریتم گرادیان نزولی (Gradient Descent) یکی از روش‌های معروفه. انواع مسائل در یادگیری نظارت‌شدهیادگیری نظارت‌شده معمولاً به دو دسته اصلی تقسیم می‌شه: رگرسیون (Regression): وقتی خروجی یه مقدار پیوسته (عدد) باشه، مثل پیش‌بینی قیمت خونه یا دمای هوا. مثلاً فرض کنید می‌خواهید با توجه به متراژ خونه و محله‌ش، قیمتش رو حدس بزنید. اینجا از الگوریتم‌های رگرسیون مثل رگرسیون خطی استفاده می‌شه. طبقه‌بندی (Classification): وقتی خروجی یه دسته یا کلاس مشخص باشه، مثل تشخیص اینکه یه ایمیل اسپمه یا نه، یا اینکه یه عکس گربه‌ست یا سگ. الگوریتم‌هایی مثل رگرسیون لجستیک، ماشین بردار پشتیبان (SVM) یا درخت تصمیم توی این مسائل خیلی کاربرد دارن. چطور یادگیری نظارت‌شده کار می‌کنه؟بیاید با یه مثال ساده این فرآیند رو مرور کنیم. فرض کنید می‌خواهید یه مدل بسازید که تشخیص بده یه میوه سیبه یا پرتقاله. مراحل کار اینجوریه: جمع‌آوری داده: یه مجموعه داده درست می‌کنید که شامل ویژگی‌های میوه‌ها (مثل رنگ، اندازه، وزن) و برچسبشون (سیب یا پرتقال) باشه. آموزش مدل: این داده‌ها رو به مدل می‌دید و ازش می‌خواهید الگوها رو پیدا کنه. مثلاً یاد می‌گیره که میوه‌های نارنجی‌رنگ و سنگین‌تر معمولاً پرتقالن. ارزیابی مدل: یه سری داده جدید (که مدل قبلاً ندیده) بهش می‌دید و می‌بینید چقدر درست پیش‌بینی می‌کنه. بهبود مدل: اگه خطاهاش زیاد باشه، پارامترهاش رو تنظیم می‌کنید یا داده‌های بیشتری بهش می‌دید. در نهایت، مدلتون آماده‌ست که میوه‌های جدید رو با دقت خوبی تشخیص بده! الگوریتم‌های معروف در یادگیری نظارت‌شدهحالا که با کلیات آشنا شدیم، بیاید چندتا از الگوریتم‌های معروف رو بشناسیم: رگرسیون خطی (Linear Regression): برای پیش‌بینی مقادیر عددی مثل قیمت یا دما. رگرسیون لجستیک (Logistic Regression): برای مسائل طبقه‌بندی مثل تشخیص اسپم. درخت تصمیم (Decision Tree): یه مدل درختی که تصمیم‌گیری رو مرحله به مرحله انجام می‌ده. ماشین بردار پشتیبان (SVM): برای پیدا کردن بهترین خط یا صفحه جداکننده بین کلاس‌ها. شبکه‌های عصبی (Neural Networks): برای مسائل پیچیده‌تر مثل تشخیص تصویر یا صدا. هر کدوم از این الگوریتم‌ها مزایا و معایب خودشون رو دارن و بسته به نوع مسئله و داده‌ها انتخاب می‌شن. کاربردهای یادگیری نظارت‌شدهیادگیری نظارت‌شده توی زندگی روزمره ما خیلی بیشتر از چیزی که فکر می‌کنید حضور داره. چندتا مثال جالب: تشخیص اسپم: ایمیل‌هاتون رو فیلتر می‌کنه تا از شر تبلیغات مزاحم خلاص بشید. تشخیص چهره: توی گوشی‌تون یا دوربین‌های امنیتی استفاده می‌شه. پیش‌بینی آب‌وهوا: دما و بارندگی رو با دقت پیش‌بینی می‌کنه. تشخیص بیماری: با تحلیل داده‌های پزشکی، می‌تونه بیماری‌ها رو زود تشخیص بده. ماشین‌های خودران: برای تشخیص علائم رانندگی و عابرین پیاده. مزایا و معایب یادگیری نظارت‌شدهمثل هر تکنولوژی دیگه‌ای، یادگیری نظارت‌شده هم نقاط قوت و ضعف خودش رو داره: مزایا: دقت بالا وقتی داده‌های برچسب‌گذاری‌شده باکیفیت داریم. قابل فهم و قابل اعتماد برای مسائل مشخص. کاربرد گسترده توی صنعت و علم. معایب: نیاز به داده‌های برچسب‌گذاری‌شده داره که گاهی جمع‌آوریش گرون و زمان‌بره. اگه داده‌ها ناقص یا اشتباه باشن، مدل هم اشتباه یاد می‌گیره. برای مسائل خیلی پیچیده ممکنه به اندازه روش‌های دیگه (مثل یادگیری عمیق) انعطاف‌پذیر نباشه. تفاوت یادگیری نظارت‌شده با یادگیری بدون نظارتیه سوال رایج اینه که یادگیری نظارت‌شده چه فرقی با یادگیری بدون نظارت (Unsupervised Learning) داره؟ توی یادگیری بدون نظارت، ما برچسب نداریم و مدل خودش باید الگوها رو پیدا کنه. مثلاً فرض کنید یه عالمه عکس میوه دارید، ولی نمی‌دونید کدوم سیبه و کدوم پرتقاله. مدل بدون نظارت می‌تونه میوه‌ها رو بر اساس شباهت‌هاشون گروه‌بندی کنه، ولی نمی‌تونه بگه "این سیبه." برای همین، یادگیری نظارت‌شده برای وقتی مناسبه که جواب درست رو از قبل داریم و می‌خواهیم پیش‌بینی دقیق انجام بدیم. آینده یادگیری نظارت‌شدهبا پیشرفت تکنولوژی و افزایش قدرت محاسباتی، یادگیری نظارت‌شده داره هر روز قوی‌تر می‌شه. ترکیبش با روش‌های دیگه مثل یادگیری عمیق (Deep Learning) باعث شده که توی حوزه‌هایی مثل پزشکی، خودروسازی و حتی هنر، تحولات بزرگی ایجاد بشه. اما چالش‌هایی مثل نیاز به داده‌های زیاد و مسائل اخلاقی (مثل سوگیری توی داده‌ها) هنوز باید حل بشن. نتیجه‌گیرییادگیری نظارت‌شده مثل یه ابزار جادویی توی جعبه ابزار هوش مصنوعیه. با دادن داده‌های درست و یه مدل مناسب، می‌تونیم مسائل پیچیده رو حل کنیم و زندگی‌مون رو بهتر کنیم. از تشخیص اسپم توی ایمیل گرفته تا پیش‌بینی قیمت خونه، این روش توی هر گوشه از دنیای مدرن ما حضور داره. اگه به یادگیری ماشین علاقه دارید، یادگیری نظارت‌شده یه نقطه شروع عالیه.
  23. sina
    در دنیای برنامه‌نویسی، گاهی نیاز داریم با اعدادی کار کنیم که از حد معمول بزرگ‌تر یا پیچیده‌تر هستند. مثلاً اعداد بسیار بزرگ در رمزنگاری، محاسبات ریاضی پیشرفته یا حتی مسائل علمی. زبان برنامه‌نویسی PHP به‌صورت پیش‌فرض برای کار با اعداد معمولی طراحی شده، اما وقتی پای اعداد بزرگ یا محاسبات دقیق به میان میاد، نیاز به ابزاری قوی‌تر احساس می‌شه. اینجا GMP (مخفف GNU Multiple Precision) وارد صحنه می‌شه. تو این مقاله قراره به‌طور کامل با GMP در PHP آشنا بشیم، کاربردهاش رو بررسی کنیم و ببینیم چطور می‌تونیم ازش استفاده کنیم. GMP چیه و چرا مهمه؟GMP یه کتابخونه متن‌باز (open-source) هست که برای انجام محاسبات دقیق روی اعداد بزرگ و اعداد صحیح با دقت بالا طراحی شده. این کتابخونه ابتدا به زبان C نوشته شده، اما PHP از طریق افزونه‌ای به نام GMP (که باید نصب بشه) این امکان رو به برنامه‌نویسا می‌ده که از قابلیت‌هاش استفاده کنن. فرق اصلی GMP با روش‌های معمولی PHP اینه که محدودیت‌های اعداد صحیح یا اعشاری رو دور می‌زنه و اجازه می‌ده با اعدادی کار کنیم که شاید صدها یا هزاران رقم داشته باشن. تو PHP، اعداد صحیح (integer) یه محدوده مشخص دارن (مثلاً در سیستم‌های ۶۴ بیتی از -2^63 تا 2^63-1). اگه بخواید یه عدد بزرگ‌تر از این محدوده رو محاسبه کنید، یا به مشکل سرریز (overflow) برمی‌خورید یا نتیجه‌تون دقیق نیست. GMP این مشکل رو حل می‌کنه و به شما اجازه می‌ده بدون نگرانی از محدودیت، محاسبات رو انجام بدید. نصب GMP در PHPبرای استفاده از GMP، اول باید مطمئن بشید که این افزونه روی سرورتون نصب شده باشه. اگه از PHP روی لینوکس استفاده می‌کنید، می‌تونید با دستور زیر GMP رو نصب کنید: sudo apt-get install php-gmpبعد از نصب، باید چک کنید که تو فایل php.ini فعال باشه. برای این کار، خط زیر رو تو فایل اضافه کنید یا مطمئن بشید که وجود داره: extension=gmpاگه سرور ویندوزی دارید، باید فایل DLL مربوط به GMP رو دانلود کنید و تو تنظیمات PHP فعالش کنید. بعد از ری‌استارت سرور، با اجرای تابع phpinfo() می‌تونید ببینید که GMP فعال شده یا نه. کار با GMP در PHPحالا که GMP رو نصب کردیم، بیایم چندتا از تابع‌های مهمش رو بررسی کنیم. GMP تو PHP به‌صورت شیءگرا (object-oriented) و رویه‌ای (procedural) قابل استفادست. تو این بخش چند مثال ساده می‌زنم که بتونید سریع دست به کد بشید. 1.جمع و تفریق اعداد بزرگ: فرض کنید می‌خواهیم دو عدد خیلی بزرگ رو جمع کنیم: $num1 = gmp_init("12345678901234567890"); $num2 = gmp_init("98765432109876543210"); $sum = gmp_add($num1, $num2); echo gmp_strval($sum); // خروجی: 111111111011111111100تابع gmp_init یه عدد بزرگ رو به فرمت GMP تبدیل می‌کنه. بعد با gmp_add جمع رو انجام می‌دیم و با gmp_strval نتیجه رو به رشته تبدیل می‌کنیم تا نمایش داده بشه. 2.ضرب و تقسیم: برای ضرب از gmp_mul و برای تقسیم از gmp_div استفاده می‌کنیم: $product = gmp_mul($num1, $num2); echo gmp_strval($product); // یه عدد خیلی بزرگ! 3.توان و ریشه: اگه بخواید یه عدد رو به توان برسونید، از gmp_pow استفاده کنید: $power = gmp_pow($num1, 3); // num1 به توان 3 echo gmp_strval($power); 4.مقایسه اعداد: برای مقایسه دو عدد بزرگ، تابع gmp_cmp به کار می‌ره: $result = gmp_cmp($num1, $num2); if ($result > 0) { echo "عدد اول بزرگ‌تره"; } elseif ($result < 0) { echo "عدد دوم بزرگ‌تره"; } else { echo "برابرن"; }کاربردهای GMPGMP فقط برای جمع و تفریق اعداد بزرگ نیست. تو زمینه‌های مختلفی مثل رمزنگاری (مثلاً الگوریتم RSA)، محاسبات علمی، و حتی بازی‌سازی که نیاز به دقت بالا داره، استفاده می‌شه. مثلاً تو RSA، شما باید با اعداد اول خیلی بزرگ کار کنید که GMP این کار رو راحت می‌کنه. مزایا و معایبمزایای GMP واضحه: دقت بالا، پشتیبانی از اعداد بزرگ، و انعطاف‌پذیری. اما یه سری معایب هم داره. مثلاً سرعتش نسبت به عملیات معمولی PHP کمتره، چون محاسبات پیچیده‌تری انجام می‌ده. همچنین نیاز به نصب جداگانه داره که ممکنه برای همه پروژه‌ها عملی نباشه. جمع‌بندیGMP تو PHP یه ابزار قدرتمنده که به برنامه‌نویسا اجازه می‌ده از محدودیت‌های اعداد معمولی عبور کنن و با خیال راحت محاسبات پیچیده انجام بدن. اگه تو پروژه‌تون نیاز به کار با اعداد بزرگ یا دقت بالا دارید، GMP می‌تونه بهترین دوستتون باشه. با نصب ساده و توابع کاربردی، این افزونه به شما کمک می‌کنه پروژه‌هاتون رو به سطح بالاتری ببرید.