سؤال

public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

رمز أعلاه يطبع:

11.399999999999

كيف يمكنني الحصول على هذا فقط طباعة (أو تكون قادرة على استخدامه) 11.4?

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

المحلول

كما ذكر آخرون, وربما كنت سوف ترغب في استخدام BigDecimal الدرجة, إذا كنت تريد أن يكون لها تمثيل دقيق 11.4.

الآن قليلا في تفسير لماذا يحدث هذا:

على float و double أنواع بدائية في جافا هي النقطة العائمة أرقام, حيث يتم تخزين رقم الثنائية تمثيل جزء و الأس.

وبشكل أكثر تحديدا, الدقة مزدوج قيمة النقطة العائمة مثل double نوع 64 بت القيمة ، حيث:

  • 1 بت يدل على علامة (إيجابية أو سلبية).
  • 11 بت الأس.
  • 52 البتات ارقام كبيرة (الجزء الكسري الثنائية).

هذه الأجزاء هي جنبا إلى جنب لإنتاج double تمثيل قيمة.

(المصدر: ويكيبيديا:الدقة المزدوجة)

للحصول على وصف مفصل لكيفية النقطة العائمة القيم يتم التعامل معها في جاوة ، انظر القسم 4.2.3:النقطة العائمة أنواع صيغ القيم من لغة جافا المواصفات.

على byte, char, int, long أنواع نقطة ثابتة الأرقام التي هي بالضبط representions من الأرقام.على عكس النقطة الثابتة أرقام, أرقام النقطة العائمة بعض الأوقات (الأسلم أن نفترض أن "معظم الوقت") لن تكون قادرة على العودة إلى تمثيل دقيق عدد.وهذا هو السبب لماذا كنت في نهاية المطاف مع 11.399999999999 نتيجة 5.6 + 5.8.

عندما تتطلب قيمة الدقيقة ، مثل 1.5 أو 150.1005, سوف ترغب في استخدام واحدة من نقطة ثابتة أنواع, والتي سوف تكون قادرة على تمثل الرقم بالضبط.

كما ذكر عدة مرات بالفعل ، جافا لديه BigDecimal الدرجة التي سوف تتعامل مع أعداد كبيرة جدا وصغيرة جدا أرقام.

من API جافا مرجعا BigDecimal الدرجة:

غير قابل للتغيير ، التعسفي-الدقة وقعت عشري الأرقام.أ BigDecimal يتكون من الدقة التعسفي صحيح بلا مقياس قيمة عدد صحيح 32-بت الحجم.إذا صفر أو إيجابية ، فإن المقياس هو عدد الأرقام إلى يمين النقطة العشرية.إذا سلبية ، بلا مقياس قيمة الرقم مضروبة في عشرة إلى قوة نفي نطاق واسع.قيمة عدد ممثلة BigDecimal ولذلك (unscaledValue × 10^-الحجم).

كان هناك العديد من الأسئلة على تجاوز سعة مكدس المتعلقة مسألة أرقام النقطة العائمة و الدقة.هنا هي قائمة من الأسئلة ذات الصلة التي قد تكون ذات فائدة:

إذا كنت تريد حقا أن نصل إلى لب الموضوع تفاصيل أرقام النقطة العائمة, نلقي نظرة على ما كل عالم الكمبيوتر يجب أن تعرف عن حساب الفاصلة العائمة.

نصائح أخرى

عند إدخال رقم مزدوج، على سبيل المثال، 33.33333333333333، وقيمة لك هو في الواقع أقرب قيمة الدقة المزدوجة للتمثيل، وهو بالضبط:

33.3333333333333285963817615993320941925048828125

وتقسيم ذلك من خلال 100 يعطي:

0.333333333333333285963817615993320941925048828125

والتي هي أيضا ليست للتمثيل كعدد الدقة المزدوجة، لذلك مرة أخرى يتم تقريب إلى أقرب قيمة للتمثيل، وهو بالضبط:

0.3333333333333332593184650249895639717578887939453125

عند قمت بطباعة هذه القيمة بها، فإنه يحصل على تقريب <م> مرة أخرى إلى 17 الأرقام العشرية، وإعطاء:

0.33333333333333326

إذا كنت ترغب فقط في معالجة القيم كما كسور، يمكنك إنشاء فئة الكسر الذي يحمل البسط والمقام المجال.

وأساليب الكتابة للالجمع والطرح والضرب والقسمة وكذلك طريقة toDouble. وبهذه الطريقة يمكنك تجنب يطفو أثناء العمليات الحسابية.

وتحرير: تنفيذ سريع،

public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}

لاحظ أن كنت لديهم نفس المشكلة إذا كنت تستخدم محدودة الدقة العشرية الحساب، وأراد أن التعامل مع 1/3: 0.333333333 * 3 غير 0.999999999، وليس 1.00000000.

