1. Avrundning av reella tal

Som vi redan har diskuterat, när ett reellt tal tilldelas en intvariabel, avrundas det alltid nedåt till närmaste mindre heltal - bråkdelen kasseras helt enkelt.

Men det är lätt att föreställa sig en situation när ett bråktal måste avrundas till närmaste heltal i endera riktningen eller till och med avrundas uppåt. Vad gör du i det här fallet?

För detta och för många liknande situationer har Java Mathklassen, som har metoderna round(), ceil(), och .floor()


Math.round()metod

Metoden Math.round()avrundar ett tal till närmaste heltal:

long x = Math.round(real_number)

Men det finns en annan nyans här: den här metoden returnerar ett longheltal (inte ett ) int. Eftersom reella tal kan vara mycket stora, bestämde Javas skapare att använda Javas största tillgängliga heltalstyp: long.

Följaktligen, om en programmerare vill tilldela resultatet till en intvariabel, måste hon uttryckligen ange för kompilatorn att hon accepterar eventuell förlust av data (i händelse av att det resulterande numret inte passar in i en inttyp).

int x = (int) Math.round(real_number)

Exempel:

Påstående Resultat
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

Math.ceil()metod

Metoden Math.ceil()avrundar ett tal uppåt till ett heltal. Här är exempel:

Påstående Resultat
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

Math.floor()metod

Metoden Math.floor()avrundar ett tal nedåt till ett heltal. Här är exempel:

Påstående Resultat
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

Naturligtvis, när du avrundar ett tal nedåt till ett heltal, är det lättare att helt enkelt använda en typ cast-operator:(int)

Påstående Resultat
int x = (int) 4.9
4

Om du tycker att det är svårt att komma ihåg dessa namn hjälper en kort engelsklektion:

  • Mathbetyder matematik
  • Roundbetyder rund
  • Ceilingbetyder tak
  • Floorbetyder golv

2. Hur flyttalstal är uppbyggda

Typen doublekan lagra värden i intervallet från till . Detta enorma utbud av värden (jämfört med typen) förklaras av att typen (liksom ) har en helt annan intern struktur än heltalstyper. Internt kodar typen sitt värde som två tal: det första kallas mantissa , och det andra kallas exponent .-1.7*10308+1.7*10308intdoublefloatdouble

Låt oss säga att vi har numret 123456789och lagrar det som en doublevariabel. När vi gör det omvandlas numret till , och internt lagrar typen två nummer — och . Signifikanden ("signifikant del av talet" eller mantissa) är markerad i rött, medan exponenten är markerad i blått.1.23456789*108double234567898

Detta tillvägagångssätt gör det möjligt att lagra både mycket stora och mycket små. Men eftersom talets representation är begränsad till 8 byte (64 bitar) och en del av bitarna används för att lagra exponenten ( liksom mantisans tecken och exponentens tecken), är det maximala antalet tillgängliga siffror för att representera mantissan är 15 .

Detta är en mycket förenklad beskrivning av hur reella tal är uppbyggda.


3. Förlust av precision vid arbete med reella tal

När du arbetar med reella tal, tänk alltid på att reella siffror inte är exakta . Det kan alltid finnas avrundningsfel och konverteringsfel vid konvertering från decimal till binär. Dessutom är den vanligaste felkällan förlust av precision när man adderar/subtraherar tal på radikalt olika skalor.

Detta sista faktum är lite häpnadsväckande för nybörjare.

Om vi ​​subtraherar från får vi .1/109109109

Subtrahera tal på radikalt olika skalor Förklaring
 1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
Det andra numret är extremt litet , vilket gör att dess signifikans (markerad i grått) ignoreras. De 15 signifikanta siffrorna är markerade i orange.

Vad kan vi säga, programmering är inte detsamma som matematik.


4. Fallgrop när man jämför reella tal

En annan fara ligger och väntar för programmerare när de jämför reella tal. Det uppstår när man arbetar med reella tal, eftersom avrundningsfel kan ackumuleras. Resultatet är att det finns situationer när reella tal förväntas vara lika, men de är det inte. Eller vice versa: siffrorna förväntas vara olika, men de är lika.

Exempel:

Påstående Förklaring
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
Variabelns värde a kommer att vara 1000000000.0
Variabelns värde c kommer att vara 1000000000.0
(talet i b variabeln är för litet)

I exemplet ovan, aoch cbör inte vara lika, men de är.

Eller låt oss ta ett annat exempel:

Påstående Förklaring
double a = 1.00000000000000001;
double b = 1.00000000000000002;
Variabelns värde a kommer att vara 1.0
Variabelns värde b kommer att vara1.0

5. Ett intressant faktum omstrictfp

Java har ett speciellt strictfpnyckelord ( strict f loating point ) , som inte finns i andra programmeringsspråk. Och vet du varför du behöver det? Det försämrar noggrannheten i operationer med flyttal. Här är historien om hur det blev:

Javas skapare:
Vi vill verkligen att Java ska vara superpopulärt och köra Java-program på så många enheter som möjligt. Så vi såg till att specifikationen för Java-maskinen säger att alla program måste köras på samma sätt på alla typer av enheter!
Tillverkare av Intel-processorer:
Hej allihopa! Vi har förbättrat våra processorer och nu representeras alla reella tal med 10-byte istället för 8-byte inuti våra processorer. Fler byte betyder mer signifikanta siffror. Vad betyder det? Det är rätt! Nu blir dina vetenskapliga beräkningar ännu mer exakta!
Forskare och alla inblandade i ultraexakta beräkningar:
Häftigt! Bra gjort. Fantastiska nyheter!
Javas skapare:
Nej-nej-nej, ni! Vi har redan sagt att alla Java-program måste köras likadant på alla enheter . Vi kommer att tvångsinaktivera möjligheten att använda 10-byte reella tal inuti Intel-processorer.
Nu är allt bra igen! Tacka oss inte.
Forskare och alla inblandade i ultraexakta beräkningar:
Har du blivit helt galen? Få snabbt tillbaka allt som det var!
Javas skapare:
Killar, det här är för ert eget bästa! Föreställ dig bara: alla Java-program körs på samma sätt på alla enheter . Det är så coolt!
Forskare och alla inblandade i ultraexakta beräkningar:
Nej. Det är inte alls coolt. Lägg snabbt tillbaka allt som det var! Eller vet du var vi lägger din Java?
Javas skapare:
Hmm. Varför sa du inte det direkt? Självklart lägger vi tillbaka den.
Vi har återställt din förmåga att använda alla funktioner i de senaste processorerna.
Förresten... Vi har också lagt till strictfpnyckelordet speciellt till språket. Om du skriver det före namnet på en funktion kommer alla operationer som involverar reella tal i den funktionen att vara lika dåliga på alla enheter !