سؤال

لماذا رمز جافا هذا

long a4 = 1L;
long a3 = 1;
long a2 = 100L * 1024 * 1024 * 1024;
long a1 = 100 * 1024 * 1024 * 1024;
System.out.println(a4);
System.out.println(a3);
System.out.println(a2);
System.out.println(a1);

عند التشغيل ، الإخراج

1
1
107374182400
0

بدلا من المتوقع

1
1
107374182400
107374182400

انتاج؟

هل كانت مفيدة؟

المحلول 2

107374182400 هو بالضبط 25 ضعف النطاق الكامل من عدد صحيح (2^32), ، مما يعني أنه إذا حاولت أن تناسبها في عدد صحيح ، فستكون كذلك الفائض. ولأنها ستناسب 25 مرة بالضبط ، فقد ينتهي الأمر بدقة على 0 (هذه مصادفة ومضاعفات ضخمة أخرى قد تنتهي إيجابية أو سلبية). وأنت تستخدم عددًا صحيحًا حتى النقطة التي تلقيها لفترة طويلة

long a1 = 100 * 1024 * 1024 * 1024;

يعادل

int temp = 100 * 1024 * 1024 * 1024;
long a1 = (long)temp;

إذا وضعت فترة طويلة في التعبير ، فسيُجبر على استخدام الرياضيات الطويلة وليس الرياضيات التي تزيل المشكلة

نصائح أخرى

 long a2 = 100L * 1024 * 1024 * 1024;

في هذه العملية ، على الأقل معامل واحد على الأقل long. وبالتالي يتم تنفيذ العملية باستخدام دقة 64 بت ، ونتيجة المشغل العددي من النوع long. يتم توسيع المعامل الآخر غير الطويل إلى الكتابة long بواسطة الترويج الرقمي ويتم تخزين القيمة الناتجة إلى متغير a2.

 long a1 = 100 * 1024 * 1024 * 1024;

التعبير المستمر عن عدد صحيح عادي ، تم حساب نتيجة التعبير كنوع int. كانت القيمة المحسوبة كبيرة جدًا بحيث لا تتناسب مع عدد صحيح وبالتالي فاضت ، مما يؤدي إلى 0 ويتم تخزينه ل a1 عامل.

تحرير: كما هو مطلوب في التعليق التالي:

لماذا لا تصبح سلبية؟

لأنه أثناء وجوده حساب عدد صحيح الحساب الثاني يعادل 25 * 2^32 أين ^ لديه معنى القوة و 2^32 قيمة عدد صحيح 0. ومع ذلك ، لشرح سبب القيمة 0: في الثنائي:

 100 * 1024 * 1024 * 1024 == 25 * 2^32;

 Integer.MAX_VALUE =  2 ^ 31 -1 = 0 11111111 11111111 11111111 1111111
 Integer.MAX_VALUE + 1 = 2 ^ 31 = 1 00000000 00000000 00000000 0000000 

2 ^ 31 هو عدد صحيح سلبي (-2147483648) كما بتة علامة 1 وبالتالي 2 ^ 32 هو مجرد تكاثر 2 إلى 2 ^ 31: تحول اليسار وسيصبح جزء الإشارة 0 وبالتالي النتيجة هي 0.

تفحص ال java language specification: 4.2.2: Integer operation للتفاصيل.

قد يكون التعبير على يمين a1 يتم حسابه لأول مرة على أنه int وبعد ذلك تم تحويله إلى long. إذا كان يساوي 0 ك int سيبقى 0 ك long

وفقا ل توثيق الحرفية المعجمية وذكر ذلك ،

يتم تحديد نوع الحرفي على النحو التالي:
- نوع عدد صحيح حرفي (§3.10.1) الذي ينتهي بـ L أو L طويل (§4.2.1).
- نوع أي عدد صحيح آخر هو int (§4.2.1).