ومما يؤسف له، 5.6، 5.8 و 11.4 ليست فقط أرقام جولة في ثنائي، لأنها تنطوي أخماس. لذا فإن تمثيل تعويم منهم ليس بالضبط، مثلما 0.3333 ليس بالضبط 1/3.

وإذا كان كل الأرقام التي نستخدمها هي العشرية غير المتكررة، وتريد نتائج دقيقة، واستخدام BigDecimal. أو كما قال آخرون، إن القيم الخاصة بك مثل المال بمعنى أنهم جميعا من مضاعفات الرقم 0.01 أو 0.001، أو شيء ما، ثم ضرب كل شيء من قبل قوة ثابتة من 10 واستخدام صحيح أو طويلة (الجمع والطرح و تافهة: احترس من الضرب)

ومع ذلك، إذا كنت سعيدا مع ثنائي للحساب، ولكن أردت فقط لطباعة الامور في شكل ودا قليلا، حاول java.util.Formatter أو String.format. في سلسلة تنسيق تحديد دقة أقل من الدقة الكاملة للضعف. إلى 10 أرقام كبيرة، ويقول، 11،399999999999 هو 11.4، وبالتالي فإن النتيجة ستكون تقريبا كما دقيقة وأكثر إنسانية للقراءة في الحالات التي تكون فيها نتيجة الثنائية قريبة جدا إلى قيمة لا تتطلب سوى عدد قليل من المنازل العشرية.

والدقة لتحديد تتوقف قليلا على مدى الرياضيات قمت به مع الأرقام الخاصة بك - بشكل عام كلما قمت بذلك، سوف تتراكم أكثر خطأ، ولكن بعض الخوارزميات تتراكم بشكل أسرع بكثير من غيرها (انهم يسمى " غير مستقر "بدلا من" مستقرة "فيما يتعلق أخطاء التقريب). إذا كان كل ما تفعلونه هو إضافة بعض القيم، ثم كنت اعتقد ان اسقاط واحدة فقط رقم عشري من الدقة وترتيب الأمور. التجربة.

قد ترغب في النظر في استخدام جافا java.الرياضيات.BigDecimal الدرجة إذا كنت حقا بحاجة إلى الدقة الرياضيات.هنا هو مقال جيد من أوراكل/الشمس على حالة BigDecimal.بينما أنت لا يمكن أبدا أن تمثل 1/3 كما ذكر أحدهم ، يمكن لديك القدرة على أن تقرر بالضبط كم دقيقة كنت ترغب في أن تكون نتيجة.setScale() هو صديقك..:)

حسنا, لأن لدي الكثير من الوقت على يدي في هذه اللحظة هنا هو المثال التعليمات البرمجية التي تتعلق سؤالك:

import java.math.BigDecimal;
/**
 * Created by a wonderful programmer known as:
 * Vincent Stoessel
 * xaymaca@gmail.com
 * on Mar 17, 2010 at  11:05:16 PM
 */
public class BigUp {

    public static void main(String[] args) {
        BigDecimal first, second, result ;
        first = new BigDecimal("33.33333333333333")  ;
        second = new BigDecimal("100") ;
        result = first.divide(second);
        System.out.println("result is " + result);
       //will print : result is 0.3333333333333333


    }
}

وأن المكونات المفضلة عندي اللغة, رائع, هنا هو أكثر إتقانا سبيل المثال من نفس الشيء:

import java.math.BigDecimal

def  first =   new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")


println "result is " + first/second   // will print: result is 0.33333333333333

متأكد من أنك قد قمت بها أن في المثال ثلاثة خط. :)

إذا كنت تريد دقة بدقة، استخدم BigDecimal. خلاف ذلك، يمكنك استخدام [إينتس] مضروبا 10 ^ مهما كانت الدقة التي تريدها.

وكما ذكر آخرون، يمكن أن تكون ممثلة ليست كل القيم العشرية كما ثنائي منذ يستند عشري على قوى 10 و ثنائي يقوم على أساس قوى من اثنين.

إذا المسائل الدقيقة، واستخدام BigDecimal، ولكن إذا كنت ترغب فقط في الانتاج ودية:

System.out.printf("%.2f\n", total);

وسوف اعطيكم:

11.40

وأنت تعمل ضد الحد من الدقة من نوع مزدوجة.

وJava.Math لديه بعض مرافق حساب دقيق تعسفي.

لا 7.3 لا محدودة التمثيل في الثنائية.أقرب يمكنك الحصول على 2054767329987789/2**48 = 7.3+1/1407374883553280.

نلقي نظرة على http://docs.python.org/tutorial/floatingpoint.html للحصول على مزيد من التوضيح.(إنه على الثعبان الموقع, ولكن Java و C++ نفس "مشكلة".)

