صندوق أدوات من الدوال الساكنة
java.lang.Math فئة مليئة بدوال رياضية جاهزة: الأسس، والجذور، والقيم المطلقة، والتقريب، والدوال المثلثية، واللوغاريتمات، والأرقام العشوائية. وأمران يجعلانها سهلة الاستخدام:
- توجد في
java.lang، التي يستوردها كل ملف جافا تلقائيًا. لا حاجة إلى كتابة سطرimport. - كل دوالها
static. تستدعيها على اسم الفئة،Math.sqrt(25)، ولا تنشئ كائنMathأبدًا. تشرح صفحة الأعضاء الساكنة معنىstatic.
لاحظ أن بعض النتائج تُطبع مع .0 وبعضها لا. لكل دالة في Math نوع إرجاع ثابت، ومعرفته هي معظم ما يلزم تعلّمه عن هذه الفئة.
| الدالة | ماذا تفعل | تُرجع |
|---|---|---|
Math.pow(a, b) | a مرفوعًا إلى الأس b | double |
Math.sqrt(x) | الجذر التربيعي | double |
Math.cbrt(x) | الجذر التكعيبي | double |
Math.abs(x) | القيمة المطلقة | نوع x نفسه |
Math.max(a, b) / Math.min(a, b) | الأكبر / الأصغر من القيمتين | الأوسع من النوعين |
Math.round(x) | أقرب عدد صحيح | long مع double، وint مع float |
Math.floor(x) / Math.ceil(x) | التقريب إلى الأسفل / إلى الأعلى | double |
Math.random() | رقم عشوائي من 0.0 حتى 1.0 | double |
Math.PI، Math.E | الثابتان π وe | double |
Math.pow: الأسس
ترفع Math.pow(base, exponent) عددًا إلى أس. تأخذ معاملين من نوع double وتُرجع double، حتى عندما تمرّر أعدادًا صحيحة:
لتخزين النتيجة في int، حوّلها باستخدام (int). مع الأسس الصغيرة للأعداد الصحيحة تكون نتيجة double دقيقة، فيعطي التحويل الإجابة الصحيحة. أما النتائج الكبيرة فهي حيث يخطئ التحويل: قيمة double أكبر من Integer.MAX_VALUE (2,147,483,647) تتحول إلى Integer.MAX_VALUE بالضبط، لذا فإن (int) Math.pow(2, 40) تعطي 2147483647. حوّل إلى long مع الأسس الأكبر، وتذكّر أن double لا يستطيع تمثيل كل عدد صحيح بدقة فوق 2⁵³. تشرح صفحة تحويل الأنواع ما يفعله التحويل بالقيمة.
لا يوجد في جافا معامل للأس. 2 ^ 3 تُترجَم، لكن ^ هو XOR على مستوى البت، والنتيجة 1 وليست 8. وهذا من أكثر أخطاء المبتدئين شيوعًا في كود الرياضيات بجافا.
قيمة double التي تساوي عشرة ملايين أو أكثر تُطبع بالصيغة العلمية، وهذا يفاجئ الناس أول مرة يطبعون فيها قوة من قوى العشرة:
1.0E7 تعني 1.0 × 10⁷. القيمة نفسها لم تتغير، بل شكل الطباعة فقط. حوّل إلى long، أو نسّق باستخدام String.format("%.0f", value)، لطباعتها أرقامًا عادية.
Math.sqrt وMath.cbrt: الجذور
تُرجع Math.sqrt(x) الجذر التربيعي لـx من نوع double. وتُرجع Math.cbrt(x) الجذر التكعيبي.
الجذر التربيعي لعدد سالب ليس عددًا حقيقيًا، لذا تُرجع Math.sqrt(-4) القيمة NaN ("ليس رقمًا") بدلًا من إطلاق استثناء. وتنتشر NaN في أي عملية حسابية تمسّها، لذا تحقق من المدخلات قبل حساب الجذر إذا كانت القيم السالبة ممكنة. تحسب Math.hypot(a, b) القيمة sqrt(a*a + b*b) مباشرة، وهي طريقة شائعة لحساب المسافة بين نقطتين.
Math.abs: القيمة المطلقة
تزيل Math.abs(x) الإشارة. وعلى عكس pow وsqrt، تُرجع النوع نفسه الذي تعطيه لها: int مع int، وdouble مع double.
الاستخدام المعتاد لها هو حساب فرق يهمك حجمه لا اتجاهه، كالمسافة بين موضعين.
Math.max وMath.min
تُرجع Math.max(a, b) الأكبر من قيمتين، وMath.min(a, b) الأصغر. تأخذان وسيطين بالضبط. ولثلاث قيم أو أكثر، ضع الاستدعاءات داخل بعضها:
عندما يكون للوسيطين نوعان مختلفان، يُوسَّع النوع الأضيق أولًا. Math.max(3, 7.5) تقارن قيمتين من نوع double وتُرجع double. أما المثال الأخير فيحصر قيمة داخل النطاق من 0 إلى 100: تجعل Math.min حدها الأعلى 100، وتمنعها Math.max من النزول تحت 0.
التقريب: round وfloor وceil
في جافا ثلاث دوال للتقريب، وتختلف في الاتجاه وفي نوع الإرجاع معًا:
- تذهب
Math.roundإلى أقرب عدد صحيح. والقيمة الواقعة في المنتصف تمامًا تُقرَّب إلى الأعلى، نحو اللانهاية الموجبة، فتصبح2.5هي3وتصبح-2.5هي-2. تُرجعlongمع وسيطdouble(وintمعfloat). - تقرّب
Math.floorدائمًا إلى الأسفل، نحو اللانهاية السالبة، وتُرجعdouble. - تقرّب
Math.ceilدائمًا إلى الأعلى، نحو اللانهاية الموجبة، وتُرجعdouble. - التحويل
(int)ليس تقريبًا على الإطلاق: يحذف الجزء الكسري، فيُنزل الأعداد الموجبة ويرفع الأعداد السالبة.
لأن Math.round(double) تُرجع long، فإن إسنادها إلى int لا يُترجَم دون تحويل صريح:
int n = Math.round(2.6); // خطأ في الترجمة: incompatible types: possible lossy conversion from long to int
int m = (int) Math.round(2.6); // صحيح، m تساوي 3
long k = Math.round(2.6); // صحيح
للتقريب إلى عدد معيّن من المنازل العشرية، كبّر القيمة، ثم قرّبها، ثم صغّرها من جديد. القسمة على 100.0 (من نوع double) بدلًا من 100 تحافظ على الكسور:
السطر الثاني يقسم long على int، وهذه قسمة صحيحة، فتضيع الكسور. وعندما تحتاج فقط إلى عرض رقم مقرّب، تكون String.format("%.2f", value) أبسط ولا تغيّر القيمة المخزنة.
Math.random: الأرقام العشوائية
تُرجع Math.random() قيمة double لا تقل عن 0.0 وأصغر من 1.0. تختلف القيمة في كل استدعاء، لذا تتغير مخرجات البرامج في هذا القسم في كل مرة تضغط فيها Run.
للحصول على عدد صحيح في نطاق، مدّد تلك القيمة، ثم حوّلها، ثم أزِحها. لعدد صحيح من min إلى max، شاملًا الطرفين:
int value = (int) (Math.random() * (max - min + 1)) + min;
وهكذا تعمل الصيغة مع النرد، حيث min تساوي 1 وmax تساوي 6:
Math.random() * 6تعطيdoubleمن0.0حتى6.0دون أن تشملها.(int)تحذف الكسر، فتعطي واحدة من0, 1, 2, 3, 4, 5.+ 1تزيح النتيجة إلى1, 2, 3, 4, 5, 6.
يعرض السطر الأول خمس رميات عشوائية. ويفحص السطر الثاني عشرة آلاف رمية، وعمليًا يطبع دائمًا lowest: 1, highest: 6: تصل الصيغة إلى طرفي النطاق ولا تتجاوزهما أبدًا.
الأقواس حول Math.random() * (max - min + 1) مهمة. يُطبَّق التحويل على القيمة التي تليه مباشرة، لذا فإن (int) Math.random() * 6 تحوّل Math.random() أولًا. والنتيجة دائمًا 0، و0 * 6 تساوي 0، فتخرج كل "رمية" بالقيمة نفسها.
Math.random() مناسبة للألعاب والتمارين. أما لما هو أكثر من ذلك، فالفئة java.util.Random وThreadLocalRandom.current().nextInt(min, max + 1) (في java.util.concurrent) تُرجعان أعدادًا صحيحة مباشرة، ويمكن أن تأخذ Random بذرة (seed) لتكرار السلسلة نفسها في الاختبارات. ولا شيء من هذه مناسب لكلمات المرور أو رموز الأمان، فاستخدم java.security.SecureRandom لها.
Math.PI وMath.E
Math.PI (π) وMath.E (عدد أويلر e) ثابتان من نوع static final double:
استخدمهما بدلًا من كتابة 3.14. دقتهما أقصى ما يسمح به double، والاسم يخبر القارئ ما هو الرقم.
نتائج صحيحة مقابل نتائج عشرية
تأخذ معظم دوال Math قيمًا من نوع double وتُرجع double. وعندما تعطيها قيمًا من نوع int، توسّع جافا الوسائط إلى double تلقائيًا، لكن العمليات الحسابية التي تكتبها قبل الاستدعاء تبقى تُجرى بنوع int. ومن هنا تأتي معظم الإجابات الخاطئة:
items / perBox هي 7 / 2، وقسمة قيمتين من نوع int تتخلص من الباقي، فتكون النتيجة 3 قبل أن تراها Math.ceil أصلًا. وMath.ceil(3.0) تساوي 3.0. اجعل أحد الطرفين double، بتحويل صريح أو بقيمة حرفية مثل 4.0، حتى تحتفظ القسمة بكسرها. تشرح صفحة المعاملات القسمة الصحيحة بتفصيل أكبر.
القاعدة العامة: حدّد النوع الذي تريده في النهاية، واجعل القسمة أو الضرب يُجرى بنوع double عندما تهمك الكسور، ولا تحوّل إلى int أو long إلا مرة واحدة في النهاية.
دوال مفيدة أخرى
بعض الدوال الأخرى من الفئة نفسها، وكلها تُستدعى بالطريقة نفسها:
Math.logهي اللوغاريتم الطبيعي، وMath.log10للأساس 10.- تعطي
Math.floorMod(a, b)باقيًا بإشارةb، وهذا ما تحتاجه للدوران داخل نطاق مثل أيام الأسبوع. أما المعامل%فيحتفظ بإشارةa. - تأخذ الدوال المثلثية (
sinوcosوtan) الزوايا بالراديان. حوّل الدرجات أولًا باستخدامMath.toRadians. - تطلق
Math.addExactوMath.multiplyExactوأخواتها استثناءArithmeticExceptionعند الفيض (overflow) بدلًا من الالتفاف بصمت إلى عدد سالب.
الأسئلة الشائعة
كيف أستخدم Math.pow في جافا؟
تُرجع Math.pow(base, exponent) قيمة base مرفوعة إلى الأس exponent من نوع double، لذا فإن Math.pow(2, 3) تساوي 8.0. ولتخزين النتيجة في int حوّلها: int n = (int) Math.pow(2, 10); تعطي 1024. لا يوجد في جافا معامل أس ^، فـ^ هو XOR على مستوى البت.
كيف أولّد رقمًا عشوائيًا في نطاق باستخدام Math.random؟
تُرجع Math.random() قيمة double من 0.0 حتى 1.0 دون أن تشملها. للحصول على عدد صحيح من min إلى max شاملًا الطرفين، استخدم (int) (Math.random() * (max - min + 1)) + min. ورمية النرد هي (int) (Math.random() * 6) + 1.
هل أحتاج إلى استيراد الفئة Math في جافا؟
لا. Math موجودة في الحزمة java.lang، التي يستوردها كل ملف جافا تلقائيًا. وكل دوالها static، لذا تستدعيها على اسم الفئة، كما في Math.sqrt(16)، دون إنشاء كائن.
لماذا تُرجع Math.round قيمة long في جافا؟
تُرجع Math.round(double) قيمة long لأن double يمكنه حمل قيم أكبر بكثير من نطاق int. وإسناد النتيجة إلى int يحتاج إلى تحويل صريح: int n = (int) Math.round(2.6);. أما Math.round(float) فتُرجع int.
ما الفرق بين Math.floor وMath.ceil وMath.round؟
تقرّب Math.floor إلى الأسفل (2.7 تصبح 2.0، و-2.3 تصبح -3.0)، وتقرّب Math.ceil إلى الأعلى (2.1 تصبح 3.0)، وتذهب Math.round إلى أقرب عدد صحيح، مع تقريب النصف إلى الأعلى (2.5 تصبح 3). تُرجع floor وceil قيمة double، وتُرجع round قيمة long.