CodeGym/Java blogg/Slumpmässig/BigDecimal i Java
John Squirrels
Nivå
San Francisco

BigDecimal i Java

Publicerad i gruppen
Hej! I dagens lektion kommer vi att prata om stora siffror. Nej, jag menar RIKTIGT STORT. Vi har tidigare upprepade gånger stött på tabellen med värdeintervall för primitiva datatyper. Det ser ut så här:
Primitiv typ Storlek i minnet Värdeintervall
byte 8 bitar -128 till 127
kort 16 bitar -32768 till 32767
röding 16 bitar 0 till 65536
int 32 bitar -2147483648 till 2147483647
lång 64 bitar -9223372036854775808 till 9223372036854775807
flyta 32 bitar (2 till -149) till ((2 i -23) * 2 till 127)
dubbel 64 bitar (-2 till 63) till ((2 till 63) - 1)
booleskt 8 (när den används i arrayer), 32 (när den inte används i arrayer) sant eller falskt
Den rymligaste heltalsdatatypen är den långa . När det kommer till flyttalsnummer är det dubbelt . Men vad händer om antalet vi behöver är så stort att det inte ens passar in i en lång ? Den långa datatypen har ett ganska stort utbud av möjliga värden, men den är fortfarande begränsad till 64 bitar. Vad behöver vi hitta på om vårt Very Large Number kräver 100 bitar? Som tur är behöver vi inte hitta på något. För fall som detta har Java två specialklasser: BigInteger (för heltal) och BigDecimal(för flyttal). Vad gör dem speciella? Först och främst, i teorin har de ingen maximal storlek. Vi säger "i teorin", för det finns inga datorer med oändligt minne. Och om ditt program skapar ett nummer som är större än mängden tillgängligt minne, kommer programmet inte att fungera, naturligtvis. Men sådana fall är osannolika. Som ett resultat kan vi säga att BigInteger och BigDecimal kan representera tal av praktiskt taget obegränsad storlek. Vad används dessa klasser till? Först och främst för beräkningar med extremt rigorösa noggrannhetskrav. Människoliv kan till exempel bero på exaktheten i beräkningarna i vissa program (t.ex. programvara som styr flygplan, raketer eller medicinsk utrustning). Så om den 150:e decimalen är viktig, då BigDecimalär det bästa valet. Dessutom används ofta föremål av denna klass i finansvärlden, där noggrann beräkning av även de minsta värdena också är extremt viktig. Hur arbetar du med BigInteger och BigDecimal -objekt och behöver du veta om dem? Objekt av dessa klasser skapas så här:
public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Att skicka en sträng till konstruktorn är bara ett möjligt alternativ. Här använder vi strängar, eftersom våra siffror överstiger maxvärdena för long och double , och vi behöver något sätt att förklara för kompilatorn vilket nummer vi vill skapa :) Skicka bara numret 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 till konstruktorn kommer inte att fungera: Java kommer att försöka klämma in det passerade numret i en av de primitiva datatyperna, men det kommer inte att passa in i någon av dem. Det är därför det är ett bra alternativ att använda en sträng för att skicka det önskade numret. Båda klasserna kan automatiskt extrahera numeriska värden från de passerade strängarna. En annan viktig punkt att komma ihåg när du arbetar med klasser med stora antal är att deras objekt är oföränderliga ( Immutable ). Du är redan bekant med oföränderlighet tack vare din erfarenhet av String -klassen och omslagsklasserna för primitiva typer (heltal, lång, etc.).
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Konsolutgång:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Som du kan förvänta dig har vårt nummer inte ändrats. För att utföra tilläggsoperationen måste du skapa ett nytt objekt för att få resultatet av operationen.
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Konsolutgång:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Se, nu fungerar allt som det ska :) Har du förresten märkt hur ovanlig tilläggsoperationen ser ut?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Detta är en annan viktig punkt. Klasser med stora siffror använder inte operatorerna + - * /. Istället tillhandahåller de en uppsättning metoder. Låt oss bekanta oss med de viktigaste (som alltid kan du hitta en komplett lista över metoder i Oracle-dokumentationen: här och här ).
  1. metoder för aritmetiska operationer: add() , subtrahera() , multiplicera() , divide() . Dessa metoder används för att utföra addition, subtraktion, multiplikation respektive division.

  2. doubleValue() , intValue() , floatValue() , longValue() , etc. används för att konvertera ett stort tal till en av Javas primitiva typer. Var försiktig när du använder dessa metoder. Glöm inte skillnaderna i bitstorlek!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }

    Konsolutgång:

    8198552921648689607
  3. min() och max() låter dig hitta det lägsta och högsta värdet för två stora tal.
    Observera att dessa metoder inte är statiska!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }

    Konsolutgång:

    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

