Large Optimized IO processing in Java - java

An input n of the order 10^18 and output should be the sum of all the numbers whose set bits is only 2. For e.g. n = 5 setbit is 101--> 2 set bits. For n = 1234567865432784,How can I optimize the below code?
class TestClass
{
public static void main(String args[])
{
long N,s=0L;
Scanner sc = new Scanner(System.in);
N=sc.nextLong();
for(long j = 1; j<=N; j++)
{
long b = j;
int count = 0;
while(b!=0)
{
b = b & (b-1);
count++;
}
if(count == 2)
{
s+=j;
count = 0;
}
else
{
count = 0;
continue;
}
}
System.out.println(s%1000000007);
s=0L;
}
}

Java has a function
if (Integer.bitCount(i) == 2) { ...
However consider a bit: that are a lot of numbers to inspect.
What about generating all numbers that have just two bits set?
Setting the ith and jth bit of n:
int n = (1 << i) | (1 << j); // i != j
Now consider 31² steps, not yet 1000 with N steps.
As this is homework my advise:
Try to turn the problem around, do the least work, take a step back, find the intelligent approach, search the math core. And enjoy.
Next time, do not spoil yourself of success moments.

As you probably had enough time to think about Joop Eggen's suggestion,
here is how i would do it (which is what Joop described i think):
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
long sum = 0;
for (int firstBitIndex = 0; firstBitIndex < 64; firstBitIndex++) {
long firstBit = 1L << firstBitIndex;
if (firstBit >= n)
break;
for (int secondBitIndex = firstBitIndex + 1; secondBitIndex < 64; secondBitIndex++) {
long value = firstBit | (1L << secondBitIndex);
if (value > n)
break;
sum += value;
}
}
System.out.println(sum % 1000000007);
sc.close();
}
}

Java provides the class BigInteger, which includes a method nextProbablePrime(). This means you could do something like this:
BigInteger n = new BigInteger(stringInputN);
BigInteger test = BigInteger.valueOf(2);
BigInteger total = BigInteger.valueOf(0);
while (test.compareTo(n) < 0){
total = total.add(test);
test = test.nextProbablePrime();
}
System.out.println(total);
This this has an extremely low probability of getting the wrong answer (but nonzero), so you might want to run it twice just to doublecheck. It should be faster than manually iterating it by hand though.

Related

Why doesn't my Fibonacci number with BigInteger that is 50000th number does not match with this website?