الحل يعتمد على بالضبط ما هي مشكلتك:

  • لو أنك فقط لا أحب رؤية كل تلك الضوضاء الأرقام ثم إصلاح سلسلة التنسيق.لا عرض أكثر من 15 ارقام كبيرة (أو 7 تعويم).
  • إذا كان هذا inexactness من الأرقام الخاصة بك هو كسر أشياء مثل "إذا" البيانات ثم يجب أن تكتب إذا (abs(x - 7.3) < التسامح) بدلا من if (x == 7.3).
  • إذا كنت تعمل مع المال ، ثم ما ربما كنت تريد حقا هو عشري نقطة ثابتة.تخزين عدد صحيح من سنتا أو ما أصغر وحدة من العملة.
  • (مستبعد جدا) إذا كنت بحاجة إلى أكثر من 53 بت الهامة (15-16 ارقام كبيرة) من الدقة ، ثم استخدام عالية الدقة النقطة العائمة نوع ، مثل BigDecimal.
private void getRound() {
    // this is very simple and interesting 
    double a = 5, b = 3, c;
    c = a / b;
    System.out.println(" round  val is " + c);

    //  round  val is  :  1.6666666666666667
    // if you want to only two precision point with double we 
            //  can use formate option in String 
           // which takes 2 parameters one is formte specifier which 
           // shows dicimal places another double value 
    String s = String.format("%.2f", c);
    double val = Double.parseDouble(s);
    System.out.println(" val is :" + val);
    // now out put will be : val is :1.67
}

استخدم java.math.BigDecimal

والزوجي وكسور الثنائية داخليا، حتى أنها في بعض الأحيان لا يمكن أن تمثل الكسور العشرية إلى العشرية بالضبط.

وضرب كل شيء في 100 وتخزينه في دام سنتا.

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

وأرقام النقطة العائمة تختلف عن الأرقام الحقيقية في أن أي رقم النقطة العائمة نظرا هناك أعلى رقم النقطة العائمة المقبل. نفس الأعداد الصحيحة. ليس هناك عدد صحيح بين 1 و 2.

وليس هناك طريقة لتمثيل 1/3 بمثابة تعويم. هناك تعويم تحتها وهناك تطفو فوقه، وهناك مسافة معينة بينهما. و1/3 في هذا الفضاء.

وApfloat لجاوا يدعي العمل مع أرقام النقطة الدقة التعسفي العائمة، ولكن أنا لم تستخدم ذلك. ربما يستحق نظرة. http://www.apfloat.org/apfloat_java/

وسئل سؤال مماثل هنا قبل جافا نقطة عائمة عالية الدقة مكتبة

والزوجي هي <م> تقريبية من الأرقام العشرية في مصدر جافا. ترونه نتيجة لعدم تطابق بين ضعف (والذي هو قيمة ثنائية مرمزة) والمصدر (والذي هو عشري ترميز).

وجافا إنتاج أقرب تقريب ثنائي. يمكنك استخدام java.text.DecimalFormat لعرض قيمة عشرية أفضل المظهر.

استخدم لBigDecimal. حتى أنه يتيح لك تحديد قواعد التقريب (مثل ROUND_HALF_EVEN، والتي من شأنها أن تقلل الخطأ الإحصائي التقريب إلى حتى الجار إذا كان كلاهما على مسافة واحدة، أي كلا 1.5 و 2.5 جولة ل2).

تحقق من BigDecimal، فإنه يعالج مشاكل في التعامل مع النقطة العائمة حسابي من هذا القبيل.

وقال إن الدعوة الجديدة تبدو هذه:

term[number].coefficient.add(co);

استخدم setScale () لتعيين عدد من العشرية مكان الدقة لاستخدامها.

لماذا لا تستخدم أسلوب الجولة () من الدرجة الرياضيات؟

// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4

إذا كان لديك أي خيار آخر سوى باستخدام قيم مزدوجة، ويمكن استخدام رمز أدناه.

public static double sumDouble(double value1, double value2) {
    double sum = 0.0;
    String value1Str = Double.toString(value1);
    int decimalIndex = value1Str.indexOf(".");
    int value1Precision = 0;
    if (decimalIndex != -1) {
        value1Precision = (value1Str.length() - 1) - decimalIndex;
    }

    String value2Str = Double.toString(value2);
    decimalIndex = value2Str.indexOf(".");
    int value2Precision = 0;
    if (decimalIndex != -1) {
        value2Precision = (value2Str.length() - 1) - decimalIndex;
    }

    int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
    sum = value1 + value2;
    String s = String.format("%." + maxPrecision + "f", sum);
    sum = Double.parseDouble(s);
    return sum;
}

لا تضيع وقتك efford باستخدام BigDecimal.في 99.99999% من الحالات لا تحتاج ذلك.جافا مزدوج نوع من cource التقريبية ولكن في جميع الحالات تقريبا ، فمن دقيقة بما فيه الكفاية.اعتبارنا أن لديك خطأ في 14 رقم كبير. هذا هو حقا لا تذكر!

للحصول على إخراج لطيفة استخدام:

System.out.printf("%.2f\n", total);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top