سؤال

لقد حاولت مؤخرًا فهم استخدام java.math.MathContext ولكن فشل في الفهم بشكل صحيح.هل يستخدم للتقريب java.math.BigDecimal.إذا كانت الإجابة بنعم، فلماذا لا يتم تقريب الأرقام العشرية ولكن حتى الجزء العشري.

من خلال مستندات API، عرفت أنها تتبع المعيار المحدد في ANSI X3.274-1996 و ANSI X3.274-1996/AM 1-2000 المواصفات لكنني لم أتمكن من قراءتها عبر الإنترنت.

واسمحوا لي أن أعرف إذا كان لديك أي فكرة عن هذا.

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

المحلول

@جاتان

شكرا لك على الإجابة.يبدو الأمر معقولا.هل يمكن أن تشرح لي MathContext في سياق طريقة BigDecimal#round.

لا يوجد شيء خاص عنه BigDecimal.round() ضد. اي شيء اخر BigDecimal طريقة.وفي جميع الأحوال فإن MathContext يحدد عدد الأرقام المهمة وتقنية التقريب.في الأساس، هناك جزأين من كل MathContext.هناك دقة، وهناك أيضًا RoundingMode.

تحدد الدقة مرة أخرى عدد الأرقام المهمة.لذلك إذا قمت بتحديد 123 كرقم، واطلب رقمين مهمين، وسوف تحصل عليه 120.قد يكون الأمر أكثر وضوحًا إذا كنت تفكر من حيث التدوين العلمي.

123 سيكون 1.23e2 في التدوين العلمي.إذا احتفظت برقمين مهمين فقط، فستحصل على 1.2e2, ، أو 120.من خلال تقليل عدد الأرقام المهمة، فإننا نخفض الدقة التي يمكننا من خلالها تحديد الرقم.

ال RoundingMode يحدد الجزء كيف يجب أن نتعامل مع فقدان الدقة.لإعادة استخدام المثال، إذا كنت تستخدم 123 كرقم، واطلب رقمين مهمين، فقد قللت من دقتك.مع RoundingMode ل HALF_UP (الوضع الافتراضي)، 123 سيصبح 120.مع RoundingMode ل CEILING, ، سوف تحصل 130.

على سبيل المثال:

System.out.println(new BigDecimal("123.4",
                   new MathContext(4,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
                   new MathContext(2,RoundingMode.HALF_UP)));
System.out.println(new BigDecimal("123.4",
                   new MathContext(2,RoundingMode.CEILING)));
System.out.println(new BigDecimal("123.4",
                   new MathContext(1,RoundingMode.CEILING)));

النواتج:

123.4
1.2E+2
1.3E+2
2E+2

يمكنك أن ترى أن كلا من الدقة ووضع التقريب يؤثران على الإخراج.

نصائح أخرى

لتقريب الجزء الكسري فقط من BigDecimal، راجع BigDecimal.setScale(int newScale, int roundingMode) طريقة.

على سبيل المثاللتغيير رقم مكون من ثلاثة أرقام بعد العلامة العشرية إلى رقم مكون من رقمين، والتقريب لأعلى:

BigDecimal original = new BigDecimal("1.235");
BigDecimal scaled = original.setScale(2, BigDecimal.ROUND_HALF_UP);

والنتيجة هي BigDecimal بقيمة 1.24 (بسبب قاعدة التقريب)

وأود أن أضيف هنا بعض الأمثلة.لم أجدها في الإجابات السابقة، لكني أجدها مفيدة لمن ربما يضلل أرقام هامة مع عدد منازل عشرية.لنفترض أن لدينا مثل هذا السياق:

MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);

لهذا الرمز:

BigDecimal d1 = new BigDecimal(1234.4, MATH_CTX);
System.out.println(d1);

فمن الواضح تماما، أن النتيجة الخاصة بك 1.23E+3 كما قال الرجال أعلاه.الأرقام المهمة الأولى هي 123...

ولكن ماذا في هذه الحالة:

BigDecimal d2 = new BigDecimal(0.000000454770054, MATH_CTX);
System.out.println(d2);

رقمك لن يتم تقريبه إلى 3 أماكن بعد الفاصلة - بالنسبة لشخص ما قد لا يكون الأمر بديهيًا ولا يستحق التأكيد عليه.وبدلاً من ذلك سيتم تقريبه إلى أول 3 أرقام مهمة, ، وهي في هذه الحالة "4 5 4".لذلك ينتج عن الكود أعلاه 4.55E-7 وليس في 0.000 كما يمكن لأي شخص أن يتوقع.

أمثلة مماثلة:

BigDecimal d3 = new BigDecimal(0.001000045477, MATH_CTX);
 System.out.println(d3);  // 0.00100

BigDecimal d4 = new BigDecimal(0.200000477, MATH_CTX);
 System.out.println(d4);   // 0.200

BigDecimal d5 = new BigDecimal(0.000000004, MATH_CTX);
    System.out.println(d5); //4.00E-9

آمل أن يكون هذا المثال الواضح، ولكن ذو الصلة، مفيدًا ...

إذا كنت أفهمك بشكل صحيح، يبدو أنك تتوقع أن يتحكم MathContext في عدد الأرقام التي يجب الاحتفاظ بها بعد العلامة العشرية.هذا ليس ما هو عليه.يحدد عدد الأرقام التي يجب الاحتفاظ بها، المجموع.لذا، إذا حددت أنك تريد 3 أرقام مهمة، فهذا كل ما ستحصل عليه.

على سبيل المثال، هذا:

System.out.println(new BigDecimal("1234567890.123456789",
                   new MathContext(20)));

System.out.println(new BigDecimal("1234567890.123456789",
                   new MathContext(10)));

System.out.println(new BigDecimal("1234567890.123456789",
                   new MathContext(5)));

سوف يخرج:

1234567890.123456789
1234567890
1.2346E+9

انها ليست من أجل المتعة.في الواقع، لقد وجدت بعض الأمثلة عبر الإنترنت، والتي تنص على استخدام MathContext لتقريب المبالغ/الأرقام المخزنة في BigDecimal.

على سبيل المثال،

لو MathContext تم تكوينه ليكون precision = 2 و rounding mode = ROUND_HALF_EVEN

BigDecimal Number = 0.5294, ، يكون مدور ل 0.53

لذلك اعتقدت أنها تقنية أحدث واستخدمتها لغرض التقريب.ومع ذلك فقد تحول إلى كابوس لأنه بدأ في تقريب جزء من الرقم حتى.

على سبيل المثال،

Number = 1.5294 يتم تقريبه إلى 1.5

Number = 10.5294 يتم تقريبه إلى 10

Number = 101.5294 يتم تقريبه إلى 100

....وما إلى ذلك وهلم جرا

لذلك ليس هذا هو السلوك الذي توقعته للتقريب (حيث أن الدقة = 2).

يبدو أن هناك بعض المنطق لأنه من الطقطقة أستطيع أن أقول إنه يأخذ أول رقمين (حيث أن الدقة هي 2) من الرقم ثم يُلحق 0 حتى الرقم.من الأرقام تصبح نفس المبلغ غير المقرب (راجع مثال 101.5294 ...)

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