استخدام java.math.MathContext
-
08-06-2019 - |
سؤال
لقد حاولت مؤخرًا فهم استخدام 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 ...)