Antal cifre i et heltal i Java

1. Introduktion

I denne hurtige vejledning udforsker vi forskellige måder at få antallet af cifre på Heltal i Java.

Vi analyserer også disse forskellige metoder og finder ud af, hvilken algoritme der passer bedst i vores situation.

2. Antal cifre i et Heltal

For metoderne diskuteret her overvejer vi kun positive heltal. Hvis vi forventer noget negativt input, kan vi først gøre brug af Math.abs (antal) inden du bruger en af ​​disse metoder.

2.1. Snor-Baseret løsning

Måske den nemmeste måde at få antallet af cifre i et Heltal er ved at konvertere det til Snorog kalder længde () metode. Dette vil returnere længden af Snor repræsentation af vores nummer:

int længde = String.valueOf (antal) .længde ();

Men dette kan være en suboptimal tilgang, da denne erklæring involverer hukommelsesallokering til en Streng for hver evaluering. JVM skal først analysere vores nummer og kopiere dets cifre til et separat Snor og også udføre en række forskellige operationer (som at opbevare midlertidige kopier, håndtere Unicode-konverteringer osv.).

Hvis vi kun har et par tal at evaluere, kan vi helt klart gå med denne løsning - fordi forskellen mellem denne og enhver anden tilgang vil være forsømmelig selv for store antal.

2.2. Logaritmisk tilgang

For de tal, der er repræsenteret i decimalform, hvis vi tager deres log i base 10 og afrunder det, så får vi antallet af cifre i det tal:

int længde = (int) (Math.log10 (nummer) + 1);

Noter det log100 af et hvilket som helst tal er ikke defineret. Så hvis vi forventer noget input med værdi 0, så kan vi også kontrollere det.

Den logaritmiske tilgang er betydeligt hurtigere end Snor baseret tilgang, da den ikke behøver at gennemgå processen med nogen datakonvertering. Det involverer bare en enkel, ligetil beregning uden ekstra initialisering af objekt eller sløjfer.

2.3. Gentagen multiplikation

I denne metode tager vi en midlertidig variabel (initialiseret til 1) og multiplicerer den kontinuerligt med 10, indtil den bliver større end vores antal. Under denne proces bruger vi også en længde variabel, som holder styr på nummerets længde:

int længde = 0; lang temp = 1; mens (temp <= antal) {længde ++; temp * = 10; } returlængde;

I denne kode, linjen temp * = 10 er det samme som at skrive temp = (temp << 3) + (temp << 1). Da multiplikation normalt er dyrere at arbejde på nogle processorer sammenlignet med skiftoperatører, kan sidstnævnte være lidt mere effektiv.

2.4. At dele med magt to

Hvis vi kender rækkevidden af ​​vores antal, kan vi bruge en variation, der yderligere reducerer vores sammenligninger. Denne metode deler antallet med kræfter på to (f.eks. 1, 2, 4, 8 osv.):

Denne metode opdeler antallet med kræfter på to (f.eks. 1, 2, 4, 8 osv.):

int længde = 1; hvis (nummer> = 100000000) {længde + = 8; nummer / = 100000000; } hvis (nummer> = 10000) {længde + = 4; antal / = 10000; } hvis (nummer> = 100) {længde + = 2; antal / = 100; } hvis (nummer> = 10) {længde + = 1; } returlængde;

Det udnytter det faktum, at ethvert tal kan repræsenteres ved tilføjelse af kræfter på 2. F.eks. Kan 15 repræsenteres som 8 + 4 + 2 + 1, som alle er kræfter på 2.

For et 15-cifret nummer ville vi lave 15 sammenligninger i vores tidligere tilgang, som vi har reduceret til kun 4 i denne metode.

2.5. Opdel og erobre

Dette er måske den største tilgang sammenlignet med alle andre beskrevet her, men det er overflødigt at sige, denne er den hurtigste fordi vi ikke udfører nogen form for konvertering, multiplikation, tilføjelse eller initialisering af objekt.

Vi får vores svar på kun tre eller fire enkle hvis udsagn:

hvis (nummer <100000) {hvis (nummer <100) {hvis (nummer <10) {returnerer 1; } andet {retur 2; }} andet {hvis (nummer <1000) {retur 3; } andet {hvis (nummer <10000) {retur 4; } andet {retur 5; }}}} ellers {if (nummer <10000000) {if (nummer <1000000) {return 6; } andet {retur 7; }} andet {hvis (nummer <100000000) {retur 8; } ellers {if (nummer <1000000000) {return 9; } andet {retur 10; }}}}

I lighed med den tidligere tilgang kan vi kun bruge denne metode, hvis vi kender rækkevidden af ​​vores nummer.

3. Benchmarking

Nu hvor vi har en god forståelse af de potentielle løsninger, lad os nu lave nogle enkle benchmarking af alle vores metoder ved hjælp af Java Microbenchmark Harness (JMH).

Følgende tabel viser den gennemsnitlige behandlingstid for hver operation (i nanosekunder):

Benchmark Mode Cnt Score Error Units Benchmarking.stringBasedSolution avgt 200 32.736 ± 0.589 ns / op Benchmarking.logarithmicApproach avgt 200 26.123 ± 0.064 ns / op Benchmarking.repeatedMultiplication avgt 200 7.494 ± 0.207 ns / op Benchmarking.dividingWithPowerso Benchmarking.divideAndConquer gennemsnit 200 0,956 ± 0,011 ns / op

Det Snor-baseret løsning, som er den enkleste, er også den dyreste operation - da dette er den eneste, der kræver datakonvertering og initialisering af nye objekter.

Den logaritmiske tilgang er betydeligt mere effektiv sammenlignet med den tidligere løsning - da den ikke involverer nogen datakonvertering. Og som en løsning med en linje kan det være et godt alternativ til Snor-baseret tilgang.

Gentagen multiplikation involverer simpel multiplikation, proportionalt med nummerlængden; for eksempel, hvis et tal er femten cifre langt, vil denne metode involvere femten multiplikationer.

Den næste metode udnytter imidlertid det faktum, at hvert nummer kan repræsenteres af kræfter på to (fremgangsmåden svarende til BCD) og reducerer det samme til 4 division operationer, så det er endnu mere effektivt end det tidligere.

Endelig, som vi kan udlede, den mest effektive algoritme er den detaljerede opdeling og erobring implementering - som leverer svaret på kun tre eller fire enkle if-udsagn. Vi kan bruge det, hvis vi har et stort datasæt med tal, vi skal analysere.

4. Konklusion

I denne korte artikel skitserede vi nogle af måderne til at finde antallet af cifre i et Heltal og vi sammenlignede effektiviteten af ​​hver tilgang.

Og som altid kan du finde den komplette kode på GitHub.