هكذا تعبيرك ، 100 * 1024 * 1024 * 1024 يتم تقييمه على النحو int نوع البيانات البدائية بسبب l أو L لم يرد ذكره في أي قيمة رقمية. والنتيجة هي 107374182400 أي في الثنائي هو كذلك 1 1001 0000 0000 0000 0000 0000 0000 0000 0000 و int هل يتم أخذ 32 بت منخفضة 32 بت كما هو مذكور في مثال 4.2.2-1. عمليات عدد صحيح الذي ينتج عنه 0

وذكر أيضًا في الوثائق نفسها ،

إذا كان لدى مشغل عدد صحيح بخلاف مشغل التحول معامل واحد على الأقل من النوع الطويل ، فسيتم تنفيذ العملية باستخدام دقة 64 بت ، ونتيجة المشغل العددي من النوع الطويل. إذا لم يكن المعامل الآخر طويلًا ، فسيتم توسيعه أولاً (§5.1.5) لكتابة طويلة عن طريق الترويج الرقمي

وهذا يعني أن أي قيمة في التعبير تحتوي l أو L ثم كل int سيتم توسيع القيم إلى 64 بت.

تعديل في التعليق يطلب أيضا

لماذا لا تصبح سلبية؟

أعتقد أنه أيضا يجيب على السؤال أعلاه

long a4 = 1L; // لا مشكلة في هذا

long a3 = 1; // هنا يعتبر الجانب الأيسر البدائي عددًا صحيحًا وفي وقت المهمة سيتم إلقاؤه لفترة طويلة ، لذا فإن النتيجة هي كما هو متوقع

long a2 = 100L * 1024 * 1024 * 1024; (هنا استخدمت 100 لتر ، لذلك سيتم تصوير الآخرين إلى المخرجات المتوقعة للغاية)

long a1 = 100 * 1024 * 1024 * 1024; (كما هو افتراضيًا ، يعتبر أي رقم بدائي في int في Java ، وسوف يعتبر هذا تكاثر عدد صحيح بحيث ينفد من النطاق ويؤدي إلى 0)

إليك ما فعلته: قمت بتعيينه 100 * 1024 * 1024 * 1024إلى نوع بيانات طويل لكنك لم تقل ذلك 100 * 1024 * 1024 * 1024 هي قيمة طويلة

بشكل افتراضي ، يعتقد برنامج التحويل البرمجي Java أنه عدد صحيح. نظرًا لأن عدد صحيح لا يمكنه الاحتفاظ بهذه القيمة الكثيرة ، فإنه سيظهر نتيجة خاطئة. أتمنى أن يساعد!

السبب تجاوز عدد صحيح
كما ناتج 100 * 1024 * 1024 * 1024; هو عدد صحيح (int) ليس long

و في long a2 = 100L * 1024 * 1024 * 1024; أنت تحدد أن واحدة من القيمة هي long (هنا 100L) والضرب مع هذه القيمة يؤدي long القيمة التي يتم تخزينها بشكل صحيح في a2

في Java ، إذا كان لديك int * int ، فسيحسب الإخراج كـ int. إنه يعطي النتيجة فقط لفترة طويلة إذا كنت تفعل int * طويل. في حالتك ، فإن 100 * 1024 * 1024 * 1024 لها نتيجة تفيض.

لذلك ، فإن إضافة "L" يجعل المعامل طويلًا ، ويخزن الحساب القيم الطويلة. وبالطبع ، لا يحدث أي تدفق ويمكن أن يتم إخراج نتيجة صحيحة (أي A2).

عمل رقم 3 لأنك حددت نوعًا طويلًا وهو 100 لتر. هذا هو السبب في أنها تكاثر طويل ويمكن تخزينها. من ناحية أخرى ، فإن الرقم 4 هو مضاعفة عدد صحيح مع أقصى قيمة 2^32-1 ولهذا السبب حصلت على تدفق فائض وظهرت القيمة الافتراضية صفر.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top