BigDecimal avrundningsbeteende

Det här ämnet har ett eget separat avsnitt, eftersom avrundning av stora tal och konfigurering av avrundningsbeteende inte är så enkelt. Du kan använda metoden setScale() för att ställa in antalet decimaler för en BigDecimal . Anta till exempel att vi vill att talet 111.5555555555 ska ha tre siffror efter decimalkomma. Men vi kan inte uppnå vad vi vill genom att skicka siffran 3 som ett argument till metoden setScale() . Som nämnts ovan, BigDecimalär för att representera tal med strikta krav på beräkningsprecision. I sin nuvarande form har vårt nummer 10 siffror efter decimalkomma. Vi vill släppa 7 av dem och bara behålla 3. Därför måste vi, förutom siffran 3, klara avrundningsläget. BigDecimal har totalt 8 avrundningslägen. Det är mycket! Men om du verkligen behöver finjustera precisionen i dina beräkningar har du allt du behöver. Så här är de 8 avrundningslägena som erbjuds av BigDecimal :
  1. ROUND_CEILING — avrundar uppåt

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN — avrundar mot noll

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR — avrundar nedåt

    111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555

  4. ROUND_HALF_UP — avrundar uppåt om talet efter decimalkomma >= 0,5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN — avrundar uppåt om talet efter decimalkomma > 0,5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN — avrundning beror på talet till vänster om decimalkomma. Om siffran till vänster är jämn blir avrundningen nedåt. Om siffran till vänster om decimaltecknet är udda, kommer avrundningen att vara uppåt.

    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2

    Siffran till vänster om decimalen är 2 (jämnt). Antalet avrundas nedåt. Vi vill ha 0 decimaler, så resultatet är 2.

    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4

    Siffran till vänster om decimalkomma är 3 (udda). Antalet avrundas uppåt. Vi vill ha 0 decimaler, så resultatet är 4.

  7. ROUND_UNNECCESSARY — Detta läge används när du måste skicka ett avrundningsläge till en metod, men talet behöver inte avrundas. Om du försöker avrunda ett tal med läget ROUND_UNNECCESSARY inställt, kastas ett ArithmeticException.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP — avrundar bort från noll.

    111.5551 -> setScale(3, ROUND_UP) -> 111.556

Jämför stora siffror

Detta är också viktigt. Du kommer ihåg att vi använder metoden equals() för att jämföra objekt i Java. Implementeringen tillhandahålls antingen av själva språket (för standard Java-klasser) eller åsidosätts av programmeraren. Men i fallet med BigDecimal- objekt rekommenderas inte metoden equals() för jämförelser. Detta beror på att metoden BigDecimal.equals() returnerar true endast om de två talen har samma värde och skala: Låt oss jämföra beteendet för metoden equals() för klasserna Double och BigDecimal :
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));

   }
}
Konsolutgång:
true
false
Som du kan se, för BigDecimal , visade sig siffrorna 1,5 och 1,50 vara ojämlika! Detta var just på grund av detaljerna i implementeringen av metoden equals() i BigDecimal -klassen. För en mer exakt jämförelse av två BigDecimal- objekt är det bättre att använda metoden compareTo() :
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Konsolutgång:
0
Metoden compareTo() returnerade 0, vilket betyder att 1,5 och 1,50 är lika. Och det här är resultatet vi förväntade oss! :) Det avslutar vår lektion idag. Nu är det dags att återgå till uppgifterna! :)
Kommentarer
  • Populär
  • Ny
  • Gammal
Du måste vara inloggad för att lämna en kommentar
Den här sidan har inga kommentarer än