Zoeken…


Invoering

Drijvende-kommagetallen zijn getallen met fractionele delen (meestal uitgedrukt met een decimaalteken). In Java, is er twee primitieve types voor floating-point getallen die float (bestedingen 4 bytes) en double (bestedingen 8 bytes). Deze documentatiepagina is bedoeld voor details met voorbeelden van bewerkingen die kunnen worden uitgevoerd op drijvende punten in Java.

Drijvende-kommawaarden vergelijken

Je moet voorzichtig zijn bij het vergelijken van drijvende-kommawaarden ( float of double ) met behulp van relationele operatoren: == != , < Enzovoort. Deze operatoren geven resultaten volgens de binaire representaties van de drijvende-kommawaarden. Bijvoorbeeld:

public class CompareTest {
    public static void main(String[] args) {
        double oneThird = 1.0 / 3.0;
        double one = oneThird * 3;
        System.out.println(one == 1.0);      // prints "false"
    }
}

De berekening oneThird heeft een kleine afrondingsfout geïntroduceerd en wanneer we oneThird met 3 vermenigvuldigen, oneThird we een resultaat dat iets anders is dan 1.0 .

Dit probleem van onnauwkeurige representaties is ernstiger wanneer we proberen double en float te float in berekeningen. Bijvoorbeeld:

public class CompareTest2 {
    public static void main(String[] args) {
        float floatVal = 0.1f;
        double doubleVal = 0.1;
        double doubleValCopy = floatVal;

        System.out.println(floatVal);      // 0.1
        System.out.println(doubleVal);     // 0.1
        System.out.println(doubleValCopy); // 0.10000000149011612
        
        System.out.println(floatVal == doubleVal); // false
        System.out.println(doubleVal == doubleValCopy); // false
    }
}

De drijvende-komma-representaties die in Java worden gebruikt voor de float en double types hebben een beperkt aantal precisiecijfers. Voor het float type is de precisie 23 binaire cijfers of ongeveer 8 decimale cijfers. Voor het double type is dit 52 bits of ongeveer 15 decimale cijfers. Bovendien zullen sommige rekenkundige bewerkingen afrondingsfouten veroorzaken. Wanneer een programma drijvende-kommawaarden vergelijkt, is het daarom standaard om een acceptabele delta te definiëren voor de vergelijking. Als het verschil tussen de twee getallen kleiner is dan de delta, worden ze gelijk geacht. Bijvoorbeeld

if (Math.abs(v1 - v2) < delta)

Delta vergelijkingsvoorbeeld:

public class DeltaCompareExample {

    private static boolean deltaCompare(double v1, double v2, double delta) {
        // return true iff the difference between v1 and v2 is less than delta
        return Math.abs(v1 - v2) < delta;
    }
    
    public static void main(String[] args) {
        double[] doubles = {1.0, 1.0001, 1.0000001, 1.000000001, 1.0000000000001};
        double[] deltas = {0.01, 0.00001, 0.0000001, 0.0000000001, 0};

        // loop through all of deltas initialized above
        for (int j = 0; j < deltas.length; j++) {
            double delta = deltas[j];
            System.out.println("delta: " + delta);

            // loop through all of the doubles initialized above
            for (int i = 0; i < doubles.length - 1; i++) {
                double d1 = doubles[i];
                double d2 = doubles[i + 1];
                boolean result = deltaCompare(d1, d2, delta);

                System.out.println("" + d1 + " == " + d2 + " ? " + result);
                
            }

            System.out.println();
        }
    }
}

Resultaat:

delta: 0.01
1.0 == 1.0001 ? true
1.0001 == 1.0000001 ? true
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true

delta: 1.0E-5
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true

delta: 1.0E-7
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true

delta: 1.0E-10
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? false
1.000000001 == 1.0000000000001 ? false

delta: 0.0
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? false
1.000000001 == 1.0000000000001 ? false

Ook voor de vergelijking van double en float primitieve typen kan een statische compare van het overeenkomstige bokstype worden gebruikt. Bijvoorbeeld:

double a = 1.0;
double b = 1.0001;

System.out.println(Double.compare(a, b));//-1
System.out.println(Double.compare(b, a));//1

Ten slotte kan het lastig zijn om te bepalen welke delta's het meest geschikt zijn voor een vergelijking. Een veelgebruikte aanpak is om deltawaarden te kiezen waarvan onze intuïtie zegt dat ze ongeveer kloppen. Als u echter de schaal en (ware) nauwkeurigheid van de invoerwaarden en de uitgevoerde berekeningen kent, is het misschien mogelijk om wiskundig goede grenzen te stellen aan de nauwkeurigheid van de resultaten, en dus aan de delta's. (Er is een formele tak van wiskunde bekend als numerieke analyse die vroeger aan computationele wetenschappers werd geleerd die dit soort analyses omvatte.)