My Fibonacci Number Sequence Generator is something like below:
import java.math.BigInteger;
public class FibonacciGerenrate {
public static void FibonacciGenSerial(int n) {
BigInteger bgIntX = BigInteger.valueOf(0L);
BigInteger bgIntY = BigInteger.valueOf(1L);
BigInteger bgSwap = BigInteger.valueOf(0L);
BigInteger bgSwap2 = BigInteger.valueOf(0L);
for (long i = 0; i < n; ++i) {
if (i == 0) {
System.out.println(bgIntX);
}
if (i == 1) {
System.out.println(bgIntY);
}
if (i > 1) {
bgSwap = bgIntY;
//bgSwap2 = bgIntX;
bgSwap2 = bgSwap.add(bgIntX);
System.out.println(bgSwap2);
bgIntX = bgIntY;
bgIntY = bgSwap2;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
FibonacciGenSerial(50000);
}
}
But after two minutes the result of my 50000th Fibonacci number is given below. And it doesn't match with the output result of the following website. Why is that? Am I wrong? How can I fix it?
666100648565481205010951547560750933431950479937080994773751415475329647357449820574055869101354533179842571730518504252690058309030165957793611893184804604322634950697308315493285225827521968081167628872452768615738108939224876141123321314473270269465000697651877688322772577296187089266717271846243032342710169463007536900896948726682347470396722227545422828097990563697789828879621460065715309733855859315802250715487615816509617290450469997736430690473288367991638342872414940097748223932840620504428668520921655344430301224215692897710294618083941298394708009681899419228230959458929147242702905587860930816067641195022945573432258310501457406158453985387540996675518570815051459141923719868534748290307729399974816799507877982414057300447384236578708136869220018082040204979278639844104757994501020243076351266748128805893493483388168490769849952216805657010874821090514296406355110553853620293655313964806869929662365912232407486790482290214419052737478156102371122601126269716933969142851424928376050243479723763826825290719288650668925541910835478719090753282030915936853660001042090112056551037656921633144893206490532744723980391060344012105109041485463735778178695972346419842041360816069653760816717602148456722833643023802496324551697060976893855597905167037325153206289367148296194735202448911826351569038642836373273388438749220506838097571642903225609197374346730325128298541730100868662836408370652884683285634505652640553978383638747687616980404728716061328452648302998982054812903248737902508504748147966013614486993459268653853968661755091110112836831904518162502479003093926076241103832746864779503324612870238425655535310753031768424140386727074621268211011923361554582637672555763296766763854351892413797277286060361458119987282967951684241873325465716615261286317039991891544731713205149083895650120764948564143504675774742730781931928449575390256866738150275504189195079536502592392448642504625645222976625257159399314999623324197626795103321718324580761387037914189285639982327419211417271975071509612777714938378809871158377357033535038841919249248086467043409693138137112595014692834270711500010138506524349690071946393449648099208714463687090366864945411336246942663509789781079889019967268789357869074643331574973686481450223653389822460520183558105963223746605217997222387889751383509988082580944620464366163610679825916386927892295095374801191974096436340267734433730251299313389962413993201863403083841538686348160621073767578057926062012975065413640006600693103780549028905864574886005678966392854693541230730899811945995142389153270240354100999411437018828868859400252967613211726276446551737789380742131931227839657181988118865833480816151389108105528537216403964625087028986820520228715010685007591856614514778740893057418957567038483687071966812519841489146071253869889423050709567596610799719867036770761423744800930144446719985845639071948611549514167774740990909139060327587087707067165105903518512015008461478015071165612693027121166154673444805231514777642042786026879557204719340331591136844403791499153922402086325805819134623464621695959806096503918813601014444481497906000448189658304143531211623553079844917054983082998776950836009095453318030659296363742980120743822658798934449668379206415174607506093762182254110615681569717083211494114018772250097676725941157779174932734820568414226363304237968436842248075823282963543871105638202916945277814768864354916760621028779029538705578282925816579093772231288716013708194434438394149151491195572603314854012840149606398382269625517147771137052311883362797842053344005270594854159706295373797302632356629421276081517886019790032658026956610798949752129107805929458801027179475571809611111740758763373153476180800487503600606253740331201651721614058623392972202709529281690876761917422759364320015857427391270406331078878439305356665324344974924966088691546853401573510776119213632887236814855337852815095530230952927329556374671331803148352243251263283265128614261836045147294319819688471388326969417579904757464922708053628945150223335578551759081194695982876790011669825263518704133543095719051298714606579941128392101513434827920391242277081025094359551288317988893709534781978393945117097207076724791494616138837298981254940507843176701027248285993023860493750030475545967637215092330757914527051682535238578874169416419343826813276679317873998472471749686675765314934017559446883914428510562722864433439498146495120119913901346238077941728002849108235739773630267418055647587363776504486028675431129509545059403089455946519091959257301580675673458296214369105815004711115705568732078472962138306788772718702122766701488203167194502460046797772368844117678537000296384367003298371856809743914987011520470356450353074991325681614617984049912889619058746341502133349510556965392824027344424606453707377080729843402550151444160443240205434479868981609992585944572035786195485899532860763384337256250361518098480850231197439501006641686919198156639962949704149039218332928999679805750001308229279436709963263406239794882894065682638778935094093844765547146298281525989658002832701160413802748514986615725425904543562884354377218482717540397490074759993076664214614879978262310338197341128247873923938475147973518208725384873960246416763890489102999975017553478512459882618858334522285043766936484250110365909823001346728831403112210757004910897939860331633776262670716334868107386964506795963587304507408784081379727762610979152292320358478558706063821848616759228308451800969357027404759064318842378084092315173807524269604159146455211809665956036125198199064555802995538741179855329046922085858818028719242720320756267564991603927439237662286873972153269427651011235776687764275443675406561338563010027840718479862348591917953933994821284372280834889531645178403889948454266146190305939429767502629047826504253391658577635431374402785042293344010121069723509203600429348621981859733004535580888240359962243091362619987113834608216353140281542703151377407446724934788657087070356643740959095887668655129378518257991750140164754529691806673352241155899083959191871012780666725664381728302763413740883234510412767276595568556388063610723825329062674666971943247295036113072723265285584887408747520460330374437559798490506055045514064213832024627976351774570181205497658698375716324872741302409695277078424193438335439292377835057730034036145478052900402863148060495085323281842554651451036178213074357384018808581022331092529011187533277675824202856654414408717211908307376739819453635469072101848013176903862214060551709095000905074280971252452952909536451044791498647604893557873228056987657309671604147796665461589224998202540292423728222584648338588736664143022108815460974616828866988926345892872995571292422421773913479426380919060101391760420261420730453554287085513644899186880442361412631217758879550052882439598889457830856779410842513718768766091275135456380178178300617147751177790796952021354316582389053446353859076939551592384382774428962913131759132408131282868099485912859413029256311254587488212460831011124533510559924989863658143059250059774988707261404862833412102527976188330569397378668933475880809400830766736994040555356783641599760677810636466319728397018292100355127463837362740187333750034023892811300477151403790798603023100128610555550613790049616753892668808336749283366803306386255139739200520795547147713447959609503199036667286329077255924746918923652728312207868221104322516466728395553078246174620007843839145562059618308045132403907998960823112902275962909973027107655355753904048396067828089331591269404084934464120850296853594525628909527716103596016612755534356543244626443354995929675356741004157822959814523198218428406546177374802501921215250213079420934002604758784198250768562575771064769772000368187985559402552864559144184644579246642229835234324930558261825479606065297775518810717430372785680588824256604595020620542104279192252958742341699434491865985473991665889763758076619448944029251378170452192928104719929641595346467381297599346164809015557379482897429306632382718572359080200580125769912394268937425208471739498198294039857540747406725444057946732876949278204480286629256472353068058903699307994090916485647143450897246288120405624044272974581328543171842457960024273937994430303017416394043067083128885809213554212555454076560792542180784246519970324808557913497445167628369709876846332995607902679917364426349371775777894415979568094641873322943199022719563252749184400889845604530664204285868733579775816968832666680229105313367395422727986751689021732800376241526129309622574934865789670249661111729875503959405546498195859589055079973719910765291871059200578848376091382450827936346881093595641008636086660186437476419800866837924558581042971863841046902667299007595753977851094063304503639295603862415053601506791945752875688662852884259197089038836135664288165187408459281783504155854777313151613458774746417419908057567542628145693509766340480961263449080763343524370041474279899270297150716040301621228556313386834331553726237194024539232248304826810025215970632165794694360001925915558517317086796919038131136526735629682618234254690009699824548131542889727269915091378373526676061198785310756633059057477359341351019021807301233526081109778738179038665569950748548783317916516531990441083102618945701517010622590869651328033237579383625761930852080497002516434690134150677105528818731097339202012653039585356617091832439042951712221740827068604212723039524324615603136864188680891174417641489121494660755507003886549855291095862457104577939327455945605614519889510432311246894620989335653836679059538065437524829322117732552766511970700736821870037554214173785971048690499128614852714423373079479669815004079790437478405606774318669283764771464300583751653017433237361104801425733258035970901068212527401383741872107655688495567909246297629646550462643273447770343300210223279668754011716842718361977583092506467739884269913691250449405207875729401675856977466707283966223128881659500958944593836216397235863285323613591565012073847795737172930233933594485324619433561564931911914888793630226393645387832882895644605397261496725355227817783507292619445421611950535223331719341500756971803362136404519452880893229885903007294748984670394618952806821098740393146788700124820764553041872496073332651308037095119882100202710186702753433978399149908454238724269918322749507909772992037226532802201150761626111638906545107602875995114792979876216193958825864398145879704552311475748837637501
But this Fibonacci generator website outputs a different result:
50000th Fibonacci number by this website
Here we go:
public class FibonacciGerenrate {
public static void FibonacciGenSerial(int n) {
BigInteger bgIntX = BigInteger.valueOf(1L);
BigInteger bgIntY = BigInteger.valueOf(1L);
BigInteger result = BigInteger.valueOf(0L);
for (long i = 0; i < n; i++) {
if (i == 1) {
System.out.println(bgIntX);
}
if (i == 2) {
System.out.println(bgIntY);
}
if (i > 2) {
result = bgIntY;
result = result.add(bgIntX);
System.out.println("result: " + result);
bgIntX = bgIntY;
bgIntY = result;
}
}
}
public static void main(String[] args) {
FibonacciGenSerial(50000);
}
as the others already stated Fibonacci's sequence start from 1 not 0 . So basically, with your code you are getting the 49'999th Fibonacci's number.
I also improved your code to be a bit faster. No need for 2 swap fields.
Your number matches the 49999th number of the Fibonacci generator website you linked.
So i guess you have to do a little change in your for loop and add 1 iteration:
Change for(long i = 0; i < n;++i) { to for(long i = 0; i <= n;++i) {
You can avoid the 1 and 2 conditionals by simply printing out fib from the start, and then doing the swap.
Or you can just print 0 and 1 and then start the loop at i = 2, ensuring that you update the running series appropriately.
BigInteger start = BigInteger.ZERO;
BigInteger next = BigInteger.ONE;
BigInteger fib = start;
for (int i = 0; i < 10; i++) {
System.out.println(fib);
fib = start.add(next);
next = start;
start = fib;
}
Prints
0
1
1
2
3
5
8
13
21
34

Checking if the graph exist (java)

Determine whether there exists a graph with a sequence of degrees of vertices (s = s1, s2...sn).
What is the best and most optimized algorithm for solving this problem.
Input:
the first line contains `t<100` - amount of sequnces.
the second line contains value `n <= 1000000`(length of a sequence).
the third line contains contains `n` non-negative integer numbers. And so on.
Output:
if the graph can exist print "yes" otherwise print "no".
For example:
Input:
3
5
1 2 3 2 1
4
3 3 2 2
3
1 3 2
Output:
No
Yes
Yes
The maximum execution time should be 0.4 second.
Here is my code (If the number of odd vertices is even, then the graph exists):
import java.util.Scanner;
public class Main {
public static final Scanner in = new Scanner(System.in);
public static void isGraph (int []a, int n) {
int k=0;
for(int i=0; i< n; i++) {
if(a[i] %2 != 0) {
k++;
}
}
if(k%2 == 0)
System.out.println("Yes");
else
System.out.println("No");
}
public static void main(String[] args) throws Exception{
double t1 = System.nanoTime();
int n;
int []a;
int t = Integer.parseInt(in.nextLine());
while(t-- > 0) {
n = in.nextInt();
a = new int[n];
for(int i=0; i<n; i++)
a[i] = in.nextInt();
isGraph(a,n);
}
System.out.println(System.nanoTime() - t1);
}
}
But the execution time of this program is more than 0.4 second. I get run time exceeded. How I can optimize code and speed up runtime. May be there is another algorithm to solve this task, please help me.
I think I have a faster way for you. Please verify this. If you are concerned about the final outcome of even/odd, then there seems to be no reason to keep track of the k counter. You can keep a dynamic value of whether the running sequence is even or odd:
public static void isGraph (int []a, int n) {
int k = 0;
for(int i=0; i< n; i++) {
k += a[i] & 1;
}
if(k%2 == 0)
System.out.println("Yes");
else
System.out.println("No");
}
This might help your reading: I have no experience with it however, I got it from a competition website:
Slow way to read:
/** Read count integers using Scanner */
static int scanInteger(int count) {
Scanner scanner = new Scanner(input);
int last = 0;
while (count-- > 0) {
last = scanner.nextInt();
}
return last;
}
Faster way:
static int readIntegers(int count)
throws IOException {
BufferedReader reader = new BufferedReader(
new InputStreamReader(input) );
StringTokenizer tokenizer = new StringTokenizer("");
int last = 0;
while (count-- > 0) {
if (! tokenizer.hasMoreTokens() ) {
tokenizer = new StringTokenizer(reader.readLine());
}
last = Integer.parseInt(tokenizer.nextToken());
}
return last;
}
EDIT: to show how to avoid two phases where Phase 1 is the read loop, and Phase 2 is the algorithm:
public static void main(String[] args) throws Exception{
double t1 = System.nanoTime();
int n;
// int []a; // Not necessary
int t = Integer.parseInt(in.nextLine());
while(t-- > 0) {
n = in.nextInt();
// a = new int[n]; // Not necessary
int k = 0;
int a;
for(int i=0; i<n; i++) {
a = in.nextInt();
k += a & 1;
}
// isGraph(a,n); // Not necessary
if(k % 2 == 0)
System.out.println("Yes");
else
System.out.println("No");
}
System.out.println(System.nanoTime() - t1);
}
May be there is another algorithm to solve this task
That's not the problem (IMO).
Hint 1: since you know the length of the sequence beforehand, you can create the array and parse the sequence faster than this:
a = Arrays.stream(s.split(" ")).mapToInt(Integer::parseInt).toArray();
(Java 8+ streams are elegant, but they are not the fastest way.)
Hint 2: using Scanner is probably faster than reading strings and parsing them.
Hint 3: you could probably avoid creating an array entirely. (It would be poor coding practice IMO ... but if performance is critical ...)

Hashmap memoization slower than directly computing the answer

I've been playing around with the Project Euler challenges to help improve my knowledge of Java. In particular, I wrote the following code for problem 14, which asks you to find the longest Collatz chain which starts at a number below 1,000,000. It works on the assumption that subchains are incredibly likely to arise more than once, and by storing them in a cache, no redundant calculations are done.
Collatz.java:
import java.util.HashMap;
public class Collatz {
private HashMap<Long, Integer> chainCache = new HashMap<Long, Integer>();
public void initialiseCache() {
chainCache.put((long) 1, 1);
}
private long collatzOp(long n) {
if(n % 2 == 0) {
return n/2;
}
else {
return 3*n +1;
}
}
public int collatzChain(long n) {
if(chainCache.containsKey(n)) {
return chainCache.get(n);
}
else {
int count = 1 + collatzChain(collatzOp(n));
chainCache.put(n, count);
return count;
}
}
}
ProjectEuler14.java:
public class ProjectEuler14 {
public static void main(String[] args) {
Collatz col = new Collatz();
col.initialiseCache();
long limit = 1000000;
long temp = 0;
long longestLength = 0;
long index = 1;
for(long i = 1; i < limit; i++) {
temp = col.collatzChain(i);
if(temp > longestLength) {
longestLength = temp;
index = i;
}
}
System.out.println(index + " has the longest chain, with length " + longestLength);
}
}
This works. And according to the "measure-command" command from Windows Powershell, it takes roughly 1708 milliseconds (1.708 seconds) to execute.
However, after reading through the forums, I noticed that some people, who had written seemingly naive code, which calculate each chain from scratch, seemed to be getting much better execution times than me. I (conceptually) took one of the answers, and translated it into Java:
NaiveProjectEuler14.java:
public class NaiveProjectEuler14 {
public static void main(String[] args) {
int longest = 0;
int numTerms = 0;
int i;
long j;
for (i = 1; i <= 10000000; i++) {
j = i;
int currentTerms = 1;
while (j != 1) {
currentTerms++;
if (currentTerms > numTerms){
numTerms = currentTerms;
longest = i;
}
if (j % 2 == 0){
j = j / 2;
}
else{
j = 3 * j + 1;
}
}
}
System.out.println("Longest: " + longest + " (" + numTerms + ").");
}
}
On my machine, this also gives the correct answer, but it gives it in 0.502 milliseconds - a third of the speed of my original program. At first I thought that maybe there was a small overhead in creating a HashMap, and that the times taken were too small to draw any conclusions. However, if I increase the upper limit from 1,000,000 to 10,000,000 in both programs, NaiveProjectEuler14 takes 4709 milliseconds (4.709 seconds), whilst ProjectEuler14 takes a whopping 25324 milliseconds (25.324 seconds)!
Why does ProjectEuler14 take so long? The only explanation I can fathom is that storing huge amounts of pairs in the HashMap data structure is adding a huge overhead, but I can't see why that should be the case. I've also tried recording the number of (key, value) pairs stored during the course of the program (2,168,611 pairs for the 1,000,000 case, and 21,730,849 pairs for the 10,000,000 case) and supplying a little over that number to the HashMap constructor so that it only has to resize itself at most once, but this does not seem to affect the execution times.
Does anyone have any rationale for why the memoized version is a lot slower?
There are some reasons for that unfortunate reality:
Instead of containsKey, do an immediate get and check for null
The code uses an extra method to be called
The map stores wrapped objects (Integer, Long) for primitive types
The JIT compiler translating byte code to machine code can do more with calculations
The caching does not concern a large percentage, like fibonacci
Comparable would be
public static void main(String[] args) {
int longest = 0;
int numTerms = 0;
int i;
long j;
Map<Long, Integer> map = new HashMap<>();
for (i = 1; i <= 10000000; i++) {
j = i;
Integer terms = map.get(i);
if (terms != null) {
continue;
}
int currentTerms = 1;
while (j != 1) {
currentTerms++;
if (currentTerms > numTerms){
numTerms = currentTerms;
longest = i;
}
if (j % 2 == 0){
j = j / 2;
// Maybe check the map only here
Integer m = map.get(j);
if (m != null) {
currentTerms += m;
break;
}
}
else{
j = 3 * j + 1;
}
}
map.put(j, currentTerms);
}
System.out.println("Longest: " + longest + " (" + numTerms + ").");
}
This does not really do an adequate memoization. For increasing parameters not checking the 3*j+1 somewhat decreases the misses (but might also skip meoized values).
Memoization lives from heavy calculation per call. If the function takes long because of deep recursion rather than calculation, the memoization overhead per function call counts negatively.

Getting a list of binary numbers composing a number

In Java, having a number like 0b1010, I would like to get a list of numbers "composing" this one: 0b1000 and 0b0010 in this example: one number for each bit set.
I'm not sure about the best solution to get it. Do you have any clue ?
Use a BitSet!
long x = 0b101011;
BitSet bs = BitSet.valueOf(new long[]{x});
for (int i = bs.nextSetBit(0); i >=0 ; i = bs.nextSetBit(i+1)) {
System.out.println(1 << i);
}
Output:
1
2
8
32
If you really want them printed out as binary strings, here's a little hack on the above method:
long x = 0b101011;
char[] cs = new char[bs.length()];
Arrays.fill(cs, '0');
BitSet bs = BitSet.valueOf(new long[]{x});
for (int i = bs.nextSetBit(0); i >=0 ; i = bs.nextSetBit(i+1)) {
cs[bs.length()-i-1] = '1';
System.out.println(new String(cs)); // or whatever you want to do with this String
cs[bs.length()-i-1] = '0';
}
Output:
000001
000010
001000
100000
Scan through the bits one by one using an AND operation. This will tell you if a bit at one position is set or not. (https://en.wikipedia.org/wiki/Bitwise_operation#AND). Once you have determined that some ith-Bit is set, make up a string and print it. PSEUDOCODE:
public static void PrintAllSubbitstrings(int number)
{
for(int i=0; i < 32; i++) //32 bits maximum for an int
{
if( number & (1 << i) != 0) //the i'th bit is set.
{
//Make up a bitstring with (i-1) zeroes to the right, then one 1 on the left
String bitString = "1";
for(int j=0; j < (i-1); j++) bitString += "0";
System.out.println(bitString);
}
}
}
Here is a little test that works for me
public static void main(String[] args) {
int num = 0b1010;
int testNum = 0b1;
while(testNum < num) {
if((testNum & num) >0) {
System.out.println(testNum + " Passes");
}
testNum *= 2;
}
}

Improving a prime sieve algorithm

I'm trying to make a decent Java program that generates the primes from 1 to N (mainly for Project Euler problems).
At the moment, my algorithm is as follows:
Initialise an array of booleans (or a bitarray if N is sufficiently large) so they're all false, and an array of ints to store the primes found.
Set an integer, s equal to the lowest prime, (ie 2)
While s is <= sqrt(N)
Set all multiples of s (starting at s^2) to true in the array/bitarray.
Find the next smallest index in the array/bitarray which is false, use that as the new value of s.
Endwhile.
Go through the array/bitarray, and for every value that is false, put the corresponding index in the primes array.
Now, I've tried skipping over numbers not of the form 6k + 1 or 6k + 5, but that only gives me a ~2x speed up, whilst I've seen programs run orders of magnitudes faster than mine (albeit with very convoluted code), such as the one here
What can I do to improve?
Edit: Okay, here's my actual code (for N of 1E7):
int l = 10000000, n = 2, sqrt = (int) Math.sqrt(l);
boolean[] nums = new boolean[l + 1];
int[] primes = new int[664579];
while(n <= sqrt){
for(int i = 2 * n; i <= l; nums[i] = true, i += n);
for(n++; nums[n]; n++);
}
for(int i = 2, k = 0; i < nums.length; i++) if(!nums[i]) primes[k++] = i;
Runs in about 350ms on my 2.0GHz machine.
While s is <= sqrt(N)
One mistake people often do in such algorithms is not precomputing square root.
while (s <= sqrt(N)) {
is much, much slower than
int limit = sqrt(N);
while (s <= limit) {
But generally speaking, Eiko is right in his comment. If you want people to offer low-level optimisations, you have to provide code.
update Ok, now about your code.
You may notice that number of iterations in your code is just little bigger than 'l'. (you may put counter inside first 'for' loop, it will be just 2-3 times bigger) And, obviously, complexity of your solution can't be less then O(l) (you can't have less than 'l' iterations).
What can make real difference is accessing memory effectively. Note that guy who wrote that article tries to reduce storage size not just because he's memory-greedy. Making compact arrays allows you to employ cache better and thus increase speed.
I just replaced boolean[] with int[] and achieved immediate x2 speed gain. (and 8x memory) And I didn't even try to do it efficiently.
update2
That's easy. You just replace every assignment a[i] = true with a[i/32] |= 1 << (i%32) and each read operation a[i] with (a[i/32] & (1 << (i%32))) != 0. And boolean[] a with int[] a, obviously.
From the first replacement it should be clear how it works: if f(i) is true, then there's a bit 1 in an integer number a[i/32], at position i%32 (int in Java has exactly 32 bits, as you know).
You can go further and replace i/32 with i >> 5, i%32 with i&31. You can also precompute all 1 << j for each j between 0 and 31 in array.
But sadly, I don't think in Java you could get close to C in this. Not to mention, that guy uses many other tricky optimizations and I agree that his could would've been worth a lot more if he made comments.
Using the BitSet will use less memory. The Sieve algorithm is rather trivial, so you can simply "set" the bit positions on the BitSet, and then iterate to determine the primes.
Did you also make the array smaller while skipping numbers not of the form 6k+1 and 6k+5?
I only tested with ignoring numbers of the form 2k and that gave me ~4x speed up (440 ms -> 120 ms):
int l = 10000000, n = 1, sqrt = (int) Math.sqrt(l);
int m = l/2;
boolean[] nums = new boolean[m + 1];
int[] primes = new int[664579];
int i, k;
while (n <= sqrt) {
int x = (n<<1)+1;
for (i = n+x; i <= m; nums[i] = true, i+=x);
for (n++; nums[n]; n++);
}
primes[0] = 2;
for (i = 1, k = 1; i < nums.length; i++) {
if (!nums[i])
primes[k++] = (i<<1)+1;
}
The following is from my Project Euler Library...Its a slight Variation of the Sieve of Eratosthenes...I'm not sure, but i think its called the Euler Sieve.
1) It uses a BitSet (so 1/8th the memory)
2) Only uses the bitset for Odd Numbers...(another 1/2th hence 1/16th)
Note: The Inner loop (for multiples) begins at "n*n" rather than "2*n" and also multiples of increment "2*n" are only crossed off....hence the speed up.
private void beginSieve(int mLimit)
{
primeList = new BitSet(mLimit>>1);
primeList.set(0,primeList.size(),true);
int sqroot = (int) Math.sqrt(mLimit);
primeList.clear(0);
for(int num = 3; num <= sqroot; num+=2)
{
if( primeList.get(num >> 1) )
{
int inc = num << 1;
for(int factor = num * num; factor < mLimit; factor += inc)
{
//if( ((factor) & 1) == 1)
//{
primeList.clear(factor >> 1);
//}
}
}
}
}
and here's the function to check if a number is prime...
public boolean isPrime(int num)
{
if( num < maxLimit)
{
if( (num & 1) == 0)
return ( num == 2);
else
return primeList.get(num>>1);
}
return false;
}
You could do the step of "putting the corresponding index in the primes array" while you are detecting them, taking out a run through the array, but that's about all I can think of right now.
I wrote a simple sieve implementation recently for the fun of it using BitSet (everyone says not to, but it's the best off the shelf way to store huge data efficiently). The performance seems to be pretty good to me, but I'm still working on improving it.
public class HelloWorld {
private static int LIMIT = 2140000000;//Integer.MAX_VALUE broke things.
private static BitSet marked;
public static void main(String[] args) {
long startTime = System.nanoTime();
init();
sieve();
long estimatedTime = System.nanoTime() - startTime;
System.out.println((float)estimatedTime/1000000000); //23.835363 seconds
System.out.println(marked.size()); //1070000000 ~= 127MB
}
private static void init()
{
double size = LIMIT * 0.5 - 1;
marked = new BitSet();
marked.set(0,(int)size, true);
}
private static void sieve()
{
int i = 0;
int cur = 0;
int add = 0;
int pos = 0;
while(((i<<1)+1)*((i<<1)+1) < LIMIT)
{
pos = i;
if(marked.get(pos++))
{
cur = pos;
add = (cur<<1);
pos += add*cur + cur - 1;
while(pos < marked.length() && pos > 0)
{
marked.clear(pos++);
pos += add;
}
}
i++;
}
}
private static void readPrimes()
{
int pos = 0;
while(pos < marked.length())
{
if(marked.get(pos++))
{
System.out.print((pos<<1)+1);
System.out.print("-");
}
}
}
}
With smaller LIMITs (say 10,000,000 which took 0.077479s) we get much faster results than the OP.
I bet java's performance is terrible when dealing with bits...
Algorithmically, the link you point out should be sufficient
Have you tried googling, e.g. for "java prime numbers". I did and dug up this simple improvement:
http://www.anyexample.com/programming/java/java_prime_number_check_%28primality_test%29.xml
Surely, you can find more at google.
Here is my code for Sieve of Erastothenes and this is actually the most efficient that I could do:
final int MAX = 1000000;
int p[]= new int[MAX];
p[0]=p[1]=1;
int prime[] = new int[MAX/10];
prime[0]=2;
void sieve()
{
int i,j,k=1;
for(i=3;i*i<=MAX;i+=2)
{
if(p[i])
continue;
for(j=i*i;j<MAX;j+=2*i)
p[j]=1;
}
for(i=3;i<MAX;i+=2)
{
if(p[i]==0)
prime[k++]=i;
}
return;
}

Categories