# Prime Generator Timing

• (2 Pages)
• 1
• 2

## 17 Replies - 2907 Views - Last Post: 31 December 2009 - 11:44 PMRate Topic: //<![CDATA[ rating = new ipb.rating( 'topic_rate_', { url: 'http://www.dreamincode.net/forums/index.php?app=forums&module=ajax&section=topics&do=rateTopic&t=142965&amp;s=fbbba09c17ada0cbb62bba0b2f6698a5&md5check=' + ipb.vars['secure_hash'], cur_rating: 0, rated: 0, allow_rate: 0, multi_rate: 1, show_rate_text: true } ); //]]>

### #1 noctolater

Reputation: 3
• Posts: 72
• Joined: 29-April 09

# Prime Generator Timing

Posted 02 December 2009 - 05:38 PM

I have written a prime number program that creates and saves prime numbers. I am constantly working on ways to improve its efficiency, even though I know that a sieve method would work better. But, I am starting to have trouble figuring out how much more efficient I have made it. I was wondering what everyone thought in terms of how I could implement a timer, so I can see how long it takes to test through a million numbers or so. That way I can clearly see how much efficiency I am gaining.

Here's the code for the program:

```import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.text.DecimalFormat;

/**
* Primes is my experiments with prime number generation.
*
* version 1.0 -uses Integers, up to a maximum value of around 2 * 10^9.
*
* version 2.0 - uses Longs, up to a maximum value of around 9 * 10^18.
*
* version 3.0 - uses BIG_DECIMAL, up to a maximum value of whatever fits in
* memory.
*
* @author Sam Lanzo
* @version 2.0
*/
public class Primes {
private static int increment = 4;
private static BufferedWriter writer;
private static final JFrame frame = new JFrame("Primes");
private static JLabel progress = new JLabel("");
private static final JButton quit = new JButton("QUIT");
private static final long MAXIMUM = Long.MAX_VALUE;
private static boolean run = true;
private static long lastPrime = -1;

/**
* setConstraints creates the parameters for the simple GUI window that
* displays the status of the prime number algorithm.
*/
public static void setConstraints() {
frame.setLayout(new GridBagLayout());
frame.setSize(250, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
}

/**
* updateView updates the simple GUI window to display the current progress
* of the prime number algorithm.
*/
public static void updateView(long lastPrime) {
frame.getContentPane().removeAll();
Primes.view(lastPrime);
frame.repaint();
}

/**
* view creates a simple window displaying the last known prime, and a quit
* button that saves the progress.
*/
public static void view(final long lastPrime) {
DecimalFormat latestPrime = new DecimalFormat("###,###,###,###,###,###");
DecimalFormat percentFormat = new DecimalFormat("##.###########%");
GridBagConstraints c = new GridBagConstraints();
double percent = lastPrime / (double) MAXIMUM;
progress = new JLabel("<html>Last Prime Checked: "
+ latestPrime.format(lastPrime) + "<P>Percent Done: "
+ percentFormat.format(percent));

c.gridy = 1;
/**
* This will break the loop of the prime search, saving the last
* prime and closing the program.
*
* @param theEvent
*			and ActionEvent
*/
public void actionPerformed(ActionEvent theEvent) {
run = false;
}
});
frame.validate();
frame.repaint();
}

/**
* readLastPrime reads the last known prime from the disk, allowing the
* program to restart where it had left off.
*/
try {
"lastPrime.txt"));
// if this is true, then you add 4 to skip the multiple of 3.
if ((lastPrime + 2) % 3 == 0) {
increment = 4;
} else {
increment = 2;
}
} catch (Exception ex) {
System.out.println("Exception: " + ex);
}
}

/**
* addPrimeadds the last known prime to the end of the prime number file. It
* breaks the prime list into files that contain all the primes within a
* range of 1 billion.
*/
public static void addPrime(long lastPrime) {
try {
long fileNumber = lastPrime / 1000000000;
writer = new BufferedWriter(new FileWriter("primes" + fileNumber
+ ".txt", true));
writer.write("" + lastPrime);
writer.newLine();
writer.flush();
} catch (Exception ex) {
System.out.println("Exception: " + ex);
}
}

/**
* writeLastPrime writes the last known prime to disk, allowing the program
* to begin again from where it left off.
*/
public static void writeLastPrime(long lastPrime) {
try {
writer = new BufferedWriter(new FileWriter("lastPrime.txt"));
writer.write("" + lastPrime);
writer.close();
} catch (Exception ex) {
System.out.println("Exception: " + ex);
}
}

/**
* multipleOfFive simply checks the last digit of the number to see if it's
* a 5, and therefore a multiple of 5.
*/
public static boolean multipleOfFive(long suspectPrime) {
String suspectedPrime = "" + suspectPrime;
if (suspectedPrime.substring(suspectedPrime.length() - 1).equals("5")) {
return false;
}
return true;
}

/**
* isPrime checks if a number is prime. First it checks the number against a
* multiple of 3 and 5. Then, it starts to go through the list of all known
* primes up to and including the square root of the number it is checking.
*
* Since it's reading primes0.txt, it will only work up to 1 billion
* squared, or 1 with 18 zeroes after it. Since Long.MAX_VALUE is a little
* more than 9 with 18 zeroes, it will stop being reliable after checking
* 1/9th of the numbers.
*
* 3,037,000,500 is what it should check up to for the whole range of
* Long.MAX_VALUE
*/
public static boolean isPrime(long suspectPrime) {
try {
"primes0.txt"));
if ((Primes.multipleOfFive(suspectPrime) == false)) {
return false;
} // squareRoot rounds up to the nearest whole number.
long squareRoot = (long) (Math.sqrt(suspectPrime) + 1);

while (testPrime != 7) {
}
// while the number being tested as a factor is less than or equal
// to the square root, and it does not divide evenly into the
// suspect prime.
while ((testPrime <= (squareRoot))
&& (suspectPrime % testPrime != 0)) {
}
// if the last number tested is greater than the square root, none
// of the numbers tested were factors.
if (testPrime < (squareRoot)) {
return false;
}
} catch (Exception ex) {
System.out.println("Exception: " + ex);
}
return true;
}

/**
* main reads in the last known prime, adds 2, and starts checking if
* numbers are prime from there. It also updates the simple GUI to display
* the last known prime when 50,000 primes are found.
*/
public static void main(String args[]) {
if (lastPrime == -1) {
Primes.writeLastPrime(7);
}

Primes.setConstraints();
Primes.view(lastPrime);
int counter = 0;

for (long i = lastPrime + (long) increment; i > 0 && i <= MAXIMUM
&& run; i += (long) increment) {
if (Primes.isPrime(i)) {
lastPrime = i;
counter++;
} // for every 50,000 primes found, update the GUI.
if (counter == 50000) {
Primes.updateView(i);
counter = 0;
}
// adding 2 and 4 alternately automatically skips all multiples of 3.
switch (increment) {
case 2:
increment = 4;
break;
case 4:
increment = 2;
break;
}
} // if the quit button has been pressed.
if (!run) {
Primes.writeLastPrime(lastPrime);
System.exit(0);
}
Primes.writeLastPrime(lastPrime);
System.exit(0);
}

/**
* checkMethod checks if the program gets the right answer when it adds up
* all the prime numbers under 2 million.  This is merely here to make sure
* any changes to the class do not skip or include extra numbers.
*/
public static void checkMethod() {
try {
"primes0.txt"));
while ((nextPrime != null) && (Long.parseLong(nextPrime) < 2000000)) {
}
System.out.println(nextPrime);
} catch (Exception ex) {
System.out.println("Exception: " + ex);
}
}
}

```

Is This A Good Question/Topic? 0

## Replies To: Prime Generator Timing

### #2 mostyfriedman

• The Algorithmi

Reputation: 727
• Posts: 4,473
• Joined: 24-October 08

## Re: Prime Generator Timing

Posted 02 December 2009 - 05:55 PM

well you can use the System.currentTimeMillis() method, it will return the current time in milliseconds, call it before you run the prime generator and once again afterwards and subtract both times from each other to know how long did it take to run

### #3 noctolater

Reputation: 3
• Posts: 72
• Joined: 29-April 09

## Re: Prime Generator Timing

Posted 02 December 2009 - 06:34 PM

Java has so many commands that I don't even know to ask about, thanks!

Also, I was wondering about maybe making the program generate an Array List of 1,000 prime numbers, and having another method that dumped it to a file. I was really wondering if this would be possible using multiple threads, since my computer has a dual core. Does anyone know how feasible this is, and if there are any good guides to thread programming around?

This post has been edited by noctolater: 02 December 2009 - 06:35 PM

### #4 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 02 December 2009 - 11:22 PM

noctolater, on 2 Dec, 2009 - 05:34 PM, said:

Java has so many commands that I don't even know to ask about, thanks!

Also, I was wondering about maybe making the program generate an Array List of 1,000 prime numbers, and having another method that dumped it to a file. I was really wondering if this would be possible using multiple threads, since my computer has a dual core. Does anyone know how feasible this is, and if there are any good guides to thread programming around?

```class Prime {
int[] numbers = new int[1000];
....
// assuming numbers[] are filled
DumpNumbers dumpNumbers = new DumpNumbers(numbers);
dumpNumbers.start();
....

private int[] numbers;

// constructor
DumpNumbers(int[] numbers) {
this.numbers = numbers;
}

// will be invoke when you'll start() the thread
public void run() {
// open file
....
for(int i = 0; i < numbers.lenght; i++) {
... write numbers[i];
}
... close file
}   // end class DumpNumbers
}

```

Have fun

### #5 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 21 December 2009 - 09:14 PM

Took a few hours but here is a good compromise between efficiency and a nice GUI
It use the Erathosthene sieve algorithm.

Usually Eratosthene algorithm used a BitSet but if we want to check uo to Long.MAX_VALUE which is 19 digits long it wont fit int memory and we need to be able to run the program in multiple steps.

So I wrote a class that is used to set/clear bit in a file so the file, if you run the program up to Long.MAX_VALUE will be Long.MAX_VALUE / 8 size
I have already post that class in the CodeSnippet but here it is again so everything will be grouped together
```import java.io.*;

/*
* Mimics the behaviour of a Java standard API BitSet class but use a file as storage
* (Usefull for the ones who wants to play with the Eratosthene sieve algorithm)
*/
public class BitSetFile {

// to set or clear a bit
static final int[] SET = {1, 2, 4, 8, 16, 32, 64, 128};
// the file used to stored the bits
protected RandomAccessFile raf;
// lastByte accessed
private byte lastByteAccessed;
// its position in file
private long lastBytePosition = -1;
/*
* Constructors that receive the File as parameter
*/
public BitSetFile(File file) throws IOException {
raf = new RandomAccessFile(file, "rws");
}

/*
* returns the length in bytes
*/
public long length(){
try {
return raf.length();
}
catch(IOException e) {
return 0;
}
}

/*
* Set a bit
*/
public void set(long bit) throws IOException {
set(bit, true);
}
/*
* Clear a bit
*/
public void clear(long bit) throws IOException {
set(bit, false);
}
/*
* Clear or set the bit
*/
private void set(long bit, boolean state) throws IOException {
long fileOffset = bit / 8;
int bitOffset = (int) bit % 8;

// if it is not the same byte as the one I have in cache
if(fileOffset != lastBytePosition) {
raf.seek(fileOffset);	   // might throw an IOException
try {
}
catch(EOFException e) {  // but catch if after end of file
lastByteAccessed = 0;
}
lastBytePosition = fileOffset;
}
// save stored byte (we wont update if it does not change)
byte saved = lastByteAccessed;
if(state)
lastByteAccessed |= SET[bitOffset];
else
lastByteAccessed &= ~SET[bitOffset];
// if it changes nothing exit
if(saved == lastByteAccessed)
return;
// ok write it (that might throw an exception)
writeByte(fileOffset, lastByteAccessed);
}

/*
* Returns if a bit is set or not
*/
public boolean get(long bit) throws IOException{
// the byte to use
long filePos = bit / 8;
// if it is not the one already cached
if(filePos != lastBytePosition) {
raf.seek(filePos);	   // might throw an IOException
try {
}
catch(EOFException e) {  // but catch if after end of file
lastByteAccessed = 0;
}
// in both case that will be the next position
lastBytePosition = filePos;
}
int bitOffset = (int) bit % 8;
byte shifted = (byte) (lastByteAccessed >>> bitOffset);
return (shifted & 1) == 1;
}

/*
*  return the last bit set
*  -1 if none
*/
long getLastBitSet() throws IOException {
long lastSet = length();
// if file empty returns -1
if(lastSet == 0)
return -1L;
// the max value will be 8 * that offset
long maxVal = lastSet * 8;
for(long i = maxVal; i >= 0; i--) {
if(get(i))
return i;
}
return -1;
}

/*
* Write the pending byte
*/
private void writeByte(long bytePos, byte byteToWrite) throws IOException{
raf.seek(bytePos);
raf.writeByte(byteToWrite);
}
/*
* Nicely close the file
* @return boolean if succeed or failed
*/
public boolean close() throws IOException {
boolean success = true;
try {
raf.close();
}
catch(IOException e) {
success = false;
}

raf = null;
return success;
}

/*
* If no reference to this object try to close nicely the file
*/
protected void finalize() {
if(raf == null)
return;
try {
close();
}
catch(IOException e) {
}
}

/*
* To unit test the whole thing with the sieve of Erathostene
*/
public static void main(String[] args) throws IOException {
final int MAX = 32;
BitSetFile bsf = new BitSetFile(new File("a.dat"));

// set the first MAX odd to true (possible prime)
for(long i = 1; i <= MAX; i += 2) {
bsf.set(i);
}
// clear all the multiples of each prime
for(long i = 3; i < MAX; i += 2) {
if(bsf.get(i)) {
// clear all the multiples... just make it for the first MAX
for(long j = i; j < MAX; j += 2) {
long val = i * j;
// but break if we exceed MAX
if(val > MAX)
break;
// if we wrap around (too big for a long)
if(val < 0)
break;
bsf.clear(val);
}
}
}
// print the ones that are prime
for(int i = 0; i <= MAX; i++) {
if(bsf.get(i))
System.out.println("" + i);
}
// printd the last one
System.out.println("Last one in the list: " + bsf.getLastBitSet());
}
}

```

Now having this, we need a few more things:
- just to for display it would be nice to have the number of primes found
- the last prime found (when we stop and restart the program)
- and actually there is no need to have in the BitSetFile all the even numbers (we can by that divide the size of the file by 2) and speed up access to it

So here is the RegisteringOddBitSetFile that extends BitSetFile but keeps only tract of the odd numbers.
The first 2 long of the file are reserved to keep: the number of primes found and the last prime found
Another feature of this class is that inverse the true/false concepts When a BitSet (or in this case a RandomAccessFile) is extended new bytes are set to 00 which is false. So in a normal BitSet operation (or in that case with the file) we have to set to true (or 1) all the bits in the extension as ptential primes. Inversing the clear/set operations makes that the file when extended (with all the bits to 0) will return true if they are tested.
So the clearBit() operation in that class calls the setBit() method in BitSetFile and vice-versa. And getBit() return false is the bit is set and true otherwise.
```import java.io.*;

/*
* This class extends BitSetFile but for the ones who like to play with the Eratosthene sieve
* it presents the following fetaures:
* - it only supports odd bit number (because we know that all even numbers can't be prime) so
*   bit[0] -> 3  bit[1] -> 5  bit[2] -} 7... this reduce the size of the file by 2
* - true and false are reverses so true is 0 and false is 1 so when bytes are appended (initialized to
*   0 by the file system) these will be considered as true to potential prime numbers no need to reset
*   them to true as in a regular BitSet
* The first 2 longs in the file contain the number of prime already found and the last prime found
* so when another run is performed:
* - there is no need to scan the file to find the last prime found
* - if the program is interrupted while filling the multiple of a prime it can be restart at that point
*/
public class RegisteringOddBitSetFile extends BitSetFile {

public RegisteringOddBitSetFile(File file) throws IOException {
super(file);
}

/*
* Set a bit (which means clear as set/clear are reversed)
*/
public void set(long bit) throws IOException {
long realBit = (bit / 2L) + (16 * 8);
if(realBit < 0) {
System.out.println("set of " + bit + " exceed Long.MAX_VALUE");
return;
}
super.clear(realBit);
}
/*
* Clear a bit (which means set as set/clear are reversed)
*/
public void clear(long bit) throws IOException {
long realBit = (bit / 2L) + (16 * 8);
if(realBit < 0) {
System.out.println("clear of " + bit + " exceed Long.MAX_VALUE");
return;
}
super.set(realBit);
}

public long length() {
long nb = super.length() - 16;
if(nb < 0)
nb = 0;
return nb;
}
/*
* Returns if a bit is set or not
*/
public boolean get(long bit) throws IOException{
long realBit = (bit / 2L) + (16 * 8);
// exceed Long.MAX_VALUE
if(realBit < 0) {
System.out.println("get of " + bit + " exceed Long.MAX_VALUE");
return false;
}
return !super.get(realBit);
}

/*
* to write the number of prime found and the last prime found
*/
void writeNbAndLast(long nb, long last) throws IOException {
raf.seek(0L);
raf.writeLong(nb);
raf.seek(8L);
raf.writeLong(last);
}

/*
* the get the number of primes already found
*/
long getNb() throws IOException {
raf.seek(0L);
}
/*
* get the last prime found
*/
long getLast() throws IOException {
raf.seek(8L);
}
}

```

Now to display the primes... 2 JSpinners. One PrimeSpinner allows to display all the primes in the file. The second PrimeSpinnerRange is used to set, by 100,000 increments which should be the first prime displayed by PrimeSpinner
The Spinner need the value and a String represention of the numbers they display... So we need first 2 little class
One to format the long into coma separated String like 1,234,567,789
```import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;

/*
* One static class to format Long
*/
public class FormatLong {

private DecimalFormat decimalFormat;

FormatLong() {
// The decimal format used for big numbers
decimalFormat = new DecimalFormat("#,###,###,###,###,###,##0");
// the format of our long
DecimalFormatSymbols dfc = decimalFormat.getDecimalFormatSymbols();
dfc.setGroupingSeparator(',');
decimalFormat.setDecimalFormatSymbols(dfc);
}
// to return
String format(long n) {
return decimalFormat.format(n) + " ";
}
}

```

And one that represent they "objects" displayed by the JSpinners
```
/*
* The data object displayed by the spinners
*/
public class SpinnerData {
long value;
String output;
static FormatLong fm = new FormatLong();

SpinnerData(long n) {
value = n;
output = fm.format(n);
}
public String toString() {
return output;
}
}

```

And finally the 2 spinners
```import java.io.*;
import javax.swing.*;

/*
* A Spinner to display the primes its model uses a RegisteringOddBitSetFile to return Primes
*/
public class PrimeSpinner extends JSpinner {

// the max in the file
private long max;
// the file itself with it's getter/setter
RegisteringOddBitSetFile obsf;
// the component showed
JLabel label;
// my model
PrimeSpinnerModel model;

// constructor disable it until we get the file
PrimeSpinner() {
setEnabled(false);
model = new PrimeSpinnerModel(this);
setModel(model);
label = new JLabel();
label.setHorizontalAlignment(JLabel.RIGHT);
setEditor(label);
}

/*
* Once the file has been opened you pass the obsf and the first max
*/
void setFile(RegisteringOddBitSetFile obsf, long max) {
this.max = max;
this.obsf = obsf;
label.setText("3  ");
setEnabled(true);
}

/*
* To set the new max
*/
void setMax(long max) {
this.max = max;
}

// the other spinner asked me to show starting at sd
void setStartingValue(SpinnerData sd) {
model.setStartingValue(sd.value + 1);
}

class PrimeSpinnerModel extends AbstractSpinnerModel {
// the current that I display
private SpinnerData current;
private SpinnerData lastNextValue, lastPreviousValue;

JSpinner father;
PrimeSpinnerModel(JSpinner father) {
this.father = father;
current = new SpinnerData(3L);
lastNextValue = new SpinnerData(0);
lastPreviousValue = new SpinnerData(0);
}

public Object getPreviousValue() {
try {
for(long i = current.value+2; i <= max; i += 2) {
if(obsf.get(i)) {
if(i != lastPreviousValue.value)
lastPreviousValue = new SpinnerData(i);
return lastPreviousValue;
}
}
}
catch(IOException e) {
}
return null;
}

public Object getNextValue() {
if(current.value == 3)
return null;
try {
for(long i = current.value-2; i >= 3; i -= 2) {
if(obsf.get(i)) {
if(i != lastNextValue.value)
lastNextValue = new SpinnerData(i);
return lastNextValue;
}
}
}
catch(IOException e) {
}
return null;
}

public Object getValue() {
return current;
}

@Override
public void setValue(Object value) {
current = (SpinnerData) value;
label.setText(current.toString() + "  ");
}

/*
* Show values from
*/
void setStartingValue(long from) {
try {
// search the first prime from from
for(long i = from; i <= max; i += 2) {
if(obsf.get(i)) {
setValue(new SpinnerData(i));
return;	// done
}
}
}
catch(IOException e) {
}
}
}
}

```

```import javax.swing.*;
import java.awt.*;

/*
* A Spinner to display to display the starting value for the other one
*/
public class PrimeSpinnerRange extends JSpinner {

// the max in the file
private long max = 1;
// the component showed
JLabel label;
SpinnerPanel fatherPanel;

// constructor disable it until we get the file
PrimeSpinnerRange(SpinnerPanel father) {
fatherPanel = father;
setModel(new RangeModel(this));
label = new JLabel("0  ");
label.setHorizontalAlignment(JLabel.RIGHT);
label.setForeground(Color.RED);
setEditor(label);
setEnabled(false);
}

/*
* To set the new max
*/
void setMax(long max) {
this.max = max;
}

class RangeModel extends AbstractSpinnerModel {
// the current that I display
private SpinnerData current;
private SpinnerData lastNextValue, lastPreviousValue;

JSpinner father;
RangeModel(JSpinner father) {
this.father = father;
current = new SpinnerData(0L);
lastNextValue = new SpinnerData(0);
lastPreviousValue = new SpinnerData(0);
}

public Object getNextValue() {
if(current.value == 0)
return null;
long value = current.value - 100000;
if(value != lastNextValue.value)
lastNextValue = new SpinnerData(value);
return lastNextValue;
}

public Object getPreviousValue() {
long value = current.value + 100000L;
value /= 100000L;
value *= 100000L;
if(value > max)
return null;
if(value != lastPreviousValue.value)
lastPreviousValue = new SpinnerData(value);
return lastPreviousValue;
}

public Object getValue() {
return current;
}

@Override
public void setValue(Object value) {
long currentValue = ((SpinnerData) value).value;
current = new SpinnerData(currentValue);
label.setText(current.toString() + "  ");
fatherPanel.rangeChanged(current);
}
}
}

```

Now a JPanel to hold the 2 spinners and allow the GUI to infoirm the spinner if a new prime is found
```import javax.swing.*;
import javax.swing.event.*;

import java.awt.*;

/*
* Hold the spinners
*/
public class SpinnerPanel extends JPanel {

private PrimeSpinner primeSpinner;
private PrimeSpinnerRange primeSpinnerRange;

SpinnerPanel() {
super(new GridLayout(1, 3, 3, 3));
JLabel label = new JLabel("Display primes from:");
label.setHorizontalAlignment(JLabel.CENTER);
primeSpinnerRange = new PrimeSpinnerRange(this);
primeSpinner = new PrimeSpinner();
}

/*
* To enable/disable the primeSpinner
*/
void setEnableSpinner(boolean state) {
primeSpinner.setEnabled(state);
primeSpinnerRange.setEnabled(state);
}
/*
* Once the file has been opened you pass the obsf and the first max
*/
void setFile(RegisteringOddBitSetFile obsf, long max) {
primeSpinner.setFile(obsf, max);
primeSpinnerRange.setMax(max);
primeSpinnerRange.setEnabled(true);
}

/*
* A new prime has been found we inform the spinners of this new maximum
*/
void setMax(long max) {
primeSpinner.setMax(max);
primeSpinnerRange.setMax(max);
}
/*
* Change in the PrimeSpinnerRange
*/
void rangeChanged(SpinnerData sd) {
primeSpinner.setStartingValue(sd);
}
}

```

#### Attached image(s)

This post has been edited by pbl: 22 December 2009 - 07:35 PM

### #6 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 22 December 2009 - 07:36 PM

And finally the GUI to hold the whole thing
It has a FileChooser to select a file (previous one or old file)
RadioButtons to specify how many new number to check from 1,000 to 1,000,000 but feel free to change it
ProgressBar that shows what is is doing
The program might be stopped when you want. It will restart at the last prime found
```import java.awt.*;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

import java.awt.event.*;
import java.io.*;

public class PrimeGui extends JFrame implements ActionListener {

JButton btnOpenFile, btnGo;
JLabel fileLabel, sizeLabel, statusLabel, lastFoundLabel, nbFoundLabel, timeLabel;
// title label
JLabel clearingLabel, searchingLabel;
String clearingLabelText = "Clearing this prime multiples";
String searchingLabelText = "Searching primes progress";

// values of the RadioButton (Caution: must be multiple of 2)
int[] radioValue = {1000, 10000, 100000, 1000000, 10000000};
// the file to store the find numbers
RegisteringOddBitSetFile obsf;
// the numbers of new numbers to find
int nbToCheck;
// length of file
long fileSize;
// the last found for sure
long lastFound, nbFound;
// timer to update GUI
Timer timer;
// if the thread is running
// if multipes of new prime need to be check in the rest of the file
boolean fillStillPossible;
// the text of the statusLabel
String statusLabelText;
// time we start
long startTime;
// The JProgress bar for the filling and the searching
JProgressBar progressBarFilling = new JProgressBar();
JProgressBar progressBarSearching = new JProgressBar();
// LighYellow color
Color lightYellow = new Color(255, 255, 120);
// to format my long
FormatLong fl = new FormatLong();
SpinnerPanel spinnerPanel;

PrimeGui() {
super("Prime Numbers calculator");
setSize(700, 380);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

// master panel inside the frame
JPanel masterPanel = new JPanel(new GridLayout(11, 1, 3, 3));
// the buttons panel
JPanel p = new JPanel(new GridLayout(1, 3, 3, 3 ));
// the file chooser
btnOpenFile = new JButton("Open file");
// just to center the button
Box box = new Box(BoxLayout.X_AXIS);
// the label for the time elapsed
timeLabel = new JLabel("");
timeLabel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
timeLabel.setHorizontalAlignment(JLabel.CENTER);
// the button to start the process
btnGo = new JButton("Go");
btnGo.setEnabled(false);
box = new Box(BoxLayout.X_AXIS);

// the file name
fileLabel = new JLabel("File:");
fileLabel.setHorizontalAlignment(JLabel.CENTER);

p = new JPanel(new GridLayout(1, 6, 3, 3));
sizeLabel = new JLabel();
sizeLabel.setHorizontalAlignment(JLabel.CENTER);
lastFoundLabel = new JLabel();
lastFoundLabel.setHorizontalAlignment(JLabel.CENTER);
nbFoundLabel = new JLabel();
nbFoundLabel.setHorizontalAlignment(JLabel.CENTER);

// the number of new numbers to check
JLabel label = new JLabel("Number of new numbers to check");
label.setHorizontalAlignment(JLabel.CENTER);

// the radio and the go
p = new JPanel(new GridLayout(1,radioValue.length, 3, 3));
ButtonGroup bg = new ButtonGroup();
for(int i = 0; i < radioBtn.length; i++) {
}

// the Progress Bars
// the one used to show the progress while serachiing fro prime
searchingLabel = borderedLabel(searchingLabelText);
progressBarSearching.setBorderPainted(true);
progressBarSearching.setMinimum(0);
progressBarSearching.setForeground(Color.BLUE);
// the one used to show the progress when clearing the multiples of a prime in the rest of the file
clearingLabel = borderedLabel(clearingLabelText);
progressBarFilling.setBorderPainted(true);
progressBarFilling.setMinimum(0);
progressBarFilling.setForeground(Color.BLUE);

// The spinners
spinnerPanel = new SpinnerPanel();

// the status label
statusLabel = new JLabel("Select a file to start the application.");

// add the panel to the frame

}

// opening the file (initiliae it if required)
private void openFile(File file) {
try {
// create the OddBitSetFile to stored the found primes
obsf = new RegisteringOddBitSetFile(file);
fileSize = obsf.length();
// update the 2 labels about name and size
fileLabel.setText("File: " + file);
sizeLabel.setText("" + fileSize);
}
catch(IOException e) {
statusLabel.setText("Problem opening file: " + e);
return;
}

// if new file init it
if(fileSize == 0) {
// the first non primes it the first byte to create the file
int[] firstNonPrime = {9, 15};
try {
// adding the first prime in the first byte
for(int i = 0; i < firstNonPrime.length; i++)
obsf.clear((long) firstNonPrime[i]);
fileSize = obsf.length();
// the number of prime is 8 - the non prime + 2 for 1 and 2
nbFound =  8 - firstNonPrime.length + 2;
// first byte contains 3,5,7,9,11,13,15,17
lastFound = 17L;
obsf.writeNbAndLast(nbFound, lastFound);
}
catch(IOException e) {
statusLabel.setText("Init file error: " + e);
return;
}
}
// read where I am at
try {
lastFound = obsf.getLast();
nbFound = obsf.getNb();
lastFoundLabel.setText(fl.format(lastFound));
nbFoundLabel.setText(fl.format(nbFound));
}
catch (IOException e) {
statusLabel.setText("The file does not seem to be a valid prime data file");
return;
}

for(int i = 0; i < radioBtn.length; i++)
statusLabel.setText("Select the number of numbers to check");

// model for the Spinner
spinnerPanel.setFile(obsf, lastFound);
}

/*
* A centered label with a border
*/
private JLabel borderedLabel(String str) {
JLabel label = centeredLabel(str);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
label.setOpaque(true);
label.setBackground(lightYellow);
label.setForeground(Color.BLUE);
return label;
}
/*
* Returns a centered JLabel from a String
*/
private JLabel centeredLabel(String str) {
JLabel label = new JLabel(str);
label.setHorizontalAlignment(JLabel.CENTER);
label.setForeground(Color.BLUE);
return label;
}
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
// if it is the timer (will be the one calling more often)
if(o == timer) {
// update the JLabel
sizeLabel.setText(fl.format(fileSize));
lastFoundLabel.setText(fl.format(lastFound));
nbFoundLabel.setText(fl.format(nbFound));
statusLabel.setText(statusLabelText);
timeLabel.setText(formatSince(startTime));
repaint();
// if the thread has finished
// no need to continue to update the display
timer.stop();
btnGo.setEnabled(true);
searchingLabel.setText(searchingLabelText);
clearingLabel.setText(clearingLabelText);
// we can re-emable the radio buttons
for(int i = 0; i < radioBtn.length; i++)
// re-enable spinner access
spinnerPanel.setEnableSpinner(true);
// clear last message
statusLabel.setText("Press GO button to start");
// clear the seraching progress bar
progressBarSearching.setValue(0);
}
return;
}

// button to open file
if(o == btnOpenFile) {
JFileChooser chooser = new JFileChooser();
// allow only to select 1 file
chooser.setMultiSelectionEnabled(false);
// our types .dat and .prim
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Data file", "dat", "prim");
chooser.setFileFilter(filter);
// check if a file was selected
int returnVal = chooser.showOpenDialog(this);
if(returnVal == JFileChooser.APPROVE_OPTION) {
// if it is the case andd it is not a directory
openFile(chooser.getSelectedFile());
}
return;
}

for(int i = 0; i < radioBtn.length; i++) {
btnGo.setEnabled(true);
statusLabel.setText("Press GO button to start");
return;
}
}

// test if it is the go button
if(btnGo == o) {
// disable spinners file chooser
spinnerPanel.setEnableSpinner(false);
btnOpenFile.setEnabled(false);
btnGo.setEnabled(false);
for(int i = 0; i < radioBtn.length; i++)
// start the thread that calculates the prime numbers
t.start();
// starts the timer that updates the GUI
timer = new Timer(500, this);
timer.start();
startTime = System.currentTimeMillis();
return;
}
}

/*
* Dump the content of the file (for debug purpose)
*/
private void dump(long to, String title) {
System.out.println("Dump " + title + " from 3 to " + lastFound);
try {
StringBuilder str = new StringBuilder(100);
for(long i = 3; i <= to; i += 2) {
if(obsf.get(i)) {
str.append(fl.format(i));

if(str.length() >= 80) {
System.out.println(str);
str = new StringBuilder(100);
}
}
}
System.out.println(str);
}
catch(IOException e) {
}
}

/*
* Format the time elapsed since the time passed as parameter
*/
private String formatSince(long begin) {
int delta = (int) (System.currentTimeMillis() - begin);
int milli = delta % 1000;
delta /= 1000;
int second = delta % 60;
delta /= 60;
int minute = delta % 60;
delta /= 60;
return String.format("%d:%02d:%02d.%03d", delta, minute, second, milli);
}
// to stat the whole thing
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new PrimeGui().setVisible(true);
}
});
}

// the inner class that actually perform the calculation

// to run in a different thread to the GUI can be updated correctly
public void run() {

// update our target based on the last found
long target = nbToCheck + lastFound;
if(target < 0) {				 // wrap around number to big
target = Long.MAX_VALUE;
if(target % 2 == 0)
target--;
}
// prepare the progress bar for searching
long from = lastFound + 2;
int nb = (int) (target - from) / 2;
progressBarSearching.setMaximum(nb);
progressBarSearching.setValue(0);
searchingLabel.setText("Searching primes from " + fl.format(from) + " to " + fl.format(target));
// clear the non primes to the end of the new file
try {
clearFileExtensionWithOldPrimes(target);
}
catch(IOException e) {
System.out.println("IOException clearing the none primes in the extendion: " + e);
return;
}

// now let's find new primes to register them and fill their multiples
fillStillPossible = true;
nb = 0;
try {
for(long i = from; i <= target; i += 2) {
progressBarSearching.setValue(++nb);
// if not prime continue
if(!obsf.get(i))
continue;
if(fillStillPossible) {
statusLabelText = fl.format(i) + "is prime. Filling the rest of the file...";
// we have to fill the extension of the file with all the multiples
// of this new found number from 3 to target / that number
clearFileWithNewPrime(i, target);
progressBarFilling.setValue(0);
}
else {
statusLabelText = "The multiples of " + fl.format(i) +"exceed the file capacity.";
}
// save the new prime found in file has it's multiples are cleared
lastFound = i;
nbFound++;
obsf.writeNbAndLast(nbFound, lastFound);
spinnerPanel.setMax(lastFound);
}
}
catch(IOException e) {
System.out.println("Exception updating multiples of " + lastFound + ": " + e);
return;
}
}

/*
* Clear in the rest of the file all the multiples of the new prime found
* return true if we filled some
*/
private void clearFileWithNewPrime(long prime, long target) throws IOException{
// we will have to clear all the multiple of prime from 3
// to target / prime
statusLabelText = "";
long to = target / prime;
if(to % 2 == 0)
to--;
// any multiplication of the prime won't fit in the file
if(to < 3) {
clearingLabel.setText("");
fillStillPossible = false;			// no need to call this method again
return;
}
// number of iterations for the progress bar
int nb = (int) (to - 3) + 1;
progressBarFilling.setMaximum(nb);
clearingLabel.setText("Setting as non prime the " + fl.format(nb) + " multiples of " +
fl.format(prime) + " up to " + fl.format(to));

int n = 0;
for(long i = 3; i <= to; i += 2) {
// test if it is prime
if(obsf.get(i)) {
obsf.clear(i * prime);
}
progressBarFilling.setValue(++n);
}
clearingLabel.setText("");
return;
}
/*
* Clear the non prime in the extended part of the file with the primes
*/
private void clearFileExtensionWithOldPrimes(long target) throws IOException {

for(long i = 3; i <= lastFound; i += 2) {
// if not prime continue
if(!obsf.get(i)) {
continue;
}
// calculate the range to fill
FillExtension fe = new FillExtension(i, lastFound, target);
// none to fill for that one I can ignore the others which are bigger
int nb = fe.nb;
if(nb == 0)
break;
nb /= 2;
nb++;
clearingLabel.setText("Setting as non prime the " + fl.format(nb) + " multiples of " +
fl.format(i) + " up to " + fl.format(target) + " in the new file extension");
fe.fill(obsf);
}
}
}

/*
* This class is used to clear the non Prime numbers in the new extension of the file
* For the from value:
* ------------------
* Let's say the file contains already the prime numbers up to 37
* For 3 I dont'have to do
* 3 * 3 = 9  3 * 5 = 15  3 * 7 = 21  3 * 9 = 27 3 * 11 = 33 should start with 3 * 13 = 39
* For 5 I don't have to do
* 5 * 5 = 25  5 * 7 = 35 should start with 5 * 9 = 45
* For 7
* 39 / 7 = 5 and I should start with 7
* For 11
* 39 / 11 = 3 and I should start with 11
*
* From these I think we can conclude to these empriric rules:
* - divide the number of the last prime by the prime to fill
* - if the result of the division is even add 1 to that number
* - if the result of the division is odd add 2 to that number
* - if that number is < to the original prime use that original prime
*
* Now for the end:
* ---------------
* A lot simpler: just divide the target by the prime... if that number is even subtract 1 to it
*/
class FillExtension {
// the prime for which we will perform the operation
long prime;
//  by wich numbers we will multiply it
long from, to;
// number to do
int nb;

FillExtension(long prime, long lastPrime, long target) {
this.prime = prime;
// find from where to start
from = lastPrime / prime;
if(from % 2 == 0)
from++;
else // if even add 2
from += 2;
// if smaller than original one
if(prime > from)
from = prime;		// take that one
// the end
to = target / prime;
if(to % 2 == 0)
to--;
// number to to
nb = (int) (to - from);   // will yield .... -4, -2, 0, 2, 4, ....
// from 15 to 15 means 1
nb += 2;
// if from > to nothing to to
if(nb < 0)
nb = 0;
nb /= 2;	   // number of time the loop will be executed
// prepare the JProgressBar
progressBarFilling.setValue(0);
if(nb > 0) {
progressBarFilling.setMaximum(nb);
}
}

// method to fill the file and the progress bar
void fill(RegisteringOddBitSetFile file) {
int n = 0;
try {
for(long i = from; i <= to; i += 2) {
long val = i * prime;
file.clear(val);
progressBarFilling.setValue(++n);
// update fileSize (not really OO) only for 3
if(prime == 3)
fileSize = file.length();
}
}
catch(IOException e) {
System.out.println("Problem filling the new area " + e);
}
}
}
}

```

### #7 nick2price

• D.I.C Lover

Reputation: 563
• Posts: 2,826
• Joined: 23-November 07

## Re: Prime Generator Timing

Posted 22 December 2009 - 07:42 PM

Show off Nice work.

### #8 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 22 December 2009 - 08:09 PM

nick2price, on 22 Dec, 2009 - 06:42 PM, said:

Show off Nice work.

Was actually fun to do
First time I was using JSpinner never understood how the ChangeListener on them really worked... to I just used their setEditor() method and updated the JLabel "by hand"

### #9 LynnL

Reputation: 21
• Posts: 109
• Joined: 13-April 09

## Re: Prime Generator Timing

Posted 23 December 2009 - 09:40 PM

Very very good show PBL

I ran the application a few times with one million increment and gheeez it goes fast

But I have a question:
When you start the application, there is the step when you fill/clear the new extended file with the non-prime numbers

Now, at the beginning the progress bar goes quite fast and then it slows down at the end
What would explain that behavior ? I am just curious

### #10 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 23 December 2009 - 09:49 PM

LynnL, on 23 Dec, 2009 - 08:40 PM, said:

Very very good show PBL

I ran the application a few times with one million increment and gheeez it goes fast

But I have a question:
When you start the application, there is the step when you fill/clear the new extended file with the non-prime numbers

Now, at the beginning the progress bar goes quite fast and then it slows down at the end
What would explain that behavior ? I am just curious

That may explain it... I hope
The way I wrote it, when you set a bit to true/false in the file the RegisteringBitSetFile class as first to read the BYTE containing that number fromn the file and then set/clear the bit
It then check if the bit status has changed
If the bit status hasn't changed it does not bother writting it back to file
So when you extend the file, sure that all multiples of 3 will be cleared but when you clear the multiples of 5 a few of them will always been done and even more multiple of 7 and then 11
So it is normal that the progress bar goes faster from one prime to the other

### #11 LynnL

Reputation: 21
• Posts: 109
• Joined: 13-April 09

## Re: Prime Generator Timing

Posted 26 December 2009 - 10:31 PM

OK another question
What happens if you stop the program when it fills the "non prime" ? (the multiples) of the registered prime

I also change to "new prime" check for 10,000,000 it seems to take long
How long does it take on your computer?

### #12 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 26 December 2009 - 10:42 PM

LynnL, on 26 Dec, 2009 - 09:31 PM, said:

OK another question
What happens if you stop the program when it fills the "non prime" ? (the multiples) of the registered prime

As the last prime registered is in the file, the process will be performed again
Better to stop it while searching for new primes

LynnL, on 26 Dec, 2009 - 09:31 PM, said:

I also change to "new prime" check for 10,000,000 it seems to take long
How long does it take on your computer?

Depends where you are at.... just tested it
On my Toshiba laptop, which is 2 years old with a dual Pentium T3400 it takes 8h00 for a 10,000,000 run
May be I should add a slider for how often the GUI should be refreshed... that must take much of the time

### #13 LynnL

Reputation: 21
• Posts: 109
• Joined: 13-April 09

## Re: Prime Generator Timing

Posted 29 December 2009 - 09:49 PM

I have almost reach Long.MAX_VALUE in the file
now if I want to see the registered primes, using your spinner that increments by 100,000 it takes a while
how can I do faster É

### #14 pbl

• There is nothing you can't do with a JTable

Reputation: 8362
• Posts: 31,955
• Joined: 06-March 08

## Re: Prime Generator Timing

Posted 29 December 2009 - 10:16 PM

LynnL, on 29 Dec, 2009 - 08:49 PM, said:

I have almost reach Long.MAX_VALUE in the file
now if I want to see the registered primes, using your spinner that increments by 100,000 it takes a while
how can I do faster É

Never though this prime stuff would last for so long.... should really put it in the Snippet so anyhow this is a re-vamped version
Forget all the other "spinner" related classes
Here is a new PrimeGui class and a SpinnerPannel class
```package prime;

import java.awt.*;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

import java.awt.event.*;
import java.io.*;

public class PrimeGui extends JFrame implements ActionListener {

JButton btnOpenFile, btnGo;
JLabel fileLabel, sizeLabel, statusLabel, lastFoundLabel, nbFoundLabel, timeLabel, notPrimeLabel;
// title label
JLabel clearingLabel, searchingLabel;
String clearingLabelText = "Clearing this prime multiples";
String searchingLabelText = "Searching primes progress";

// values of the RadioButton (Caution: must be multiple of 2)
int[] radioValue = {1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
// the file to store the find numbers and a readOnly for the displayed prime
// the numbers of new numbers to find
int nbToCheck;
// length of file
long fileSize;
// the last found for sure
long lastFound, nbFound;
// timer to update GUI
Timer timer;
// if the thread is running
// if multipes of new prime need to be check in the rest of the file
boolean fillStillPossible;
// the text of the statusLabel
String statusLabelText, notPrimeTxt;
// time we start
long startTime;
// The JProgress bar for the filling and the searching
JProgressBar progressBarFilling = new JProgressBar();
JProgressBar progressBarSearching = new JProgressBar();
// LighYellow color
Color lightYellow = new Color(255, 255, 120);
// to format my long
FormatLong fl = new FormatLong();

// the spinner
SpinnerPanel spinnerPanel;
// the displayed prime
long displayedPrime;
JLabel displayedPrimeLabel;

PrimeGui() {
super("Prime Numbers calculator");
setSize(700, 420);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

// master panel inside the frame
JPanel masterPanel = new JPanel(new GridLayout(13, 1, 3, 3));
// the buttons panel
JPanel p = new JPanel(new GridLayout(1, 3, 3, 3 ));
// the file chooser
btnOpenFile = new JButton("Open file");
btnOpenFile.setBackground(Color.YELLOW);
// just to center the button
Box box = new Box(BoxLayout.X_AXIS);
// the label for the time elapsed
timeLabel = new JLabel("");
timeLabel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
timeLabel.setHorizontalAlignment(JLabel.CENTER);
// the button to start the process
btnGo = new JButton("Go");
btnGo.setEnabled(false);
btnGo.setForeground(Color.RED);
box = new Box(BoxLayout.X_AXIS);

// the file name
fileLabel = new JLabel("File:");
fileLabel.setHorizontalAlignment(JLabel.CENTER);

p = new JPanel(new GridLayout(1, 6, 3, 3));
sizeLabel = new JLabel();
sizeLabel.setHorizontalAlignment(JLabel.CENTER);
lastFoundLabel = new JLabel();
lastFoundLabel.setHorizontalAlignment(JLabel.CENTER);
nbFoundLabel = new JLabel();
nbFoundLabel.setHorizontalAlignment(JLabel.CENTER);

// the number of new numbers to check
JLabel label = borderedLabel("Number of new numbers to check");
label.setForeground(Color.RED);

// the radio and the go
Box b = new Box(BoxLayout.X_AXIS);
ButtonGroup bg = new ButtonGroup();
for(int i = 0; i < radioBtn.length; i++) {
}

// the Progress Bars
// the one used to show the progress while serachiing fro prime
searchingLabel = borderedLabel(searchingLabelText);
progressBarSearching.setBorderPainted(true);
progressBarSearching.setMinimum(0);
progressBarSearching.setForeground(Color.BLUE);
// the one used to show the progress when clearing the multiples of a prime in the rest of the file
clearingLabel = borderedLabel(clearingLabelText);
progressBarFilling.setBorderPainted(true);
progressBarFilling.setMinimum(0);
progressBarFilling.setForeground(Color.BLUE);

// the not prime cleared (centered with empty JLabels)
p = new JPanel(new GridLayout(1,4));
notPrimeLabel = new JLabel();

// The displayed prime and the spinners
p = new JPanel(new GridLayout(1,2, 2, 2));
p.add(centeredLabel("Primes list (use +/- spinners to update):"));
displayedPrimeLabel = new JLabel("");
displayedPrimeLabel.setHorizontalAlignment(JLabel.CENTER);
displayedPrimeLabel.setForeground(Color.BLUE);
p.setBorder(BorderFactory.createLineBorder(Color.BLUE));
// the spinners
spinnerPanel = new SpinnerPanel(this);

// the status label
statusLabel = new JLabel("Select a file to start the application.");

// add the panel to the frame

}

// opening the file (initiliae it if required)
private void openFile(File file) {
try {
// create the OddBitSetFile to stored the found primes
obsf = new RegisteringOddBitSetFile(file, false);
fileSize = obsf.length();
// update the 2 labels about name and size
fileLabel.setText("File: " + file);
sizeLabel.setText("" + fileSize);
}
catch(IOException e) {
statusLabel.setText("Problem opening file: " + e);
return;
}

// if new file init it
if(fileSize == 0) {
// the first non primes it the first byte to create the file
int[] firstNonPrime = {9, 15};
try {
// adding the first prime in the first byte
for(int i = 0; i < firstNonPrime.length; i++) {
obsf.clear((long) firstNonPrime[i]);
notPrimeTxt = fl.format(firstNonPrime[i]);
}
fileSize = obsf.length();
// the number of prime is 8 - the non prime + 2 for 1 and 2
nbFound =  8 - firstNonPrime.length + 2;
// first byte contains 3,5,7,9,11,13,15,17
lastFound = 17L;
obsf.writeNbAndLast(nbFound, lastFound);
}
catch(IOException e) {
statusLabel.setText("Init file error: " + e);
return;
}
}
// read where I am at
try {
lastFound = obsf.getLast();
nbFound = obsf.getNb();
lastFoundLabel.setText(fl.format(lastFound));
nbFoundLabel.setText(fl.format(nbFound));
}
catch (IOException e) {
statusLabel.setText("The file does not seem to be a valid prime data file");
return;
}

for(int i = 0; i < radioBtn.length; i++)
statusLabel.setText("Select the number of numbers to check");

// enable the Spinner
spinnerPanel.enableSpinner(true);
// at application start use the latest prime as displayed number
displayedPrime = lastFound;
displayedPrimeLabel.setText(fl.format(displayedPrime));
}

/*
* A centered label with a border
*/
private JLabel borderedLabel(String str) {
JLabel label = centeredLabel(str);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
label.setOpaque(true);
label.setBackground(lightYellow);
label.setForeground(Color.BLUE);
return label;
}
/*
* Returns a centered JLabel from a String
*/
private JLabel centeredLabel(String str) {
JLabel label = new JLabel(str);
label.setHorizontalAlignment(JLabel.CENTER);
label.setForeground(Color.BLUE);
return label;
}
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
// if it is the timer (will be the one calling more often)
if(o == timer) {
// update the JLabel
sizeLabel.setText(fl.format(fileSize));
lastFoundLabel.setText(fl.format(lastFound));
nbFoundLabel.setText(fl.format(nbFound));
statusLabel.setText(statusLabelText);
timeLabel.setText(formatSince(startTime));
notPrimeLabel.setText(notPrimeTxt);
repaint();
// if the thread has finished
// no need to continue to update the display
timer.stop();
//				spinnerPanel.enableSpinner(true);
btnGo.setEnabled(true);
searchingLabel.setText(searchingLabelText);
clearingLabel.setText(clearingLabelText);
// we can re-emable the radio buttons
for(int i = 0; i < radioBtn.length; i++)
// clear last message
statusLabel.setText("Press GO button to start");
// clear the seraching progress bar
progressBarSearching.setValue(0);
}
return;
}

// button to open file
if(o == btnOpenFile) {
JFileChooser chooser = new JFileChooser();
// allow only to select 1 file
chooser.setMultiSelectionEnabled(false);
// our types .dat and .prim
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Data file", "dat", "prim");
chooser.setFileFilter(filter);
// check if a file was selected
int returnVal = chooser.showOpenDialog(this);
if(returnVal == JFileChooser.APPROVE_OPTION) {
// if it is the case andd it is not a directory
openFile(chooser.getSelectedFile());
}
return;
}

for(int i = 0; i < radioBtn.length; i++) {
btnGo.setEnabled(true);
statusLabel.setText("Press GO button to start");
return;
}
}

// test if it is the go button
if(btnGo == o) {
// apply interminatestate while searchin
statusLabelText = "";
// disable file chooser
btnOpenFile.setEnabled(false);
btnGo.setEnabled(false);
for(int i = 0; i < radioBtn.length; i++)
// start the thread that calculates the prime numbers
t.start();
// starts the timer that updates the GUI
timer = new Timer(500, this);
timer.start();
startTime = System.currentTimeMillis();
return;
}
}

/*
* Dump the content of the file (for debug purpose)
*/
private void dump(long to, String title) {
System.out.println("Dump " + title + " from 3 to " + lastFound);
try {
StringBuilder str = new StringBuilder(100);
for(long i = 3; i <= to; i += 2) {
if(obsf.get(i)) {
str.append(fl.format(i));

if(str.length() >= 80) {
System.out.println(str);
str = new StringBuilder(100);
}
}
}
System.out.println(str);
}
catch(IOException e) {
}
}

/*
* Format the time elapsed since the time passed as parameter
*/
private String formatSince(long begin) {
int delta = (int) (System.currentTimeMillis() - begin);
int milli = delta % 1000;
delta /= 1000;
int second = delta % 60;
delta /= 60;
int minute = delta % 60;
delta /= 60;
return String.format("%d:%02d:%02d.%03d", delta, minute, second, milli);
}

// for the spinnerPanel to update the displayed prime
void updateDisplayedPrime(int delta) {
long attempt = displayedPrime + delta;
// attempt before 3
if(attempt <= 3L) {
displayedPrime = 3L;
displayedPrimeLabel.setText("3");
return;
}
// attempt goes over the last one
if(attempt >= lastFound) {
displayedPrime = lastFound;
displayedPrimeLabel.setText(fl.format(displayedPrime));
return;
}
// we will try to find next prime or the previous one
try {
if(delta > 0) {
for(long i = attempt; i <= lastFound; i += 2) {
displayedPrime = i;
displayedPrimeLabel.setText(fl.format(displayedPrime));
return;
}
}
}
// the previous if delta < 0 or if the attempt for next failed
for(long i = attempt; i >= 3; i -= 2) {
displayedPrime = i;
displayedPrimeLabel.setText(fl.format(displayedPrime));
return;
}
}
}
catch(IOException e) {
System.out.println("Error trying to find nextDisplayedPrime");
}
}

// to stat the whole thing
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new PrimeGui().setVisible(true);
}
});
}

// the inner class that actually perform the calculation

// to run in a different thread to the GUI can be updated correctly
public void run() {

// update our target based on the last found
long target = nbToCheck + lastFound;
if(target < 0) {				 // wrap around number to big
target = Long.MAX_VALUE;
if(target % 2 == 0)
target--;
}
// prepare the progress bar for searching
long from = lastFound + 2;
int nb = (int) (target - from) / 2;
progressBarSearching.setMaximum(nb);
progressBarSearching.setValue(0);
searchingLabel.setText("Searching primes from " + fl.format(from) + " to " + fl.format(target));
// clear the non primes to the end of the new file
try {
clearFileExtensionWithOldPrimes(target);
}
catch(IOException e) {
System.out.println("IOException clearing the none primes in the extendion: " + e);
return;
}

// now let's find new primes to register them and fill their multiples
fillStillPossible = true;
nb = 0;
try {
for(long i = from; i <= target; i += 2) {
progressBarSearching.setValue(++nb);
// if not prime continue
if(!obsf.get(i))
continue;
if(fillStillPossible) {
statusLabelText = fl.format(i) + "is prime. Filling the rest of the file...";
// we have to fill the extension of the file with all the multiples
// of this new found number from 3 to target / that number
clearFileWithNewPrime(i, target);
progressBarFilling.setValue(0);
}
else {
statusLabelText = "The multiples of " + fl.format(i) +"exceed the file capacity, so they will be cleared next time the file will be extended.";
}
// save the new prime found in file has it's multiples are cleared
lastFound = i;
nbFound++;
obsf.writeNbAndLast(nbFound, lastFound);
////					spinnerArrayPanel.setMaxPrime(lastFound);
}
}
catch(IOException e) {
System.out.println("Exception updating multiples of " + lastFound + ": " + e);
return;
}
}

/*
* Clear in the rest of the file all the multiples of the new prime found
* return true if we filled some
*/
private void clearFileWithNewPrime(long prime, long target) throws IOException{
// we will have to clear all the multiple of prime from 3
// to target / prime
statusLabelText = "";
long to = target / prime;
if(to % 2 == 0)
to--;
// any multiplication of the prime won't fit in the file
if(to < 3) {
clearingLabel.setText("");
fillStillPossible = false;			// no need to call this method again
return;
}
// number of iterations for the progress bar
int nb = (int) (to - 3) + 1;
progressBarFilling.setMaximum(nb);
clearingLabel.setText("Setting as non prime the " + fl.format(nb) + " multiples of " +
fl.format(prime) + " up to " + fl.format(to));

int n = 0;
for(long i = 3; i <= to; i += 2) {
// test if it is prime
if(obsf.get(i)) {
long val = i * prime;
obsf.clear(val);
notPrimeTxt = fl.format(val);
}
// do not bother filling the progressBar if nb < 1000
// won't have to see it on the screen
if(nb > 1000)
progressBarFilling.setValue(++n);
}
clearingLabel.setText("");
return;
}
/*
* Clear the non prime in the extended part of the file with the primes
*/
private void clearFileExtensionWithOldPrimes(long target) throws IOException {

for(long i = 3; i <= lastFound; i += 2) {
// if not prime continue
if(!obsf.get(i)) {
continue;
}
// calculate the range to fill
FillExtension fe = new FillExtension(i, lastFound, target);
// none to fill for that one I can ignore the others which are bigger
int nb = fe.nb;
if(nb == 0)
break;
nb /= 2;
nb++;
clearingLabel.setText("Setting as non prime the " + fl.format(nb) + " multiples of " +
fl.format(i) + " up to " + fl.format(target) + " in the new file extension");
fe.fill(obsf);
}
notPrimeTxt = "";
}
}

/*
* This class is used to clear the non Prime numbers in the new extension of the file
* For the from value:
* ------------------
* Let's say the file contains already the prime numbers up to 37
* For 3 I dont'have to do
* 3 * 3 = 9  3 * 5 = 15  3 * 7 = 21  3 * 9 = 27 3 * 11 = 33 should start with 3 * 13 = 39
* For 5 I don't have to do
* 5 * 5 = 25  5 * 7 = 35 should start with 5 * 9 = 45
* For 7
* 39 / 7 = 5 and I should start with 7
* For 11
* 39 / 11 = 3 and I should start with 11
*
* From these I think we can conclude to these empriric rules:
* - divide the number of the last prime by the prime to fill
* - if the result of the division is even add 1 to that number
* - if the result of the division is odd add 2 to that number
* - if that number is < to the original prime use that original prime
*
* Now for the end:
* ---------------
* A lot simpler: just divide the target by the prime... if that number is even subtract 1 to it
*/
class FillExtension {
// the prime for which we will perform the operation
long prime;
//  by wich numbers we will multiply it
long from, to;
// number to do
int nb;

FillExtension(long prime, long lastPrime, long target) {
this.prime = prime;
// find from where to start
from = lastPrime / prime;
if(from % 2 == 0)
from++;
else // if even add 2
from += 2;
// if smaller than original one
if(prime > from)
from = prime;		// take that one
// the end
to = target / prime;
if(to % 2 == 0)
to--;
// number to to
nb = (int) (to - from);   // will yield .... -4, -2, 0, 2, 4, ....
// from 15 to 15 means 1
nb += 2;
// if from > to nothing to to
if(nb < 0)
nb = 0;
nb /= 2;	   // number of time the loop will be executed
// prepare the JProgressBar
progressBarFilling.setValue(0);
if(nb > 0) {
progressBarFilling.setMaximum(nb);
}
notPrimeTxt = "";
}

// method to fill the file and the progress bar
void fill(RegisteringOddBitSetFile file) {
int n = 0;
try {
for(long i = from; i <= to; i += 2) {
long val = i * prime;
file.clear(val);
notPrimeTxt = fl.format(val);
// do not bother filling the progressBar if under 1000
// will just make a glitch at the screen
if(nb > 1000)
progressBarFilling.setValue(++n);
// update fileSize (not really OO) only for 3
if(prime == 3)
fileSize = file.length();
}
}
catch(IOException e) {
System.out.println("Problem filling the new area " + e);
}
}
}
}

```

[code]
package prime;

import javax.swing.*;

public class SpinnerPanel extends Box {

// the delta in our spinner
int[] delta = {2, 1000, 10000, 100000, 1000000, 10000000, 100000000};
PrimeGui gui;
PrimeSpinner[] primeSpinner = new PrimeSpinner[delta.length];

SpinnerPanel(

### #15 LynnL

Reputation: 21
• Posts: 109
• Joined: 13-April 09

## Re: Prime Generator Timing

Posted 30 December 2009 - 12:14 AM

Sorry does not compile
Something wrong with the constructor of RegisteringOddBitSetFile