OverFlow en UnderFlow

Float- gegevenstype

Het float-gegevenstype is een 32-bits IEEE 754-drijvende komma met enkele precisie.

Overloop Float

De maximaal mogelijke waarde is 3.4028235e+38 Wanneer deze waarde wordt overschreden, wordt Infinity geproduceerd

float f = 3.4e38f;
float result = f*2;        
System.out.println(result); //Infinity

Float UnderFlow

Minimale waarde is 1.4e-45f, wanneer deze onder deze waarde komt, produceert deze 0.0

    float f = 1e-45f;
    float result = f/1000;
    System.out.println(result);

dubbel gegevenstype

Het dubbele gegevenstype is een 64-bit IEEE 754-drijvende-komma met dubbele precisie.

Double overloop

De maximale mogelijke waarde is 1.7976931348623157e+308 Wanneer deze waarde wordt overschreden, produceert deze Infinity

double d = 1e308;
double result=d*2;      
System.out.println(result); //Infinity

Double onderstroom

Minimale waarde is 4.9e-324, wanneer deze onder deze waarde komt, produceert deze 0.0

    double d = 4.8e-323;
    double result = d/1000;
    System.out.println(result); //0.0

De waarden voor zwevende punten opmaken

Drijvende komma Getallen kunnen worden opgemaakt als een decimaal getal met String.format met 'f' vlag 'f'

    //Two digits in fracttional part are rounded
    String format1 = String.format("%.2f", 1.2399);
    System.out.println(format1); // "1.24"

    // three digits in fractional part are rounded 
    String format2 = String.format("%.3f", 1.2399);
    System.out.println(format2); // "1.240"
    
    //rounded to two digits, filled with zero 
    String format3 = String.format("%.2f", 1.2);
    System.out.println(format3); // returns "1.20"
    
    //rounder to two digits
    String format4 = String.format("%.2f", 3.19999);
    System.out.println(format4); // "3.20"

Zwevende punt Nummers kunnen worden opgemaakt als een decimaal getal met behulp van DecimalFormat

   // rounded with one digit fractional part 
    String format = new DecimalFormat("0.#").format(4.3200);
    System.out.println(format); // 4.3
    
   // rounded with two digit fractional part 
    String format = new DecimalFormat("0.##").format(1.2323000);
    System.out.println(format); //1.23

    // formatting floating numbers to decimal number
    double dv = 123456789;
    System.out.println(dv); // 1.23456789E8
    String format =  new DecimalFormat("0").format(dv);
    System.out.println(format); //123456789

Strikte naleving van de IEEE-specificatie

Drijvende-kommabewerkingen op float en double voldoen standaard niet strikt aan de regels van de IEEE 754-specificatie. Een uitdrukking mag implementatiespecifieke uitbreidingen van het bereik van deze waarden gebruiken; in wezen waardoor ze nauwkeuriger dan nodig zijn.

strictfp schakelt dit gedrag uit. Deze wordt toegepast op een klasse, interface of werkwijze, en geldt voor alles daarin opgenomen, zoals klassen, interfaces, methoden, constructors variabele initialiseerders, etc. Met strictfp moeten de tussenwaarden van een floating-point expressie binnen de vlotterwaarde ingesteld of de dubbele waarde ingesteld. Dit zorgt ervoor dat de resultaten van dergelijke expressies precies die zijn die de IEEE 754-specificatie voorspelt.

Alle constante uitdrukkingen zijn impliciet streng, zelfs als ze niet binnen een strictfp bereik vallen.

Daarom heeft strictfp het netto-effect dat het soms bepaalde strictfp minder nauwkeurig maakt, en kan het ook drijvende-kommabewerkingen langzamer maken (omdat de CPU nu meer werk doet om ervoor te zorgen dat eventuele native extra precisie het resultaat niet beïnvloedt). Het zorgt er echter ook voor dat de resultaten op alle platforms exact hetzelfde zijn. Het is daarom nuttig in zaken als wetenschappelijke programma's, waar reproduceerbaarheid belangrijker is dan snelheid.

public class StrictFP { // No strictfp -> default lenient
    public strictfp float strict(float input) {
        return input * input / 3.4f; // Strictly adheres to the spec.
                                     // May be less accurate and may be slower.
    }

    public float lenient(float input) {
        return input * input / 3.4f; // Can sometimes be more accurate and faster,
                                     // but results may not be reproducable.
    }

    public static final strictfp class Ops { // strictfp affects all enclosed entities
        private StrictOps() {}

        public static div(double dividend, double divisor) { // implicitly strictfp
            return dividend / divisor;
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow