Skip to content
July 29, 2011 / oop123

Java 7 is here!

Oracle has just released JDK 7 (just in case no one knows). It’s not a huge update in term of features (like Oracle said, “evolutionary”, not “revolutionary”), but it is an update nevertheless.

Since other people already wrote so much about the new features, I may as well just give you some links:

Apparently, Oracle pushed most of the major features planned in Java 7 to Java 8 (closures, Jigsaw, and the rest of Coin) in what they called “plan B” (very creative). Oh well.

July 27, 2011 / oop123

Project Euler #80 – Java

You can see the problem here: Problem #80.

This is a simple question (especially because it’s only asking for the digits of 100 number). The only trouble I encountered is misinterpreting “100 decimal digits” with the digits after the decimal point instead of the mathematical definition (as all the digits including digits before decimal).

I used the Newton-Raphson method and Java’s BigDecimal to calculate the square roots. For those who don’t know how the Newton-Raphson method works: for any number n, take a guess for its square root, and you can get a new and better guess with guess = (n / guess + guess) / 2.

public static String sqrtTo100Digits(int num) {
	BigDecimal bnum = BigDecimal.valueOf(num);
	BigDecimal TWO = BigDecimal.valueOf(2);
	BigDecimal guess = BigDecimal.valueOf(num / 2);
	for (int i = 2; i <= 122; i += 10) {       //122 should ensure a precision of up to 100
		BigDecimal temp = bnum.divide(guess, i, BigDecimal.ROUND_HALF_UP);
		guess = guess.add(temp).divide(TWO);
	}
	return guess.toString().substring(0, 101); //101 to account for decimal decimal point
}

The code of .main(String[] args) are then pretty straight forward.

int sum = 0;
for (int i = 2; i < 100; i++) {
	if (Math.sqrt(i) % 1 == 0) continue;
	String num = sqrtTo100Digits(i).toString();
	sum += num.charAt(0) - 48; //-48 converts a digit in char to its equivalent int
	for (int j = 2; j < num.length(); j++) {
		sum += num.charAt(j) - 48;
	}
}
System.out.println(sum);

Runs in around 56 milliseconds on my computer. A simple question. CU

July 24, 2011 / oop123

Writing a Simple Calculator in Java – Part 5

Let’s define an enum to hold the memory functions (M+, MR, and MC).

package gui.action;
import java.awt.event.*;
import java.math.BigDecimal;

public enum Memory implements ActionListener {
	;

	//store the BigDecimal
	private static BigDecimal num = null;

	/*
	 * Should override this in the enums
	 */
	@Override
	public void actionPerformed(ActionEvent e) {}
}

M+: Add the stored BigDecimal and the current BigDecimal.

M_PLUS {
	public void actionPerformed(ActionEvent e) {
		BigDecimal num2 = new BigDecimal(CalcUtils.getNum());
		if (num != null) num = num.add(num2);
		else num = num2;

		if (BigDecimal.ZERO.equals(num)) {
			num = null;
		}
	}
}

MR: Show the stored BigDecimal.

M_RECALL {
	public void actionPerformed(ActionEvent e) {
		if (num != null) CalcUtils.setNum(num.toString());
	}
}

MC: Clear the stored BigDecimal.

M_CLEAR {
	public void actionPerformed(ActionEvent e) {
		num = null;
	}
}

The only thing missing is an indicator to user there is a number in memory. I’m not going to add that now it’s part 5, but it’s pretty simple and you can imagine how it can be implemented.

July 21, 2011 / oop123

Writing a Simple Calculator in Java – Part 4

Let’s define an enum to hold the unary functions.

package gui.action;
import java.awt.event.*;
import java.math.BigDecimal;

public enum Unary implements ActionListener {
	;

	/*
	 * Should override this in the enums
	 */
	@Override
	public void actionPerformed(ActionEvent e) {}
}

Decimal Point: If there isn’t already a decimal point on the displayed number, append a decimal point.

DOT {
	public void actionPerformed(ActionEvent e) {
		String str = CalcUtils.getNum();
		if (!str.contains(".")) CalcUtils.setNum(str + ".");
	}
}

Reverse Sign: If there is a negative sign at the beginning of the number, take it away; otherwise, add it.

REVERSE_SIGN {
	public void actionPerformed(ActionEvent e) {
		String str = CalcUtils.getNum();
		if (str.startsWith("-")) CalcUtils.setNum(str.substring(1));
		else CalcUtils.setNum("-" + str);
		//or CalcUtils.setNum(str.startsWith("-") ? str.substring(1) : "-" + str)
	}
}

Percentage Sign: Divide the current number by 100.

PERCENTAGE {
	public void actionPerformed(ActionEvent e) {
		BigDecimal num = new BigDecimal(CalcUtils.getNum());
		num = num.divide(new BigDecimal("100"));
		CalcUtils.setNum(CalcUtils.trimToMaxDigitsAndTrailing0IfNumIsFloat(num.toString()));
	}
}

Square Root: Square root current number (use Math.sqrt())

SQRT {
	public void actionPerformed(ActionEvent e) {
		Double num = Math.sqrt(Double.parseDouble(CalcUtils.getNum()));
		CalcUtils.setNum(CalcUtils.trimToMaxDigitsAndTrailing0IfNumIsFloat(num.toString()));
	}
}

Inverse: Take the inverse (1/x) of current number.

INVERSE {
	public void actionPerformed(ActionEvent e) {
		BigDecimal num = new BigDecimal(CalcUtils.getNum());
		num = BigDecimal.ONE.divide(num, 20, BigDecimal.ROUND_HALF_UP);
		CalcUtils.setNum(CalcUtils.trimToMaxDigitsAndTrailing0IfNumIsFloat(num.toString()));
	}
}

Backspace: Delete last digit of current number. Also watch out when the current number only has one single digit.

BACKSPACE {
	public void actionPerformed(ActionEvent e) {
		String num = CalcUtils.getNum();
		if (num.length() == 1 || (num.length() == 2 && num.startsWith("-"))) {
			CalcUtils.setNum("0");
		} else {
			CalcUtils.setNum(num.substring(0, num.length() - 1));
		}
	}
}

Clear: Change displayed number to 0 and clear Operation.lastOp and Operation.lastNum (a trivial method so not going to show it here).

CLEAR {
	public void actionPerformed(ActionEvent e) {
		CalcUtils.setNum("0");
		Operation.clear();
	}
}
July 19, 2011 / oop123

Writing a Simple Calculator in Java – Part 3

Since the calculator can also add floating numbers, we will use BigDecimal to do all the calculations. Normal double does not have the precision required for exact calculations. It will made the code more complicated, but that is the price of accuracy. Some quick notes on BigDecimal: operations such as +, -, *, / are all replaced by .add(), .subtract(), .multiply(), .divide() on the BigDecimal object.

The following is just a code skeleton.

  • The enum defines the five ActionListeners for the +, -, *, /, and = buttons.
  • The .operate() method defines the Operation’s action
  • The .actionPerformed() will provide a skeleton call to .operate().
  • lastNum and lastOp are used to keep track of user input.
  • I did not add any precedence to the calculator (i.e. multiply before add), but if you want to know how to implement something like that see Stack Overflow and Wikipedia entry on it.
package gui.action;
import java.math.BigDecimal;
import java.awt.event.*;
import javax.swing.*;

public enum Operation implements ActionListener {
	ADD {
		@Override
		public String operate(BigDecimal num1, BigDecimal num2) {
			return null;
		}
	}, MINUS {
		@Override
		public String operate(BigDecimal num1, BigDecimal num2) {
			return null;
		}
	}, TIMES {
		@Override
		public String operate(BigDecimal num1, BigDecimal num2) {
			return null;
		}
	}, DIVIDE {
		@Override
		public String operate(BigDecimal num1, BigDecimal num2) {
			return null;
		}
	}, EQUAL {
		@Override
		public String operate(BigDecimal num1, BigDecimal num2) {
			return null;
		}
	};

	private static Operation lastOp = null;
	private static String lastNum = null;
	
	@Override
	public void actionPerformed(ActionEvent e) {}

	public abstract String operate(String BigDecimal num1, BigDecimal num2);
}

The code for .actionPerformed() is pretty self-explanatory. If the user entered a new number and there is a lastOp, calculate a result and display it. Set the lastOp to the new operation unless it’s an EQUAL, and set the lastNum to the current number. Finally, tell the calculator to start a new number.

if (lastOp != null && TypeNumber.hasNewNum()) {
	BigDecimal num1 = new BigDecimal(lastNum);
	BigDecimal num2 = new BigDecimal(CalcUtils.getNum())
	CalcUtils.setNum( CalcUtils.trimToMaxDigitsAndTrailing0IfNumIsFloat( lastOp.operate(num1, num2) ));
}
if (this != EQUAL) {
	lastOp = this;
}
lastNum = CalcUtils.getNum();
TypeNumber.startNewNum();

Now let’s write the individual operation.

ADD:

return num1.add(num2).toString();

MINUS:

return num1.subtract(num2).toString();

TIMES:

return num1.multiply(num2).toString();

DIVIDE:

return num1.divide(num2).toString();

EQUAL:

//NO NEED TO OVERRIDE -> .actionPerformed() do all the work already
return null;

The calculator can now do basic arithmetic! There are various bugs (or quirks) in it, like 1 / 6 * 6 gives 0.999999999999996 instead of 1, but oh well, it’s close enough 😛

July 18, 2011 / oop123

Writing a Simple Calculator in Java – Part 2

I started with a utility class with methods to get or set the string inside the display JTextField. Inside the setter, I limit the amount of digits the string can contains to 18 since that’s how much the text field can display without overflowing (accounting for a negative sign and decimal point).

package gui.action;
import javax.swing.JTextField;
import java.math.BigDecimal;

public class CalcUtils {
	//not for instantiation
	private CalcUtils() {}
	
	public static JTextField field = null;
	
	public static void setField(JTextField fie) {
		field = fie;
	}
	
	public static String getNum() {
		//not a number -> error
		try {
			new BigDecimal(field.getText());
			return field.getText();
		} catch(NumberFormatException e) {
			return "0";
		}
	}

	public static final int MAX_DIGITS = 18;
	
	public static void setNum(String str) {
		//set a limit of 18 digits for the str
		if (countDigits(str) <= MAX_DIGITS) field.setText(str);
		else field.setText("Error: number too big");
	}
	
	public static int countDigits(String str) {
		int count = 0;
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
				count++;
			}
		}
		return count;
	}
	
	//because i'm planning to work with BigDecimal
	public static String trimToMaxDigitsAndTrailing0IfNumIsFloat(String str) {
		if (!str.contains(".")) {
			return str;
		}

		//remove excess digits
		int count = 0;
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
				count++;
			}
			if (count == MAX_DIGITS) {
				str = str.substring(0, i + 1);
				break;
			}
		}
		
		//remove trailing 0
		count = 0;
		for (int i = str.length() - 1; i >= 0; i--) {
			char ch = str.charAt(i);
			if (ch == '0') {
				count++;
			} else if (ch == '.') {
				count++;
				break;
			} else {
				break;
			}
		}
		str = str.substring(0, str.length() - count);
		

		return str;
	}
}

I also added the following line to the MainFrame constructor for the utility class to work.

CalcUtils.setField(field.field);

Now let’s write some code so the number buttons actually do something (this can actually be written as an enum, but eh).

package gui.action;
import java.awt.event.*;

public class TypeNumber implements ActionListener {
	private String digit = null;

	//constructs with digit 0-9 repectively
	public TypeNumber(int num) {
		digit = String.valueOf(num);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		String num = CalcUtils.getNum();

		//make sure "012" can't happen or user is inputing next number of expression
		if (num.equals("0") || newNum) {
			CalcUtils.setNum(digit);
			newNum = false;
		}
		//make sure there is less than 18 digits
		else if (CalcUtils.countDigits(num) < CalcUtils.MAX_DIGITS) {
			CalcUtils.setNum( num + digit);
		}
	}

	//Those will be used in +, -, *, /, = to control the typing of numbers
	private static boolean newNum = false;
	public static void startNewNum() {
		newNum = true;
	}
	public static boolean hasNewNum() {
		//opposite -> when the user type in a newNum, newNum becomes false, so we reverse the bool
		return !newNum;
	}
}

The class append the digit to the end of the display, unless it’s “0” or a new number need to be entered (i.e. user pressed +), in which case it would replace the number with the digit pressed. After some copy and paste to add the ActionListeners to the number buttons, they can actually type something now! 🙂

Screenshot of Java calculator with number punched in

July 17, 2011 / oop123

Writing a Simple Calculator in Java – Part 1

Let’s start with the GUI.

Using a GridLayout, we can easily make a calculator panel.

package gui;
import java.awt.*;
import javax.swing.*;

public class Pad extends JPanel {
	//implements Serializable, not important
	private static final long serialVersionUID = 6018546535458821851L;

	public Pad() {
		this.setLayout(new GridLayout(5, 5, 5, 5));

		//create all the buttons
		JButton b1 = new JButton("1");
		JButton b2 = new JButton("2");
		JButton b3 = new JButton("3");
		JButton b4 = new JButton("4");
		JButton b5 = new JButton("5");
		JButton b6 = new JButton("6");
		JButton b7 = new JButton("7");
		JButton b8 = new JButton("8");
		JButton b9 = new JButton("9");
		JButton b0 = new JButton("0");
		JButton badd = new JButton("+");
		JButton bminus = new JButton("\u2212"); //unicode for minus
		JButton bmult = new JButton("\u00D7");  //unicode for multiply
		JButton bdiv = new JButton("\u00F7");   //unicode for divide
		JButton bsqrt = new JButton("\u221A");  //unicode for sqrt symbol
		JButton bdel = new JButton("\u2190");   //unicode for backspace
		JButton bequal = new JButton("=");
		JButton bdot = new JButton(".");
		JButton bC = new JButton("C");
		JButton binv = new JButton("1/x");
		JButton bsign = new JButton("\u00B1");
		JButton bper = new JButton("%");
		JButton bMPlus = new JButton("M+");
		JButton bMMinus = new JButton("MR");
		JButton bMRC = new JButton("MC");

		//some buttons' text is small, make them bigger bigger
		Font bigger = new Font(bsign.getFont().getName(), Font.PLAIN, 16);
		bsign.setFont(bigger);
		badd.setFont(bigger);
		bminus.setFont(bigger);
		bmult.setFont(bigger);
		bdiv.setFont(bigger);

		//add them, each group being a row of the GridLayout
		add(bMPlus);
		add(bMR);
		add(bMC);
		add(badd);
		add(bdel);

		add(b7);
		add(b8);
		add(b9);
		add(bminus);
		add(bC);

		add(b4);
		add(b5);
		add(b6);
		add(bmult);
		add(binv);

		add(b1);
		add(b2);
		add(b3);
		add(bdiv);
		add(bper);

		add(bdot);
		add(b0);
		add(bsign);
		add(bequal);
		add(bsqrt);
	}
}

We put the text field to display the numbers in a panel (so we can change its size later).

package gui;
import java.awt.*;
import javax.swing.*;

public class NumField extends JPanel {
	private static final long serialVersionUID = 8901400055245008856L;

	JTextField field;

	public NumField(int width) {
		//configure field's property
		field = new JTextField("0");
		field.setEditable(false);
		field.setBackground(Color.WHITE);
		field.setPreferredSize(new Dimension(width, 50));
		field.setHorizontalAlignment(JTextField.RIGHT);
		field.setFont(new Font(field.getFont().getName(), Font.PLAIN, 30));
		add(field);
	}
}

Then we have the MainFrame. I add the above two components with the default BorderLayer manager.

package gui;
import java.awt.BorderLayout;
import javax.swing.JFrame;

public class MainFrame extends JFrame {
	private static final long serialVersionUID = -8026416994513756565L;
	public static final int DEFAULT_HEIGHT = 350;
	public static final int DEFAULT_WIDTH = 350;
	private NumField field;

	public MainFrame() {
		//-10 to leave some margin for the field
		field = new NumField(DEFAULT_WIDTH - 10);

		//add the components (
		add(field, BorderLayout.NORTH);
		add(new Pad());

		//configure the frame
		setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
		setTitle("Calculator");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setResizable(false);
		setVisible(true);
	}
}

I put the code to open the main window at Calculator.main(String[] args).

import javax.swing.SwingUtilities;
import gui.MainFrame;

public class Calculator {
	public static void main(String[] args) {
		//for Swing beginners, .invokeLater() should always be used for Swing stuff, otherwise it can cause
		//threading problems
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new MainFrame();
			}
		});
	}
}

Here’s what it look like on my computer (Windows). It looks ugly, but it’s still a calculator 🙂

A screenshot of the Java calculator