به نظر میرسد کار با اعداد در PHP یک مفهوم بیاهمیت است، در حالی که میتواند کاملا کاربردی باشد. هر چند در ابتدا آسان به نظر میرسد، زیرا PHP تبدیل خودکار نوع را فراهم میکند. به عنوان مثال شما میتوانید یک مقدار صحیح به یک متغیر اختصاص دهید، در این صورت نوع آن متغیر یک عدد صحیح خواهد بود. در خط بعدی میتوانید یک رشته را به همان متغیر اختصاص دهید و نوع آن به یک رشته تغییر میکند. متأسفانه این تبدیل خودکار گاهی اوقات میتواند کد شما را خراب کند.
انواع زیادی برای مقادیر عددی نیز وجود دارد. در این آموزش راجع به اعداد integer و float در PHP و همچنین توابعی که میتوان برای تعیین نوع اعدادی که با آنها سر و کار داریم و تبدیل آنها به یکدیگر استفاده کرد، آشنا خواهید شد. همچنین یاد خواهید گرفت که چگونه اعداد صحیح و ممیز شناور را به رشتههای عددی و برعکس تبدیل کنید.
انواع مختلف اعداد در PHP
Integer
ابتداییترین نوع اعداد در PHP عدد صحیح است. همانطور که قبلا میدانید، اعداد صحیح اعدادی هستند که هیچ قسمت اعشاری ندارند. به عنوان مثال 2 یک عدد صحیح است و به همین ترتیب 235298 یا 235298- را نیز شامل میشود. از سوی دیگر 0/2 و 58/3 ممیز شناور هستند. بعدا در مورد آنها با جزئیات بیشتر صحبت خواهیم کرد.
نکته مهمی که باید به خاطر داشته باشید این است که اگر عددی دارای قسمت اعشاری نباشد، لازم نیست از نوع int مقداردهی شود. به عنوان مثال حاصل ضرب 16 در 5/2 دقیقا 40 میشود، اما نوع این نتیجه همچنان float خواهد بود. پس هنگامی که اعداد را ضرب میکنید، اگر حداقل یکی از عملوندها float باشد نتیجه نهایی هم از نوع float خواهد بود. فرقی نمیکند که عدد نهایی دارای قسمت اعشاری باشد یا خیر.
همچنین حداکثر مقدار ممکنی که یک عدد صحیح میتواند در سیستم شما داشته باشد را میتوان با استفاده از ثابت PHP_INT_MAX به دست آورد. مقداری بزرگتر از مقدار برگردانده شده توسط PHP_INT_MAX به عنوان یک float ذخیره میشود، حتی اگر شبیه یک عدد صحیح باشد.
به طور کلی انتظار میرود که حاصل ضرب دو متغیر از نوع int یک مقدار int باشد. اما در مورد یک عدد سرریز شده این مسئله درست نیست. ضرب پنج یا شش عدد مختلف میتواند به راحتی شما را از محدوده نوع int خارج کند. به عنوان مثال نتیجه 128 x 309 x 32 x 43 x 309 در سیستم من float در نظر گرفته میشود، زیرا از مقدار PHP_INT_MAX که 2147483647 است بیشتر به حساب میآید.
همچنین میتوانید از تابع is_int($value) برای بررسی اینکه آیا یک عدد از نوع صحیح است یا نه نیز استفاده کنید. دو عبارت از این تابع به نامهای is_integer($value) و is_long($value) وجود دارد که هر دوی آنها نتیجه یکسانی خواهند داشت.
Float
متداولترین نوع عددی که با آن سر و کار دارید، ممیز شناور است. بر خلاف اعداد صحیح که در اکثر موارد بدون اعشار بودند، تعدادی از نوع float را میتوان به روشهای مختلفی نشان داد. مثلا مقادیر 3.14، 12.0، 5.87E+10 و 3.56E-5 همگی ممیز شناور هستند.
هر زمان که اعداد اعشاری یا اعداد بسیار بزرگ به کار گرفته شوند، PHP به طور خودکار آنها را به نوع float تبدیل میکند. این معمولا میتواند اعداد را تا محدوده 1.7976931348623E+308 ذخیره نماید، هرچند به نوع پلتفرم مورد استفاده نیز بستگی دارد.
1.7976931348623E+308 ممکن است مقدار بسیار بزرگی به نظر برسد و اینطور هم هست، اما floatها حداکثر دقتی در حدود 14 رقم دارند. و هر عددی که ارقام بیشتری از آن داشته باشد، دقت خود را از دست میدهد. این بدان معناست که میتوانید تعداد بسیار زیادی را ذخیره کنید، اما نمیتوانید اطلاعات مربوط به مقدار دقیق آن را حفظ نمایید. با اینکه در بسیاری از موارد مقدار float تقریبی است.
دو تابع وجود دارد که میتواند برای تعیین اینکه آیا مقداری که با آن سر و کار دارید ممیز شناور است یا نه استفاده شود. این توابع ()is_float و ()is_double هستند. در واقع ()is_double فقط نام مستعار is_float است، بنابراین میتوانید از هر یک از آنها استفاده کرده و نتیجه یکسانی را بگیرید.
Infinity و NaN
دو نوع دیگر از مقادیر عددی وجود دارد که ممکن است هنگام نوشتن برنامههای مرتبط با ریاضیات با آنها مواجه شوید. این مقادیر infinity و NaN (Not a Number) هستند. هر دو نیاز به کمی توضیح دارند، زیرا با آنچه شما انتظار دارید متفاوتاند.
بینهایت در PHP با بینهایت در زندگی واقعی متفاوت است. در PHP هر مقدار عددی بالاتر از PHP_FLOAT_MAX تعیین شده در پلتفرم، بینهایت در نظر گرفته میشود. بنابراین 1.8e308 به شما خروجی float(INF) توسط ()var_dump میدهد. به علاوه با استفاده از توابع ()is_finite و ()is_infinite میتوانید بررسی کنید که آیا یک مقدار عددی متناهی است یا بینهایت.
به طور مشابه NaN مخفف Not a Number است، اما عددی بودن یا نبودن یک مقدار را بررسی نمیکند. مقدار NaN برای نتیجه عملیات ریاضی استفاده میشود که در ریاضیات امکان پذیر نیست. برای مثال log(-1)، NaN خواهد بود. علاوه بر این (5)acos هم NaN است. بنابراین با استفاده از تابع ()is_nan میتوانید بررسی کنید که آیا مقداری که توسط یک عملیات ریاضی برگردانده میشود عددی است یا خیر.
رشتههای عددی در PHP
همانطور که PHP به صورت پویا نوع اعداد مختلف را بر اساس نحوه استفاده یا تخصیص مقادیر آنها تغییر میدهد، همچنین میتواند مقدار رشتههای عددی مختلف را نیز برای تبدیل آنها به اعداد استنتاج کند.
تابع ()is_numeric میتواند به شما در تعیین این که آیا رشته یا متغیر واقعا عددی است یا نه کمک نماید. این تابع برای اعدادی که در قالب octal، binary یا hexadecimal نوشته شدهاند درست عمل میکند. همچنین اگر اعداد نمایی مانند +16.52e39 نوشته شوند، مقدار true برمیگردد.
بعد از ورژن PHP 7.0.0 وقتی یک رشته را به ()is_numeric میفرستید، فقط زمانی true را برمیگرداند که رشته از یک علامت اختیاری، چند رقم، یک اعشار اختیاری و یک قسمت نمایی اختیاری تشکیل شده باشد. این بدان معنی است یک رشته عددی که در قالب هگزادسیمال یا باینری نوشته شده است، از PHP 7.0.0 به بعد false را برمیگرداند.
PHP به طور ضمنی هر رشته عددی معتبری را در صورت نیاز به یک عدد ارسال میکند. مثالهای زیر میتواند به شما در درک بهتر این قضیه کمک کند.
<?php
$num = "3258712" + 12380;
// Output: int(3271092)
var_dump($num);
$num = "3258712" + "12380";
// Output: int(3271092)
var_dump($num);
$num = 3258712 + "12380";
// Output: int(3271092)
var_dump($num);
$num = 3258712 * "12380";
// Output: float(40342854560)
var_dump($num);
$num = 3258712 / "12380";
// Output: float(263.2239095315)
var_dump($num);
$num = 3258712 / "8";
// Output: int(407339)
var_dump($num);
$num = "53.9e4" + 10;
// Output: float(539010)
var_dump($num);
$num = "398.328" + 10;
// Output: float(408.328)
var_dump($num);
$num = "398328" + 0xfedd24;
// Output: int(17101084)
var_dump($num);
$num = 398328 + "0xfedd24";
// Output: int(398328)
var_dump($num);
?>
همانطور که میبینید، تمام رشتههای عددی معتبر قبل از انجام عملیات جمع یا سایر عملیات به مقادیر مربوطه تبدیل شدند. نوع num$ در پایان به مقدار نهایی آن بستگی دارد.
در آخرین مورد رشته هگزادسیمال "0xfedd24" به مقدار اعشاری خود تبدیل نمیشود، زیرا PHP 7 آن را یک رشته عددی معتبر در نظر نمیگیرد.
تبدیل رشتهها و اعشاریها به اعداد صحیح
هر از گاهی نیاز است که یک نوع مقدار عددی را به دیگری تبدیل کنید. PHP توابع و تکنیکهای مختلفی برای انجام این کار دارد. در بیشتر مواقع تبدیل به صورت ضمنی خواهد بود و شما لازم نیست نگران آن باشید. با این حال اگر مجبور به انجام تبدیل صریح باشید، تکنیکهای ذکر شده در اینجا قطعا کمک خواهند کرد.
برای تبدیل هر مقدار به عدد صحیح میتوانید از (int) یا (integer) استفاده کنید. در مورد اعشاریها هم مقادیر همیشه به سمت صفر گرد میشوند. راه دیگر برای تبدیل رشتهها و اعشاریها به اعداد صحیح، با کمک تابع ()intval است. هر دوی (int) و ()intval مشابه هم کار میکنند.
<?php
$float_a = 3598723.8258;
$int_cast = (int)$float_a;
// Output: 3598723
echo $int_cast;
$string_a = "98723.828";
$int_cast = (int)$string_a;
// Output: 98723
echo $int_cast;
$string_b = "987233498349834828";
$int_cast = (int)$string_b;
// Output: 2147483647 on a 32 Bit Machine
echo $int_cast;
// Output: 987233498349834828 on a 64 Bit Machine
echo $int_cast;
$float_b = 21474836473492789;
$int_cast = (int)$float_b;
// Output: -6507212
echo $int_cast;
?>
باید توجه داشته باشید که تبدیل رشتههای سرریز شده به اعداد صحیح، مقدار نهایی را روی حداکثر مقدار مجاز تنظیم میکند. با این حال تبدیل یک float که مقدار آن بیش از حداکثر مقدار صحیح مجاز باشد، باعث نوسان مقدار بین 2147483648- و 2147483647 میشود.
در شرایط خاص ممکن است لازم باشد بدون از دست دادن دقت، با اعداد بسیار بزرگ کنار بیایید. به عنوان مثال با استفاده از عملگر * نمیتوان نتیجه دقیقی از ضرب 987233498349834828 در 3487197512 به دست آورد. چرا که بعد از تبدیل به شما 3.4426781992086E+27 را میدهد. اما محاسبه پاسخ واقعی که 3442678199208600117812547936 است، نیاز به استفاده از کتابخانههایی مانند BCMath دارد. BCMath با ذخیره اعداد به عنوان رشته و انجام عملیات حسابی روی آنها به صورت دستی کار میکند. فقط به یاد داشته باشید که اگر از BCMath استفاده کنید، به جای اعداد int و float با رشتهها سر و کار خواهید داشت.
برخی از کتابخانهها از شما میخواهند که فقط اعدادی از نوع int را به متدهایشان ارسال کنید، اما ممکن است ناخواسته به آنها یک مقدار float بدهید. میتواند به این دلیل اتفاق بیفتد که مقدار مد نظر مانند یک int به نظر برسد، زیرا ممکن است دارای بخش اعشاری نباشد. اگر کتابخانه از تابعی مانند ()is_int برای بررسی اینکه آیا عدد ارسال شده از نوع صحیح است یا نه استفاده کند، به طور قطع منجر به خطا میشود. در چنین مواردی همیشه عاقلانه است که ابتدا آن عدد را با استفاده از (int) یا ()intval به عدد صحیح تبدیل کرده و سپس آن را به هر تابع یا متد کتابخانه ارسال نمایید.
یک مثال از زمانی که چنین شرایطی ممکن است ایجاد شود، این است که شما با توابع ریاضی مانند floor()، ()ceil و ... سر و کار دارید. ()floor و ()ceil همیشه یک float برمیگردانند، حتی اگر آنها را به int تبدیل کنید.
<?php
$int_a = 15*12;
// Output: int(180)
var_dump($int_a);
$num = floor($int_a);
// Output: float(180)
var_dump($num);
?>
یکی از مشکلات تبدیل floatها به اعداد صحیح این است که بخش اعشاری اعداد را از دست خواهید داد که ممکن است مطلوب نباشد. در چنین مواقعی میتوانید از توابعی مانند ()floor بهره گرفته و تنها زمانی عدد را به نوع int ارسال کنید که مقدار واقعی آن برابر با مقدار برگردانده شده توسط ()floor باشد.
<?php
$number = 16*2.5;
if(floor($number) == $number) {
$fraction->setNumerator((int)$number);
} else {
echo 'Did not set the numerator.';
doSomethingElse();
}
?>
فرض کنید کتابخانهای دارید که به شما امکان میدهد محاسبات کسری را انجام دهید، و هنگامی که عددی را به متد ()setNumerator آن ارسال میکنید استثناهایی ایجاد میشود. انواع عملیات ممکن است یک عدد را به نوع float تبدیل کند حتی اگر هنوز یک عدد صحیح در محدوده حداقل و حداکثر نوع int باشد. استفاده از چیزی مانند کد بالا به شما کمک میکند تا با چنین مواردی به راحتی برخورد کنید.
نکاتی برای کار با اعداد در PHP
اعداد میتوانند بینهایت بزرگ باشند، اما کامپیوترهای ما حافظه محدودی دارند. این میتواند هنگام کار با اعداد در یک زبان برنامهنویسی به مشکلاتی منجر شود.
مشکلات اعداد صحیح با اندازه ثابت
بزرگترین عددی که میتوانید به عنوان یک عدد صحیح استاندارد در یک ماشین 64 بیتی ذخیره کنید 9223372036854775807 است. هر محاسباتی با نتیجه بیشتر از آن را نمیتوان با اعداد صحیح ساده انجام داد و نیاز به راه حلهای دیگری دارد. این بدان معنی است که وقتی احتمال میرود نتیجه از این محدودیتها بالاتر است، نباید از اعداد صحیح معمولی استفاده کرد. یک گزینه برای اعداد بزرگتر استفاده از اعداد ممیز شناور است. هر چند آنها هم مشکلات خاص خود را دارند.
مشکلات اعداد ممیز شناور
اعداد ممیز شناور برای محاسبات روزمره بسیار رایج هستند. با این حال هر کاری که با اعداد انجام میدهید که به مقایسه آنها مربوط باشد، میتواند منجر به مشکلات شود. به این دلیل است که اعداد ممیز شناور دقت محدودی دارند، بنابراین مقایسه بین آنها همیشه مطلوب نیست. همچنین کامپیوترها سیستمهای باینری هستند ولی سیستمهای اعداد ما اعشاری است، بنابراین تبدیل بین آنها همیشه دقیق نخواهد بود. به عنوان مثال 1/0 نمیتواند دقیقا به صورت باینری نمایش داده شود، به طور مشابه 1/3 را نیز نمیتوان دقیقا در تعداد ثابتی از ارقام اعشاری نشان داد و همیشه مقداری از دست دادن دقت وجود دارد.
برای برنامههایی مانند رندر گرافیکی یا بازی، این از دست دادن دقت مشکلی به وجود نمیآورد. اما برای برنامههای بانکی یا تجارت الکترونیک میتواند مشکلات عمدهای ایجاد کند. یکی از راههای جلوگیری از این خطا، تبدیل اعدادی که با آنها کار میکنید به اعداد صحیح است. به عنوان مثال هر چیزی که 01/12 دلار قیمت دارد را میتوان با اعداد صحیح به صورت 1201 سنت ذخیره کرد. پس در مواقعی که دقت لازم است، همیشه به جای استفاده از ممیز شناور از اعداد صحیح معمولی استفاده کنید.
اعداد نامحدود
بهترین راه برای دور زدن محدودیت های ذکر شده در دو نکته بالا، ذخیره اعداد به صورت رشته است. یک کتابخانه دلخواه مانند BCMath در PHP میتواند در این مورد به شما کمک کند. این دارای بسیاری از توابع مفید است که جمع، تفریق، تقسیم و ضرب اعداد بسیار بزرگ را بدون از دست دادن دقت برای شما آسانتر میکند.
<?php
// Output: 3072022.352153
echo pow(145.37, 3);
// Output: 3072022.352153
echo bcpow('145.37', '3', 6);
// Output: 3072022.35215300000000000000
echo bcpow('145.37', '3', 20);
// Output: 7.485894688036E+64
echo pow(145.37, 30);
// Output: 74858946880359568408424850947105278367228015491111279108371943756.809526
echo bcpow('145.37', '30', 6);
// Output: 74858946880359568408424850947105278367228015491111279108371943756.809526310877954976795991720196399964284058833429514016256049
echo bcpow('145.37', '30', 60);
?>
همانطور که میبینید، تابع ()bcpow میتواند دقت را روی مقدار دلخواه تعریف شده توسط پارامتر سوم تنظیم نماید.
البته این روش نیز مشکلاتی دارد. استفاده از BCMath به طور قابل توجهی کندتر از انواع اعداد داخلی در PHP است. به طور پیش فرض بهتر است از انواع عددی داخلی استفاده کنید، مگر اینکه به دقت و محدوده بیشتری نیاز داشته باشید.
سخن پایانی
این آموزش روشهای مختلف ذخیره و تبدیل اعداد در PHP و اینکه چگونه میتوان تعیین کرد که یک عدد از چه نوعی است را پوشش میدهد. برای مثال میتوانید از توابعی مانند ()is_int و ()is_float برای تعیین نوع یک عدد استفاده کنید و بر اساس آن پیش بروید.
همانطور که در آموزش دیدید، PHP از تبدیل خودکار نوع پشتیبانی میکند. این بدان معنی است که گاهی اوقات اعداد صحیح کوچک مانند 5 یا 476 می توانستند بدون اینکه متوجه شوید به عنوان float ذخیره شوند. استفاده از این اعداد در توابعی که فقط مقادیر int را میپذیرند ممکن است منجر به استثنا یا خطا شود. همچنین یک راه حل ساده برای این مشکل آموختیم که وقتی اعداد قسمت اعشاری ندارند و مقادیر آنها پس از تبدیل نوع تغییر نمیکند را به طور صریح به int تبدیل کنیم.
پس از مطالعه این آموزش باید بتوانید پس از استفاده از انواع عملیات با توابع از پیش تعریف شده، نوع یک عدد یا نتیجه آن را تعیین کرده و پس از انجام برخی بررسیها به طور صریح آنها را به یک نوع خاص تبدیل کنید.
مثل همیشه اگر سوال یا نکتهای دارید، خوشحال میشویم آن را در بخش نظرات زیر مطرح نمایید.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید